From 142a3703d8b60804a5ff1179a0dbc6bcbf37ce64 Mon Sep 17 00:00:00 2001 From: Sebastian Berg Date: Tue, 3 Jan 2023 14:44:04 +0100 Subject: [PATCH] MAINT: Add additional information to missing scalar AttributeError This is a followup on gh-22607 which removed them. Since it appears some users missed the DeprecationWarning entirely, it may help them to include the old information as an attribute error. An example is: ``` In [1]: np.int AttributeError: module 'numpy' has no attribute 'int'. `np.int` was a deprecated alias for the builtin `int`. To avoid this error in existing code, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information. The aliases was originally deprecated in NumPy 1.20; for more details and guidance see the original release note at: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations ``` Yes, that is very verbose... your changes. Lines starting --- numpy/__init__.py | 40 +++++++++++++++++++++++++-- numpy/core/tests/test_deprecations.py | 15 ++++++++++ 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/numpy/__init__.py b/numpy/__init__.py index bdea595ed3f5..e20a83ab1e7b 100644 --- a/numpy/__init__.py +++ b/numpy/__init__.py @@ -155,6 +155,40 @@ from . import matrixlib as _mat from .matrixlib import * + # Deprecations introduced in NumPy 1.20.0, 2020-06-06 + import builtins as _builtins + + _msg = ( + "module 'numpy' has no attribute '{n}'.\n" + "`np.{n}` was a deprecated alias for the builtin `{n}`. " + "To avoid this error in existing code, use `{n}` by itself. " + "Doing this will not modify any behavior and is safe. {extended_msg}\n" + "The aliases was originally deprecated in NumPy 1.20; for more " + "details and guidance see the original release note at:\n" + " https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations") + + _specific_msg = ( + "If you specifically wanted the numpy scalar type, use `np.{}` here.") + + _int_extended_msg = ( + "When replacing `np.{}`, you may wish to use e.g. `np.int64` " + "or `np.int32` to specify the precision. If you wish to review " + "your current use, check the release note link for " + "additional information.") + + _type_info = [ + ("object", ""), # The NumPy scalar only exists by name. + ("bool", _specific_msg.format("bool_")), + ("float", _specific_msg.format("float64")), + ("complex", _specific_msg.format("complex128")), + ("str", _specific_msg.format("str_")), + ("int", _int_extended_msg.format("int"))] + + __former_attrs__ = { + n: _msg.format(n=n, extended_msg=extended_msg) + for n, extended_msg in _type_info + } + # Future warning introduced in NumPy 1.24.0, 2022-11-17 _msg = ( "`np.{n}` is a deprecated alias for `{an}`. (Deprecated NumPy 1.24)") @@ -265,8 +299,10 @@ def _expired(*args, **kwds): # the AttributeError warnings.warn( f"In the future `np.{attr}` will be defined as the " - "corresponding NumPy scalar. (This may have returned Python " - "scalars in past versions.", FutureWarning, stacklevel=2) + "corresponding NumPy scalar.", FutureWarning, stacklevel=2) + + if attr in __former_attrs__: + raise AttributeError(__former_attrs__[attr]) # Importing Tester requires importing all of UnitTest which is not a # cheap import Since it is mainly used in test suits, we lazy import it diff --git a/numpy/core/tests/test_deprecations.py b/numpy/core/tests/test_deprecations.py index dba301418612..033815150b0e 100644 --- a/numpy/core/tests/test_deprecations.py +++ b/numpy/core/tests/test_deprecations.py @@ -1176,3 +1176,18 @@ def test_future_scalar_attributes(name): # Unfortunately, they are currently still valid via `np.dtype()` np.dtype(name) name in np.sctypeDict + + +# Ignore the above future attribute warning for this test. +@pytest.mark.filterwarnings("ignore:In the future:FutureWarning") +class TestRemovedGlobals: + # Removed 2023-01-12, NumPy 1.24.0 + # Not a deprecation, but the large error was added to aid those who missed + # the previous deprecation, and should be removed similarly to one + # (or faster). + @pytest.mark.parametrize("name", + ["object", "bool", "float", "complex", "str", "int"]) + def test_attributeerror_includes_info(self, name): + msg = f".*\n`np.{name}` was a deprecated alias for the builtin" + with pytest.raises(AttributeError, match=msg): + getattr(np, name)