diff options
author | Ralf Gommers <ralf.gommers@gmail.com> | 2019-09-19 09:42:28 +0200 |
---|---|---|
committer | Ralf Gommers <ralf.gommers@gmail.com> | 2019-09-19 18:24:14 +0200 |
commit | 9530d43f1b1314e3fc3b3c9175746849fe679f67 (patch) | |
tree | abaff4e55b5bc2476f58ae83d83799e35b42642b /numpy/tests | |
parent | 2bc84dba9871eaa654153f855c9b74e88a55ff10 (diff) | |
download | numpy-9530d43f1b1314e3fc3b3c9175746849fe679f67.tar.gz |
TST: add test to check that (semi-)public API modules can be imported
Also remove `numpy.ma.version.py`, it was not importable and served
no purpose.
Diffstat (limited to 'numpy/tests')
-rw-r--r-- | numpy/tests/test_public_api.py | 85 |
1 files changed, 68 insertions, 17 deletions
diff --git a/numpy/tests/test_public_api.py b/numpy/tests/test_public_api.py index a9b478938..e27d9b404 100644 --- a/numpy/tests/test_public_api.py +++ b/numpy/tests/test_public_api.py @@ -5,6 +5,7 @@ import subprocess import pkgutil import types import importlib +import warnings import numpy as np import numpy @@ -193,19 +194,10 @@ PRIVATE_BUT_PRESENT_MODULES = ['numpy.' + s for s in [ "conftest", "core", "core.arrayprint", - "core.code_generators", - "core.code_generators.genapi", - "core.code_generators.generate_numpy_api", - "core.code_generators.generate_ufunc_api", - "core.code_generators.generate_umath", - "core.code_generators.numpy_api", - "core.code_generators.ufunc_docstrings", - "core.cversions", "core.defchararray", "core.einsumfunc", "core.fromnumeric", "core.function_base", - "core.generate_numpy_api", "core.getlimits", "core.info", "core.machar", @@ -264,7 +256,6 @@ PRIVATE_BUT_PRESENT_MODULES = ['numpy.' + s for s in [ "distutils.lib2def", "distutils.line_endings", "distutils.mingw32ccompiler", - "distutils.msvc9compiler", "distutils.msvccompiler", "distutils.npy_pkg_config", "distutils.numpy_distribution", @@ -285,9 +276,6 @@ PRIVATE_BUT_PRESENT_MODULES = ['numpy.' + s for s in [ "f2py.rules", "f2py.use_rules", "fft.helper", - "fft.info", - "fft.pocketfft", - "fft.pocketfft_internal", "lib.arraypad", "lib.arraysetops", "lib.arrayterator", @@ -313,7 +301,6 @@ PRIVATE_BUT_PRESENT_MODULES = ['numpy.' + s for s in [ "ma.core", "ma.testutils", "ma.timer_comparison", - "ma.version", "matrixlib", "matrixlib.defmatrix", "random.bit_generator", @@ -351,6 +338,22 @@ def is_unexpected(name): return True +# These are present in a directory with an __init__.py but cannot be imported +# code_generators/ isn't installed, but present for an inplace build +SKIP_LIST = [ + "numpy.core.code_generators", + "numpy.core.code_generators.genapi", + "numpy.core.code_generators.generate_umath", + "numpy.core.code_generators.ufunc_docstrings", + "numpy.core.code_generators.generate_numpy_api", + "numpy.core.code_generators.generate_ufunc_api", + "numpy.core.code_generators.numpy_api", + "numpy.core.cversions", + "numpy.core.generate_numpy_api", + "numpy.distutils.msvc9compiler", +] + + def test_all_modules_are_expected(): """ Test that we don't add anything that looks like a new public module by @@ -361,7 +364,7 @@ def test_all_modules_are_expected(): for _, modname, ispkg in pkgutil.walk_packages(path=np.__path__, prefix=np.__name__ + '.', onerror=None): - if is_unexpected(modname): + if is_unexpected(modname) and modname not in SKIP_LIST: # We have a name that is new. If that's on purpose, add it to # PUBLIC_MODULES. We don't expect to have to add anything to # PRIVATE_BUT_PRESENT_MODULES. Use an underscore in the name! @@ -373,7 +376,7 @@ def test_all_modules_are_expected(): # Stuff that clearly shouldn't be in the API and is detected by the next test # below -SKIP_LIST = [ +SKIP_LIST_2 = [ 'numpy.math', 'numpy.distutils.log.sys', 'numpy.distutils.system_info.copy', @@ -442,7 +445,7 @@ def test_all_modules_are_expected_2(): fullobjname = mod_name + '.' + objname if isinstance(getattr(module, objname), types.ModuleType): if is_unexpected(fullobjname): - if fullobjname not in SKIP_LIST: + if fullobjname not in SKIP_LIST_2: members.append(fullobjname) return members @@ -454,3 +457,51 @@ def test_all_modules_are_expected_2(): if unexpected_members: raise AssertionError("Found unexpected object(s) that look like " "modules: {}".format(unexpected_members)) + + +def test_api_importable(): + """ + Check that all submodules listed higher up in this file can be imported + + Note that if a PRIVATE_BUT_PRESENT_MODULES entry goes missing, it may + simply need to be removed from the list (deprecation may or may not be + needed - apply common sense). + """ + def check_importable(module_name): + try: + importlib.import_module(module_name) + except (ImportError, AttributeError): + return False + + return True + + module_names = [] + for module_name in PUBLIC_MODULES: + if not check_importable(module_name): + module_names.append(module_name) + + if module_names: + raise AssertionError("Modules in the public API that cannot be " + "imported: {}".format(module_names)) + + for module_name in PUBLIC_ALIASED_MODULES: + try: + eval(module_name) + except AttributeError: + module_names.append(module_name) + + if module_names: + raise AssertionError("Modules in the public API that were not " + "found: {}".format(module_names)) + + with warnings.catch_warnings(record=True) as w: + warnings.filterwarnings('always', category=DeprecationWarning) + warnings.filterwarnings('always', category=ImportWarning) + for module_name in PRIVATE_BUT_PRESENT_MODULES: + if not check_importable(module_name): + module_names.append(module_name) + + if module_names: + raise AssertionError("Modules that are not really public but looked " + "public and can not be imported: " + "{}".format(module_names)) |