diff options
Diffstat (limited to 'numpy/testing/_private/noseclasses.py')
-rw-r--r-- | numpy/testing/_private/noseclasses.py | 364 |
1 files changed, 0 insertions, 364 deletions
diff --git a/numpy/testing/_private/noseclasses.py b/numpy/testing/_private/noseclasses.py deleted file mode 100644 index 48fa4dc1f..000000000 --- a/numpy/testing/_private/noseclasses.py +++ /dev/null @@ -1,364 +0,0 @@ -# These classes implement a doctest runner plugin for nose, a "known failure" -# error class, and a customized TestProgram for NumPy. - -# Because this module imports nose directly, it should not -# be used except by nosetester.py to avoid a general NumPy -# dependency on nose. -import os -import sys -import doctest -import inspect - -import numpy -import nose -from nose.plugins import doctests as npd -from nose.plugins.errorclass import ErrorClass, ErrorClassPlugin -from nose.plugins.base import Plugin -from nose.util import src -from .nosetester import get_package_name -from .utils import KnownFailureException, KnownFailureTest - - -# Some of the classes in this module begin with 'Numpy' to clearly distinguish -# them from the plethora of very similar names from nose/unittest/doctest - -#----------------------------------------------------------------------------- -# Modified version of the one in the stdlib, that fixes a python bug (doctests -# not found in extension modules, https://bugs.python.org/issue3158) -class NumpyDocTestFinder(doctest.DocTestFinder): - - def _from_module(self, module, object): - """ - Return true if the given object is defined in the given - module. - """ - if module is None: - return True - elif inspect.isfunction(object): - return module.__dict__ is object.__globals__ - elif inspect.isbuiltin(object): - return module.__name__ == object.__module__ - elif inspect.isclass(object): - return module.__name__ == object.__module__ - elif inspect.ismethod(object): - # This one may be a bug in cython that fails to correctly set the - # __module__ attribute of methods, but since the same error is easy - # to make by extension code writers, having this safety in place - # isn't such a bad idea - return module.__name__ == object.__self__.__class__.__module__ - elif inspect.getmodule(object) is not None: - return module is inspect.getmodule(object) - elif hasattr(object, '__module__'): - return module.__name__ == object.__module__ - elif isinstance(object, property): - return True # [XX] no way not be sure. - else: - raise ValueError("object must be a class or function") - - def _find(self, tests, obj, name, module, source_lines, globs, seen): - """ - Find tests for the given object and any contained objects, and - add them to `tests`. - """ - - doctest.DocTestFinder._find(self, tests, obj, name, module, - source_lines, globs, seen) - - # Below we re-run pieces of the above method with manual modifications, - # because the original code is buggy and fails to correctly identify - # doctests in extension modules. - - # Local shorthands - from inspect import ( - isroutine, isclass, ismodule, isfunction, ismethod - ) - - # Look for tests in a module's contained objects. - if ismodule(obj) and self._recurse: - for valname, val in obj.__dict__.items(): - valname1 = f'{name}.{valname}' - if ( (isroutine(val) or isclass(val)) - and self._from_module(module, val)): - - self._find(tests, val, valname1, module, source_lines, - globs, seen) - - # Look for tests in a class's contained objects. - if isclass(obj) and self._recurse: - for valname, val in obj.__dict__.items(): - # Special handling for staticmethod/classmethod. - if isinstance(val, staticmethod): - val = getattr(obj, valname) - if isinstance(val, classmethod): - val = getattr(obj, valname).__func__ - - # Recurse to methods, properties, and nested classes. - if ((isfunction(val) or isclass(val) or - ismethod(val) or isinstance(val, property)) and - self._from_module(module, val)): - valname = f'{name}.{valname}' - self._find(tests, val, valname, module, source_lines, - globs, seen) - - -# second-chance checker; if the default comparison doesn't -# pass, then see if the expected output string contains flags that -# tell us to ignore the output -class NumpyOutputChecker(doctest.OutputChecker): - def check_output(self, want, got, optionflags): - ret = doctest.OutputChecker.check_output(self, want, got, - optionflags) - if not ret: - if "#random" in want: - return True - - # it would be useful to normalize endianness so that - # bigendian machines don't fail all the tests (and there are - # actually some bigendian examples in the doctests). Let's try - # making them all little endian - got = got.replace("'>", "'<") - want = want.replace("'>", "'<") - - # try to normalize out 32 and 64 bit default int sizes - for sz in [4, 8]: - got = got.replace("'<i%d'" % sz, "int") - want = want.replace("'<i%d'" % sz, "int") - - ret = doctest.OutputChecker.check_output(self, want, - got, optionflags) - - return ret - - -# Subclass nose.plugins.doctests.DocTestCase to work around a bug in -# its constructor that blocks non-default arguments from being passed -# down into doctest.DocTestCase -class NumpyDocTestCase(npd.DocTestCase): - def __init__(self, test, optionflags=0, setUp=None, tearDown=None, - checker=None, obj=None, result_var='_'): - self._result_var = result_var - self._nose_obj = obj - doctest.DocTestCase.__init__(self, test, - optionflags=optionflags, - setUp=setUp, tearDown=tearDown, - checker=checker) - - -print_state = numpy.get_printoptions() - -class NumpyDoctest(npd.Doctest): - name = 'numpydoctest' # call nosetests with --with-numpydoctest - score = 1000 # load late, after doctest builtin - - # always use whitespace and ellipsis options for doctests - doctest_optflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS - - # files that should be ignored for doctests - doctest_ignore = ['generate_numpy_api.py', - 'setup.py'] - - # Custom classes; class variables to allow subclassing - doctest_case_class = NumpyDocTestCase - out_check_class = NumpyOutputChecker - test_finder_class = NumpyDocTestFinder - - # Don't use the standard doctest option handler; hard-code the option values - def options(self, parser, env=os.environ): - Plugin.options(self, parser, env) - # Test doctests in 'test' files / directories. Standard plugin default - # is False - self.doctest_tests = True - # Variable name; if defined, doctest results stored in this variable in - # the top-level namespace. None is the standard default - self.doctest_result_var = None - - def configure(self, options, config): - # parent method sets enabled flag from command line --with-numpydoctest - Plugin.configure(self, options, config) - self.finder = self.test_finder_class() - self.parser = doctest.DocTestParser() - if self.enabled: - # Pull standard doctest out of plugin list; there's no reason to run - # both. In practice the Unplugger plugin above would cover us when - # run from a standard numpy.test() call; this is just in case - # someone wants to run our plugin outside the numpy.test() machinery - config.plugins.plugins = [p for p in config.plugins.plugins - if p.name != 'doctest'] - - def set_test_context(self, test): - """ Configure `test` object to set test context - - We set the numpy / scipy standard doctest namespace - - Parameters - ---------- - test : test object - with ``globs`` dictionary defining namespace - - Returns - ------- - None - - Notes - ----- - `test` object modified in place - """ - # set the namespace for tests - pkg_name = get_package_name(os.path.dirname(test.filename)) - - # Each doctest should execute in an environment equivalent to - # starting Python and executing "import numpy as np", and, - # for SciPy packages, an additional import of the local - # package (so that scipy.linalg.basic.py's doctests have an - # implicit "from scipy import linalg" as well). - # - # Note: __file__ allows the doctest in NoseTester to run - # without producing an error - test.globs = {'__builtins__':__builtins__, - '__file__':'__main__', - '__name__':'__main__', - 'np':numpy} - # add appropriate scipy import for SciPy tests - if 'scipy' in pkg_name: - p = pkg_name.split('.') - p2 = p[-1] - test.globs[p2] = __import__(pkg_name, test.globs, {}, [p2]) - - # Override test loading to customize test context (with set_test_context - # method), set standard docstring options, and install our own test output - # checker - def loadTestsFromModule(self, module): - if not self.matches(module.__name__): - npd.log.debug("Doctest doesn't want module %s", module) - return - try: - tests = self.finder.find(module) - except AttributeError: - # nose allows module.__test__ = False; doctest does not and - # throws AttributeError - return - if not tests: - return - tests.sort() - module_file = src(module.__file__) - for test in tests: - if not test.examples: - continue - if not test.filename: - test.filename = module_file - # Set test namespace; test altered in place - self.set_test_context(test) - yield self.doctest_case_class(test, - optionflags=self.doctest_optflags, - checker=self.out_check_class(), - result_var=self.doctest_result_var) - - # Add an afterContext method to nose.plugins.doctests.Doctest in order - # to restore print options to the original state after each doctest - def afterContext(self): - numpy.set_printoptions(**print_state) - - # Ignore NumPy-specific build files that shouldn't be searched for tests - def wantFile(self, file): - bn = os.path.basename(file) - if bn in self.doctest_ignore: - return False - return npd.Doctest.wantFile(self, file) - - -class Unplugger: - """ Nose plugin to remove named plugin late in loading - - By default it removes the "doctest" plugin. - """ - name = 'unplugger' - enabled = True # always enabled - score = 4000 # load late in order to be after builtins - - def __init__(self, to_unplug='doctest'): - self.to_unplug = to_unplug - - def options(self, parser, env): - pass - - def configure(self, options, config): - # Pull named plugin out of plugins list - config.plugins.plugins = [p for p in config.plugins.plugins - if p.name != self.to_unplug] - - -class KnownFailurePlugin(ErrorClassPlugin): - '''Plugin that installs a KNOWNFAIL error class for the - KnownFailureClass exception. When KnownFailure is raised, - the exception will be logged in the knownfail attribute of the - result, 'K' or 'KNOWNFAIL' (verbose) will be output, and the - exception will not be counted as an error or failure.''' - enabled = True - knownfail = ErrorClass(KnownFailureException, - label='KNOWNFAIL', - isfailure=False) - - def options(self, parser, env=os.environ): - env_opt = 'NOSE_WITHOUT_KNOWNFAIL' - parser.add_option('--no-knownfail', action='store_true', - dest='noKnownFail', default=env.get(env_opt, False), - help='Disable special handling of KnownFailure ' - 'exceptions') - - def configure(self, options, conf): - if not self.can_configure: - return - self.conf = conf - disable = getattr(options, 'noKnownFail', False) - if disable: - self.enabled = False - -KnownFailure = KnownFailurePlugin # backwards compat - - -class FPUModeCheckPlugin(Plugin): - """ - Plugin that checks the FPU mode before and after each test, - raising failures if the test changed the mode. - """ - - def prepareTestCase(self, test): - from numpy.core._multiarray_tests import get_fpu_mode - - def run(result): - old_mode = get_fpu_mode() - test.test(result) - new_mode = get_fpu_mode() - - if old_mode != new_mode: - try: - raise AssertionError( - "FPU mode changed from {0:#x} to {1:#x} during the " - "test".format(old_mode, new_mode)) - except AssertionError: - result.addFailure(test, sys.exc_info()) - - return run - - -# Class allows us to save the results of the tests in runTests - see runTests -# method docstring for details -class NumpyTestProgram(nose.core.TestProgram): - def runTests(self): - """Run Tests. Returns true on success, false on failure, and - sets self.success to the same value. - - Because nose currently discards the test result object, but we need - to return it to the user, override TestProgram.runTests to retain - the result - """ - if self.testRunner is None: - self.testRunner = nose.core.TextTestRunner(stream=self.config.stream, - verbosity=self.config.verbosity, - config=self.config) - plug_runner = self.config.plugins.prepareTestRunner(self.testRunner) - if plug_runner is not None: - self.testRunner = plug_runner - self.result = self.testRunner.run(self.test) - self.success = self.result.wasSuccessful() - return self.success |