Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 91bfcfa

Browse files
committed
MAINT: Hide internals of np.lib to only show submodules
This commit creates a new module to "conveniently" import all symbols into the main namespace, while hiding them in `np.lib`.
1 parent 572d5a1 commit 91bfcfa

File tree

9 files changed

+134
-65
lines changed

9 files changed

+134
-65
lines changed

benchmarks/asv_compare.conf.json.tpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
4040
// The Pythons you'd like to test against. If not provided, defaults
4141
// to the current version of Python used to run `asv`.
42-
"pythons": ["3.7"],
42+
"pythons": ["3.9"],
4343
4444
// The matrix of dependencies to test. Each key is the name of a
4545
// package (in PyPI) and the values are version numbers. An empty

numpy/__init__.py

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@
153153
from . import lib
154154
# NOTE: to be revisited following future namespace cleanup.
155155
# See gh-14454 and gh-15672 for discussion.
156-
from .lib import *
156+
from .lib._lib_importer import *
157157

158158
from . import linalg
159159
from . import fft
@@ -225,7 +225,7 @@
225225
__all__.extend(['__version__', 'show_config'])
226226
__all__.extend(core.__all__)
227227
__all__.extend(_mat.__all__)
228-
__all__.extend(lib.__all__)
228+
__all__.extend(lib._lib_importer.__all__)
229229
__all__.extend(['linalg', 'fft', 'random', 'ctypeslib', 'ma'])
230230

231231
# These are exported by np.core, but are replaced by the builtins below
@@ -235,14 +235,6 @@
235235
__all__.remove('long')
236236
__all__.remove('unicode')
237237

238-
# Remove things that are in the numpy.lib but not in the numpy namespace
239-
# Note that there is a test (numpy/tests/test_public_api.py:test_numpy_namespace)
240-
# that prevents adding more things to the main namespace by accident.
241-
# The list below will grow until the `from .lib import *` fixme above is
242-
# taken care of
243-
__all__.remove('Arrayterator')
244-
del Arrayterator
245-
246238
# These names were removed in NumPy 1.20. For at least one release,
247239
# attempts to access these names in the numpy namespace will trigger
248240
# a warning, and calling the function will raise an exception.

numpy/lib/__init__.py

