summaryrefslogtreecommitdiff
path: root/lib/spack/external/nose/suite.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/spack/external/nose/suite.py')
-rw-r--r--lib/spack/external/nose/suite.py609
1 files changed, 0 insertions, 609 deletions
diff --git a/lib/spack/external/nose/suite.py b/lib/spack/external/nose/suite.py
deleted file mode 100644
index a831105e34..0000000000
--- a/lib/spack/external/nose/suite.py
+++ /dev/null
@@ -1,609 +0,0 @@
-"""
-Test Suites
------------
-
-Provides a LazySuite, which is a suite whose test list is a generator
-function, and ContextSuite,which can run fixtures (setup/teardown
-functions or methods) for the context that contains its tests.
-
-"""
-from __future__ import generators
-
-import logging
-import sys
-import unittest
-from nose.case import Test
-from nose.config import Config
-from nose.proxy import ResultProxyFactory
-from nose.util import isclass, resolve_name, try_run
-
-if sys.platform == 'cli':
- if sys.version_info[:2] < (2, 6):
- import clr
- clr.AddReference("IronPython")
- from IronPython.Runtime.Exceptions import StringException
- else:
- class StringException(Exception):
- pass
-
-log = logging.getLogger(__name__)
-#log.setLevel(logging.DEBUG)
-
-# Singleton for default value -- see ContextSuite.__init__ below
-_def = object()
-
-
-def _strclass(cls):
- return "%s.%s" % (cls.__module__, cls.__name__)
-
-class MixedContextError(Exception):
- """Error raised when a context suite sees tests from more than
- one context.
- """
- pass
-
-
-class LazySuite(unittest.TestSuite):
- """A suite that may use a generator as its list of tests
- """
- def __init__(self, tests=()):
- """Initialize the suite. tests may be an iterable or a generator
- """
- super(LazySuite, self).__init__()
- self._set_tests(tests)
-
- def __iter__(self):
- return iter(self._tests)
-
- def __repr__(self):
- return "<%s tests=generator (%s)>" % (
- _strclass(self.__class__), id(self))
-
- def __hash__(self):
- return object.__hash__(self)
-
- __str__ = __repr__
-
- def addTest(self, test):
- self._precache.append(test)
-
- # added to bypass run changes in 2.7's unittest
- def run(self, result):
- for test in self._tests:
- if result.shouldStop:
- break
- test(result)
- return result
-
- def __nonzero__(self):
- log.debug("tests in %s?", id(self))
- if self._precache:
- return True
- if self.test_generator is None:
- return False
- try:
- test = self.test_generator.next()
- if test is not None:
- self._precache.append(test)
- return True
- except StopIteration:
- pass
- return False
-
- def _get_tests(self):
- log.debug("precache is %s", self._precache)
- for test in self._precache:
- yield test
- if self.test_generator is None:
- return
- for test in self.test_generator:
- yield test
-
- def _set_tests(self, tests):
- self._precache = []
- is_suite = isinstance(tests, unittest.TestSuite)
- if callable(tests) and not is_suite:
- self.test_generator = tests()
- elif is_suite:
- # Suites need special treatment: they must be called like
- # tests for their setup/teardown to run (if any)
- self.addTests([tests])
- self.test_generator = None
- else:
- self.addTests(tests)
- self.test_generator = None
-
- _tests = property(_get_tests, _set_tests, None,
- "Access the tests in this suite. Access is through a "
- "generator, so iteration may not be repeatable.")
-
-
-class ContextSuite(LazySuite):
- """A suite with context.
-
- A ContextSuite executes fixtures (setup and teardown functions or
- methods) for the context containing its tests.
-
- The context may be explicitly passed. If it is not, a context (or
- nested set of contexts) will be constructed by examining the tests
- in the suite.
- """
- failureException = unittest.TestCase.failureException
- was_setup = False
- was_torndown = False
- classSetup = ('setup_class', 'setup_all', 'setupClass', 'setupAll',
- 'setUpClass', 'setUpAll')
- classTeardown = ('teardown_class', 'teardown_all', 'teardownClass',
- 'teardownAll', 'tearDownClass', 'tearDownAll')
- moduleSetup = ('setup_module', 'setupModule', 'setUpModule', 'setup',
- 'setUp')
- moduleTeardown = ('teardown_module', 'teardownModule', 'tearDownModule',
- 'teardown', 'tearDown')
- packageSetup = ('setup_package', 'setupPackage', 'setUpPackage')
- packageTeardown = ('teardown_package', 'teardownPackage',
- 'tearDownPackage')
-
- def __init__(self, tests=(), context=None, factory=None,
- config=None, resultProxy=None, can_split=True):
- log.debug("Context suite for %s (%s) (%s)", tests, context, id(self))
- self.context = context
- self.factory = factory
- if config is None:
- config = Config()
- self.config = config
- self.resultProxy = resultProxy
- self.has_run = False
- self.can_split = can_split
- self.error_context = None
- super(ContextSuite, self).__init__(tests)
-
- def __repr__(self):
- return "<%s context=%s>" % (
- _strclass(self.__class__),
- getattr(self.context, '__name__', self.context))
- __str__ = __repr__
-
- def id(self):
- if self.error_context:
- return '%s:%s' % (repr(self), self.error_context)
- else:
- return repr(self)
-
- def __hash__(self):
- return object.__hash__(self)
-
- # 2.3 compat -- force 2.4 call sequence
- def __call__(self, *arg, **kw):
- return self.run(*arg, **kw)
-
- def exc_info(self):
- """Hook for replacing error tuple output
- """
- return sys.exc_info()
-
- def _exc_info(self):
- """Bottleneck to fix up IronPython string exceptions
- """
- e = self.exc_info()
- if sys.platform == 'cli':
- if isinstance(e[0], StringException):
- # IronPython throws these StringExceptions, but
- # traceback checks type(etype) == str. Make a real
- # string here.
- e = (str(e[0]), e[1], e[2])
-
- return e
-
- def run(self, result):
- """Run tests in suite inside of suite fixtures.
- """
- # proxy the result for myself
- log.debug("suite %s (%s) run called, tests: %s", id(self), self, self._tests)
- #import pdb
- #pdb.set_trace()
- if self.resultProxy:
- result, orig = self.resultProxy(result, self), result
- else:
- result, orig = result, result
- try:
- self.setUp()
- except KeyboardInterrupt:
- raise
- except:
- self.error_context = 'setup'
- result.addError(self, self._exc_info())
- return
- try:
- for test in self._tests:
- if result.shouldStop:
- log.debug("stopping")
- break
- # each nose.case.Test will create its own result proxy
- # so the cases need the original result, to avoid proxy
- # chains
- test(orig)
- finally:
- self.has_run = True
- try:
- self.tearDown()
- except KeyboardInterrupt:
- raise
- except:
- self.error_context = 'teardown'
- result.addError(self, self._exc_info())
-
- def hasFixtures(self, ctx_callback=None):
- context = self.context
- if context is None:
- return False
- if self.implementsAnyFixture(context, ctx_callback=ctx_callback):
- return True
- # My context doesn't have any, but its ancestors might
- factory = self.factory
- if factory:
- ancestors = factory.context.get(self, [])
- for ancestor in ancestors:
- if self.implementsAnyFixture(
- ancestor, ctx_callback=ctx_callback):
- return True
- return False
-
- def implementsAnyFixture(self, context, ctx_callback):
- if isclass(context):
- names = self.classSetup + self.classTeardown
- else:
- names = self.moduleSetup + self.moduleTeardown
- if hasattr(context, '__path__'):
- names += self.packageSetup + self.packageTeardown
- # If my context has any fixture attribute, I have fixtures
- fixt = False
- for m in names:
- if hasattr(context, m):
- fixt = True
- break
- if ctx_callback is None:
- return fixt
- return ctx_callback(context, fixt)
-
- def setUp(self):
- log.debug("suite %s setUp called, tests: %s", id(self), self._tests)
- if not self:
- # I have no tests
- log.debug("suite %s has no tests", id(self))
- return
- if self.was_setup:
- log.debug("suite %s already set up", id(self))
- return
- context = self.context
- if context is None:
- return
- # before running my own context's setup, I need to
- # ask the factory if my context's contexts' setups have been run
- factory = self.factory
- if factory:
- # get a copy, since we'll be destroying it as we go
- ancestors = factory.context.get(self, [])[:]
- while ancestors:
- ancestor = ancestors.pop()
- log.debug("ancestor %s may need setup", ancestor)
- if ancestor in factory.was_setup:
- continue
- log.debug("ancestor %s does need setup", ancestor)
- self.setupContext(ancestor)
- if not context in factory.was_setup:
- self.setupContext(context)
- else:
- self.setupContext(context)
- self.was_setup = True
- log.debug("completed suite setup")
-
- def setupContext(self, context):
- self.config.plugins.startContext(context)
- log.debug("%s setup context %s", self, context)
- if self.factory:
- if context in self.factory.was_setup:
- return
- # note that I ran the setup for this context, so that I'll run
- # the teardown in my teardown
- self.factory.was_setup[context] = self
- if isclass(context):
- names = self.classSetup
- else:
- names = self.moduleSetup
- if hasattr(context, '__path__'):
- names = self.packageSetup + names
- try_run(context, names)
-
- def shortDescription(self):
- if self.context is None:
- return "test suite"
- return "test suite for %s" % self.context
-
- def tearDown(self):
- log.debug('context teardown')
- if not self.was_setup or self.was_torndown:
- log.debug(
- "No reason to teardown (was_setup? %s was_torndown? %s)"
- % (self.was_setup, self.was_torndown))
- return
- self.was_torndown = True
- context = self.context
- if context is None:
- log.debug("No context to tear down")
- return
-
- # for each ancestor... if the ancestor was setup
- # and I did the setup, I can do teardown
- factory = self.factory
- if factory:
- ancestors = factory.context.get(self, []) + [context]
- for ancestor in ancestors:
- log.debug('ancestor %s may need teardown', ancestor)
- if not ancestor in factory.was_setup:
- log.debug('ancestor %s was not setup', ancestor)
- continue
- if ancestor in factory.was_torndown:
- log.debug('ancestor %s already torn down', ancestor)
- continue
- setup = factory.was_setup[ancestor]
- log.debug("%s setup ancestor %s", setup, ancestor)
- if setup is self:
- self.teardownContext(ancestor)
- else:
- self.teardownContext(context)
-
- def teardownContext(self, context):
- log.debug("%s teardown context %s", self, context)
- if self.factory:
- if context in self.factory.was_torndown:
- return
- self.factory.was_torndown[context] = self
- if isclass(context):
- names = self.classTeardown
- else:
- names = self.moduleTeardown
- if hasattr(context, '__path__'):
- names = self.packageTeardown + names
- try_run(context, names)
- self.config.plugins.stopContext(context)
-
- # FIXME the wrapping has to move to the factory?
- def _get_wrapped_tests(self):
- for test in self._get_tests():
- if isinstance(test, Test) or isinstance(test, unittest.TestSuite):
- yield test
- else:
- yield Test(test,
- config=self.config,
- resultProxy=self.resultProxy)
-
- _tests = property(_get_wrapped_tests, LazySuite._set_tests, None,
- "Access the tests in this suite. Tests are returned "
- "inside of a context wrapper.")
-
-
-class ContextSuiteFactory(object):
- """Factory for ContextSuites. Called with a collection of tests,
- the factory decides on a hierarchy of contexts by introspecting
- the collection or the tests themselves to find the objects
- containing the test objects. It always returns one suite, but that
- suite may consist of a hierarchy of nested suites.
- """
- suiteClass = ContextSuite
- def __init__(self, config=None, suiteClass=None, resultProxy=_def):
- if config is None:
- config = Config()
- self.config = config
- if suiteClass is not None:
- self.suiteClass = suiteClass
- # Using a singleton to represent default instead of None allows
- # passing resultProxy=None to turn proxying off.
- if resultProxy is _def:
- resultProxy = ResultProxyFactory(config=config)
- self.resultProxy = resultProxy
- self.suites = {}
- self.context = {}
- self.was_setup = {}
- self.was_torndown = {}
-
- def __call__(self, tests, **kw):
- """Return ``ContextSuite`` for tests. ``tests`` may either
- be a callable (in which case the resulting ContextSuite will
- have no parent context and be evaluated lazily) or an
- iterable. In that case the tests will wrapped in
- nose.case.Test, be examined and the context of each found and a
- suite of suites returned, organized into a stack with the
- outermost suites belonging to the outermost contexts.
- """
- log.debug("Create suite for %s", tests)
- context = kw.pop('context', getattr(tests, 'context', None))
- log.debug("tests %s context %s", tests, context)
- if context is None:
- tests = self.wrapTests(tests)
- try:
- context = self.findContext(tests)
- except MixedContextError:
- return self.makeSuite(self.mixedSuites(tests), None, **kw)
- return self.makeSuite(tests, context, **kw)
-
- def ancestry(self, context):
- """Return the ancestry of the context (that is, all of the
- packages and modules containing the context), in order of
- descent with the outermost ancestor last.
- This method is a generator.
- """
- log.debug("get ancestry %s", context)
- if context is None:
- return
- # Methods include reference to module they are defined in, we
- # don't want that, instead want the module the class is in now
- # (classes are re-ancestored elsewhere).
- if hasattr(context, 'im_class'):
- context = context.im_class
- elif hasattr(context, '__self__'):
- context = context.__self__.__class__
- if hasattr(context, '__module__'):
- ancestors = context.__module__.split('.')
- elif hasattr(context, '__name__'):
- ancestors = context.__name__.split('.')[:-1]
- else:
- raise TypeError("%s has no ancestors?" % context)
- while ancestors:
- log.debug(" %s ancestors %s", context, ancestors)
- yield resolve_name('.'.join(ancestors))
- ancestors.pop()
-
- def findContext(self, tests):
- if callable(tests) or isinstance(tests, unittest.TestSuite):
- return None
- context = None
- for test in tests:
- # Don't look at suites for contexts, only tests
- ctx = getattr(test, 'context', None)
- if ctx is None:
- continue
- if context is None:
- context = ctx
- elif context != ctx:
- raise MixedContextError(
- "Tests with different contexts in same suite! %s != %s"
- % (context, ctx))
- return context
-
- def makeSuite(self, tests, context, **kw):
- suite = self.suiteClass(
- tests, context=context, config=self.config, factory=self,
- resultProxy=self.resultProxy, **kw)
- if context is not None:
- self.suites.setdefault(context, []).append(suite)
- self.context.setdefault(suite, []).append(context)
- log.debug("suite %s has context %s", suite,
- getattr(context, '__name__', None))
- for ancestor in self.ancestry(context):
- self.suites.setdefault(ancestor, []).append(suite)
- self.context[suite].append(ancestor)
- log.debug("suite %s has ancestor %s", suite, ancestor.__name__)
- return suite
-
- def mixedSuites(self, tests):
- """The complex case where there are tests that don't all share
- the same context. Groups tests into suites with common ancestors,
- according to the following (essentially tail-recursive) procedure:
-
- Starting with the context of the first test, if it is not
- None, look for tests in the remaining tests that share that
- ancestor. If any are found, group into a suite with that
- ancestor as the context, and replace the current suite with
- that suite. Continue this process for each ancestor of the
- first test, until all ancestors have been processed. At this
- point if any tests remain, recurse with those tests as the
- input, returning a list of the common suite (which may be the
- suite or test we started with, if no common tests were found)
- plus the results of recursion.
- """
- if not tests:
- return []
- head = tests.pop(0)
- if not tests:
- return [head] # short circuit when none are left to combine
- suite = head # the common ancestry suite, so far
- tail = tests[:]
- context = getattr(head, 'context', None)
- if context is not None:
- ancestors = [context] + [a for a in self.ancestry(context)]
- for ancestor in ancestors:
- common = [suite] # tests with ancestor in common, so far
- remain = [] # tests that remain to be processed
- for test in tail:
- found_common = False
- test_ctx = getattr(test, 'context', None)
- if test_ctx is None:
- remain.append(test)
- continue
- if test_ctx is ancestor:
- common.append(test)
- continue
- for test_ancestor in self.ancestry(test_ctx):
- if test_ancestor is ancestor:
- common.append(test)
- found_common = True
- break
- if not found_common:
- remain.append(test)
- if common:
- suite = self.makeSuite(common, ancestor)
- tail = self.mixedSuites(remain)
- return [suite] + tail
-
- def wrapTests(self, tests):
- log.debug("wrap %s", tests)
- if callable(tests) or isinstance(tests, unittest.TestSuite):
- log.debug("I won't wrap")
- return tests
- wrapped = []
- for test in tests:
- log.debug("wrapping %s", test)
- if isinstance(test, Test) or isinstance(test, unittest.TestSuite):
- wrapped.append(test)
- elif isinstance(test, ContextList):
- wrapped.append(self.makeSuite(test, context=test.context))
- else:
- wrapped.append(
- Test(test, config=self.config, resultProxy=self.resultProxy)
- )
- return wrapped
-
-
-class ContextList(object):
- """Not quite a suite -- a group of tests in a context. This is used
- to hint the ContextSuiteFactory about what context the tests
- belong to, in cases where it may be ambiguous or missing.
- """
- def __init__(self, tests, context=None):
- self.tests = tests
- self.context = context
-
- def __iter__(self):
- return iter(self.tests)
-
-
-class FinalizingSuiteWrapper(unittest.TestSuite):
- """Wraps suite and calls final function after suite has
- executed. Used to call final functions in cases (like running in
- the standard test runner) where test running is not under nose's
- control.
- """
- def __init__(self, suite, finalize):
- super(FinalizingSuiteWrapper, self).__init__()
- self.suite = suite
- self.finalize = finalize
-
- def __call__(self, *arg, **kw):
- return self.run(*arg, **kw)
-
- # 2.7 compat
- def __iter__(self):
- return iter(self.suite)
-
- def run(self, *arg, **kw):
- try:
- return self.suite(*arg, **kw)
- finally:
- self.finalize(*arg, **kw)
-
-
-# backwards compat -- sort of
-class TestDir:
- def __init__(*arg, **kw):
- raise NotImplementedError(
- "TestDir is not usable with nose 0.10. The class is present "
- "in nose.suite for backwards compatibility purposes but it "
- "may not be used.")
-
-
-class TestModule:
- def __init__(*arg, **kw):
- raise NotImplementedError(
- "TestModule is not usable with nose 0.10. The class is present "
- "in nose.suite for backwards compatibility purposes but it "
- "may not be used.")