Lines changed: 75 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""
2-
**Note:** almost all functions in the ``numpy.lib`` namespace
2+
**Note:** almost all functions in the ``numpy.lib.submodule`` namespaces
33
are also present in the main ``numpy`` namespace. Please use the
44
functions as ``np.<funcname>`` where possible.
55
@@ -11,51 +11,83 @@
1111
useful to have in the main name-space.
1212
1313
"""
14-
import math
15-
16-
from numpy.version import version as __version__
17-
18-
# Public submodules
19-
# Note: recfunctions and (maybe) format are public too, but not imported
20-
from . import mixins
21-
from . import scimath as emath
22-
23-
# Private submodules
24-
from .type_check import *
25-
from .index_tricks import *
26-
from .function_base import *
27-
from .nanfunctions import *
28-
from .shape_base import *
29-
from .stride_tricks import *
30-
from .twodim_base import *
31-
from .ufunclike import *
32-
from .histograms import *
33-
34-
from .polynomial import *
35-
from .utils import *
36-
from .arraysetops import *
37-
from .npyio import *
14+
# NOTE: This file is the _public_ interface for additional submodules
15+
# housed in `numpy.lib`. The private import mechanism lives in the
16+
# `_lib_importer.py` file, which defines `__all__` to include all names to
17+
# be added to the main namespace!
18+
19+
from . import scimath as emath # import explicitly to rename
20+
3821
from .arrayterator import Arrayterator
39-
from .arraypad import *
40-
from ._version import *
4122
from numpy.core._multiarray_umath import tracemalloc_domain
42-
43-
__all__ = ['emath', 'math', 'tracemalloc_domain', 'Arrayterator']
44-
__all__ += type_check.__all__
45-
__all__ += index_tricks.__all__
46-
__all__ += function_base.__all__
47-
__all__ += shape_base.__all__
48-
__all__ += stride_tricks.__all__
49-
__all__ += twodim_base.__all__
50-
__all__ += ufunclike.__all__
51-
__all__ += arraypad.__all__
52-
__all__ += polynomial.__all__
53-
__all__ += utils.__all__
54-
__all__ += arraysetops.__all__
55-
__all__ += npyio.__all__
56-
__all__ += nanfunctions.__all__
57-
__all__ += histograms.__all__
23+
from ._version import NumpyVersion
5824

5925
from numpy._pytesttester import PytestTester
6026
test = PytestTester(__name__)
6127
del PytestTester
28+
29+
from . import _lib_importer as _hidden_lib_namespace
30+
31+
32+
# Ensure that __all__ only contains those things that we want it to contain.
33+
# Because this is an __init__, we would otherwise include all submodules.
34+
#
35+
# NOTE: The symbols not included in `__all__` will be hidden, but do not go
36+
# through `__getattr__` (see `__dir__`).
37+
__all__ = {'emath', 'Arrayterator', 'tracemalloc_domain', 'NumpyVersion'}
38+
39+
__lib_submodules_ = {
40+
'type_check',
41+
'emath',
42+
'arraysetops',
43+
'utils',
44+
'format',
45+
'npyio',
46+
'arrayterator',
47+
'mixins',
48+
'stride_tricks',
49+
'twodim_base',
50+
'histograms',
51+
'index_tricks',
52+
'nanfunctions',
53+
'shape_base',
54+
}
55+
# Add submodules to all (and finalize all)
56+
__all__.update(__lib_submodules_)
57+
__all__ = sorted(__all__)
58+
59+
# Add hidden submodules:
60+
__lib_submodules_.update({
61+
'arraypad',
62+
'function_base',
63+
'polynomial',
64+
'scimath',
65+
"ufunclike",
66+
})
67+
68+
69+
def __getattr__(name):
70+
if name in __lib_submodules_:
71+
import importlib
72+
# Allow lazy import (and avoid requiring explicit import), at the
73+
# time of writing `mixins` may be the only namespace using this.
74+
return importlib.import_module("." + name, __name__)
75+
76+
try:
77+
attribute = getattr(_hidden_lib_namespace, name)
78+
except AttributeError:
79+
pass
80+
else:
81+
# Adding a warning in this branch would allow us to properly deprecate
82+
# all hidden attributes. Raise an error here to test NumPy itself.
83+
return attribute
84+
85+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
86+
87+
88+
def __dir__():
89+
# Overriding __dir__ hides symbols from tab completion for example.
90+
# Note that it does _not_ hide symbols from `np.lib.__dict__()`, to do
91+
# that, we would have to delete them from the locals here and hide them
92+
# into `__getattr__`. But this seems sufficient, e.g. for tab completion.
93+
return __all__

numpy/lib/_lib_importer.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# This file defines which functions end up in the main namespace of NumPy.
2+
# Note that the use of * import with an __all__ based on the locals(), means
3+
# that the __all__ of the subpackages also defines what
4+
# There are at least two approaches how this could be modified in the future
5+
# conveniently:
6+
# * We could create an `__export_to_numpy_namespace__` list in each package
7+
# and use this to define the `__all__` here (which is still copied into
8+
# the main namespace.
9+
# * At least all functions copied to the main namespace probably already
10+
# use the `@set_module` decorator. So we could just use that (or something
11+
# similar) to manually add it to the main namespace.
12+
# (in which case we still need to make sure the file is imported)
13+
14+
15+
import math
16+
17+
# Public submodules
18+
# Note: recfunctions and (maybe) format are public too, but not imported
19+
from . import scimath as emath
20+
21+
# Private submodules
22+
from .type_check import *
23+
from .index_tricks import *
24+
from .function_base import *
25+
from .nanfunctions import *
26+
from .shape_base import *
27+
from .stride_tricks import *
28+
from .twodim_base import *
29+
from .ufunclike import *
30+
from .histograms import *
31+
32+
from .polynomial import *
33+
from .utils import *
34+
from .arraysetops import *
35+
from .npyio import *
36+
from .arraypad import *
37+
38+
39+
__all__ = [k for k in locals().keys() if not k.startswith("_")]

numpy/lib/recfunctions.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717

1818
_check_fill_value = np.ma.core._check_fill_value
1919

20+
# Make "recfunctions" available in numpy.lib for convenience, we could
21+
# make it a lazy import instead/additionally.
22+
np.lib.__all__.append("recfunctions")
23+
np.lib.__all__.sort()
2024

2125
__all__ = [
2226
'append_fields', 'apply_along_fields', 'assign_fields_by_name',

numpy/lib/tests/test_arraypad.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -629,7 +629,7 @@ def test_check_constant_odd_pad_amount(self):
629629

630630
def test_check_constant_pad_2d(self):
631631
arr = np.arange(4).reshape(2, 2)
632-
test = np.lib.pad(arr, ((1, 2), (1, 3)), mode='constant',
632+
test = np.pad(arr, ((1, 2), (1, 3)), mode='constant',
633633
constant_values=((1, 2), (3, 4)))
634634
expected = np.array(
635635
[[3, 1, 1, 4, 4, 4],

numpy/lib/tests/test_function_base.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@
1919
)
2020
import numpy.lib.function_base as nfb
2121
from numpy.random import rand
22-
from numpy.lib import (
22+
from numpy.lib.function_base import (
2323
add_newdoc_ufunc, angle, average, bartlett, blackman, corrcoef, cov,
24-
delete, diff, digitize, extract, flipud, gradient, hamming, hanning,
24+
delete, diff, digitize, extract, gradient, hamming, hanning,
2525
i0, insert, interp, kaiser, meshgrid, msort, piecewise, place, rot90,
26-
select, setxor1d, sinc, trapz, trim_zeros, unwrap, unique, vectorize
26+
select, sinc, trapz, trim_zeros, unwrap, vectorize,
2727
)
28+
from numpy.lib.arraysetops import setxor1d, unique
29+
from numpy.lib.twodim_base import flipud
2830

2931

3032
def get_mat(n):
@@ -1928,14 +1930,14 @@ def test_simple(self):
19281930
a = [1, 2, 3]
19291931
b = [1, 2, np.inf]
19301932
c = [1, 2, np.nan]
1931-
np.lib.asarray_chkfinite(a)
1932-
assert_raises(ValueError, np.lib.asarray_chkfinite, b)
1933-
assert_raises(ValueError, np.lib.asarray_chkfinite, c)
1933+
np.asarray_chkfinite(a)
1934+
assert_raises(ValueError, np.asarray_chkfinite, b)
1935+
assert_raises(ValueError, np.asarray_chkfinite, c)
19341936

19351937
def test_dtype_order(self):
19361938
# Regression test for missing dtype and order arguments
19371939
a = [1, 2, 3]
1938-
a = np.lib.asarray_chkfinite(a, order='F', dtype=np.float64)
1940+
a = np.asarray_chkfinite(a, order='F', dtype=np.float64)
19391941
assert_(a.dtype == np.float64)
19401942

19411943

numpy/lib/tests/test_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
from numpy.core import arange
66
from numpy.testing import assert_, assert_equal, assert_raises_regex
7-
from numpy.lib import deprecate, deprecate_with_doc
87
import numpy.lib.utils as utils
8+
from numpy.lib.utils import deprecate, deprecate_with_doc
99

1010
from io import StringIO
1111

numpy/testing/_private/utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ def assert_equal(actual, desired, err_msg='', verbose=True):
339339
verbose)
340340
return
341341
from numpy.core import ndarray, isscalar, signbit
342-
from numpy.lib import iscomplexobj, real, imag
342+
from numpy.lib.type_check import iscomplexobj, real, imag
343343
if isinstance(actual, ndarray) or isinstance(desired, ndarray):
344344
return assert_array_equal(actual, desired, err_msg, verbose)
345345
msg = build_err_msg([actual, desired], err_msg, verbose=verbose)
@@ -542,7 +542,7 @@ def assert_almost_equal(actual,desired,decimal=7,err_msg='',verbose=True):
542542
"""
543543
__tracebackhide__ = True # Hide traceback for py.test
544544
from numpy.core import ndarray
545-
from numpy.lib import iscomplexobj, real, imag
545+
from numpy.lib.type_check import iscomplexobj, real, imag
546546

547547
# Handle complex numbers: separate into real/imag to handle
548548
# nan/inf/negative zero correctly

0 commit comments

Comments
 (0)