loader.py 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623
  1. """
  2. Test Loader
  3. -----------
  4. nose's test loader implements the same basic functionality as its
  5. superclass, unittest.TestLoader, but extends it by more liberal
  6. interpretations of what may be a test and how a test may be named.
  7. """
  8. from __future__ import generators
  9. import logging
  10. import os
  11. import sys
  12. import unittest
  13. import types
  14. from inspect import isfunction
  15. from nose.pyversion import unbound_method, ismethod
  16. from nose.case import FunctionTestCase, MethodTestCase
  17. from nose.failure import Failure
  18. from nose.config import Config
  19. from nose.importer import Importer, add_path, remove_path
  20. from nose.selector import defaultSelector, TestAddress
  21. from nose.util import func_lineno, getpackage, isclass, isgenerator, \
  22. ispackage, regex_last_key, resolve_name, transplant_func, \
  23. transplant_class, test_address
  24. from nose.suite import ContextSuiteFactory, ContextList, LazySuite
  25. from nose.pyversion import sort_list, cmp_to_key
  26. log = logging.getLogger(__name__)
  27. #log.setLevel(logging.DEBUG)
  28. # for efficiency and easier mocking
  29. op_normpath = os.path.normpath
  30. op_abspath = os.path.abspath
  31. op_join = os.path.join
  32. op_isdir = os.path.isdir
  33. op_isfile = os.path.isfile
  34. __all__ = ['TestLoader', 'defaultTestLoader']
  35. class TestLoader(unittest.TestLoader):
  36. """Test loader that extends unittest.TestLoader to:
  37. * Load tests from test-like functions and classes that are not
  38. unittest.TestCase subclasses
  39. * Find and load test modules in a directory
  40. * Support tests that are generators
  41. * Support easy extensions of or changes to that behavior through plugins
  42. """
  43. config = None
  44. importer = None
  45. workingDir = None
  46. selector = None
  47. suiteClass = None
  48. def __init__(self, config=None, importer=None, workingDir=None,
  49. selector=None):
  50. """Initialize a test loader.
  51. Parameters (all optional):
  52. * config: provide a `nose.config.Config`_ or other config class
  53. instance; if not provided a `nose.config.Config`_ with
  54. default values is used.
  55. * importer: provide an importer instance that implements
  56. `importFromPath`. If not provided, a
  57. `nose.importer.Importer`_ is used.
  58. * workingDir: the directory to which file and module names are
  59. relative. If not provided, assumed to be the current working
  60. directory.
  61. * selector: a selector class or instance. If a class is
  62. provided, it will be instantiated with one argument, the
  63. current config. If not provided, a `nose.selector.Selector`_
  64. is used.
  65. """
  66. if config is None:
  67. config = Config()
  68. if importer is None:
  69. importer = Importer(config=config)
  70. if workingDir is None:
  71. workingDir = config.workingDir
  72. if selector is None:
  73. selector = defaultSelector(config)
  74. elif isclass(selector):
  75. selector = selector(config)
  76. self.config = config
  77. self.importer = importer
  78. self.workingDir = op_normpath(op_abspath(workingDir))
  79. self.selector = selector
  80. if config.addPaths:
  81. add_path(workingDir, config)
  82. self.suiteClass = ContextSuiteFactory(config=config)
  83. self._visitedPaths = set([])
  84. unittest.TestLoader.__init__(self)
  85. def getTestCaseNames(self, testCaseClass):
  86. """Override to select with selector, unless
  87. config.getTestCaseNamesCompat is True
  88. """
  89. if self.config.getTestCaseNamesCompat:
  90. return unittest.TestLoader.getTestCaseNames(self, testCaseClass)
  91. def wanted(attr, cls=testCaseClass, sel=self.selector):
  92. item = getattr(cls, attr, None)
  93. if isfunction(item):
  94. item = unbound_method(cls, item)
  95. elif not ismethod(item):
  96. return False
  97. return sel.wantMethod(item)
  98. cases = filter(wanted, dir(testCaseClass))
  99. # add runTest if nothing else picked
  100. if not cases and hasattr(testCaseClass, 'runTest'):
  101. cases = ['runTest']
  102. if self.sortTestMethodsUsing:
  103. sort_list(cases, cmp_to_key(self.sortTestMethodsUsing))
  104. return cases
  105. def _haveVisited(self, path):
  106. # For cases where path is None, we always pretend we haven't visited
  107. # them.
  108. if path is None:
  109. return False
  110. return path in self._visitedPaths
  111. def _addVisitedPath(self, path):
  112. if path is not None:
  113. self._visitedPaths.add(path)
  114. def loadTestsFromDir(self, path):
  115. """Load tests from the directory at path. This is a generator
  116. -- each suite of tests from a module or other file is yielded
  117. and is expected to be executed before the next file is
  118. examined.
  119. """
  120. log.debug("load from dir %s", path)
  121. plugins = self.config.plugins
  122. plugins.beforeDirectory(path)
  123. if self.config.addPaths:
  124. paths_added = add_path(path, self.config)
  125. entries = os.listdir(path)
  126. sort_list(entries, regex_last_key(self.config.testMatch))
  127. for entry in entries:
  128. # this hard-coded initial-dot test will be removed:
  129. # http://code.google.com/p/python-nose/issues/detail?id=82
  130. if entry.startswith('.'):
  131. continue
  132. entry_path = op_abspath(op_join(path, entry))
  133. is_file = op_isfile(entry_path)
  134. wanted = False
  135. if is_file:
  136. is_dir = False
  137. wanted = self.selector.wantFile(entry_path)
  138. else:
  139. is_dir = op_isdir(entry_path)
  140. if is_dir:
  141. # this hard-coded initial-underscore test will be removed:
  142. # http://code.google.com/p/python-nose/issues/detail?id=82
  143. if entry.startswith('_'):
  144. continue
  145. wanted = self.selector.wantDirectory(entry_path)
  146. is_package = ispackage(entry_path)
  147. # Python 3.3 now implements PEP 420: Implicit Namespace Packages.
  148. # As a result, it's now possible that parent paths that have a
  149. # segment with the same basename as our package ends up
  150. # in module.__path__. So we have to keep track of what we've
  151. # visited, and not-revisit them again.
  152. if wanted and not self._haveVisited(entry_path):
  153. self._addVisitedPath(entry_path)
  154. if is_file:
  155. plugins.beforeContext()
  156. if entry.endswith('.py'):
  157. yield self.loadTestsFromName(
  158. entry_path, discovered=True)
  159. else:
  160. yield self.loadTestsFromFile(entry_path)
  161. plugins.afterContext()
  162. elif is_package:
  163. # Load the entry as a package: given the full path,
  164. # loadTestsFromName() will figure it out
  165. yield self.loadTestsFromName(
  166. entry_path, discovered=True)
  167. else:
  168. # Another test dir in this one: recurse lazily
  169. yield self.suiteClass(
  170. lambda: self.loadTestsFromDir(entry_path))
  171. tests = []
  172. for test in plugins.loadTestsFromDir(path):
  173. tests.append(test)
  174. # TODO: is this try/except needed?
  175. try:
  176. if tests:
  177. yield self.suiteClass(tests)
  178. except (KeyboardInterrupt, SystemExit):
  179. raise
  180. except:
  181. yield self.suiteClass([Failure(*sys.exc_info())])
  182. # pop paths
  183. if self.config.addPaths:
  184. for p in paths_added:
  185. remove_path(p)
  186. plugins.afterDirectory(path)
  187. def loadTestsFromFile(self, filename):
  188. """Load tests from a non-module file. Default is to raise a
  189. ValueError; plugins may implement `loadTestsFromFile` to
  190. provide a list of tests loaded from the file.
  191. """
  192. log.debug("Load from non-module file %s", filename)
  193. try:
  194. tests = [test for test in
  195. self.config.plugins.loadTestsFromFile(filename)]
  196. if tests:
  197. # Plugins can yield False to indicate that they were
  198. # unable to load tests from a file, but it was not an
  199. # error -- the file just had no tests to load.
  200. tests = filter(None, tests)
  201. return self.suiteClass(tests)
  202. else:
  203. # Nothing was able to even try to load from this file
  204. open(filename, 'r').close() # trigger os error
  205. raise ValueError("Unable to load tests from file %s"
  206. % filename)
  207. except (KeyboardInterrupt, SystemExit):
  208. raise
  209. except:
  210. exc = sys.exc_info()
  211. return self.suiteClass(
  212. [Failure(exc[0], exc[1], exc[2],
  213. address=(filename, None, None))])
  214. def loadTestsFromGenerator(self, generator, module):
  215. """Lazy-load tests from a generator function. The generator function
  216. may yield either:
  217. * a callable, or
  218. * a function name resolvable within the same module
  219. """
  220. def generate(g=generator, m=module):
  221. try:
  222. for test in g():
  223. test_func, arg = self.parseGeneratedTest(test)
  224. if not callable(test_func):
  225. test_func = getattr(m, test_func)
  226. yield FunctionTestCase(test_func, arg=arg, descriptor=g)
  227. except KeyboardInterrupt:
  228. raise
  229. except:
  230. exc = sys.exc_info()
  231. yield Failure(exc[0], exc[1], exc[2],
  232. address=test_address(generator))
  233. return self.suiteClass(generate, context=generator, can_split=False)
  234. def loadTestsFromGeneratorMethod(self, generator, cls):
  235. """Lazy-load tests from a generator method.
  236. This is more complicated than loading from a generator function,
  237. since a generator method may yield:
  238. * a function
  239. * a bound or unbound method, or
  240. * a method name
  241. """
  242. # convert the unbound generator method
  243. # into a bound method so it can be called below
  244. if hasattr(generator, 'im_class'):
  245. cls = generator.im_class
  246. inst = cls()
  247. method = generator.__name__
  248. generator = getattr(inst, method)
  249. def generate(g=generator, c=cls):
  250. try:
  251. for test in g():
  252. test_func, arg = self.parseGeneratedTest(test)
  253. if not callable(test_func):
  254. test_func = unbound_method(c, getattr(c, test_func))
  255. if ismethod(test_func):
  256. yield MethodTestCase(test_func, arg=arg, descriptor=g)
  257. elif callable(test_func):
  258. # In this case we're forcing the 'MethodTestCase'
  259. # to run the inline function as its test call,
  260. # but using the generator method as the 'method of
  261. # record' (so no need to pass it as the descriptor)
  262. yield MethodTestCase(g, test=test_func, arg=arg)
  263. else:
  264. yield Failure(
  265. TypeError,
  266. "%s is not a callable or method" % test_func)
  267. except KeyboardInterrupt:
  268. raise
  269. except:
  270. exc = sys.exc_info()
  271. yield Failure(exc[0], exc[1], exc[2],
  272. address=test_address(generator))
  273. return self.suiteClass(generate, context=generator, can_split=False)
  274. def loadTestsFromModule(self, module, path=None, discovered=False):
  275. """Load all tests from module and return a suite containing
  276. them. If the module has been discovered and is not test-like,
  277. the suite will be empty by default, though plugins may add
  278. their own tests.
  279. """
  280. log.debug("Load from module %s", module)
  281. tests = []
  282. test_classes = []
  283. test_funcs = []
  284. # For *discovered* modules, we only load tests when the module looks
  285. # testlike. For modules we've been directed to load, we always
  286. # look for tests. (discovered is set to True by loadTestsFromDir)
  287. if not discovered or self.selector.wantModule(module):
  288. for item in dir(module):
  289. test = getattr(module, item, None)
  290. # print "Check %s (%s) in %s" % (item, test, module.__name__)
  291. if isclass(test):
  292. if self.selector.wantClass(test):
  293. test_classes.append(test)
  294. elif isfunction(test) and self.selector.wantFunction(test):
  295. test_funcs.append(test)
  296. sort_list(test_classes, lambda x: x.__name__)
  297. sort_list(test_funcs, func_lineno)
  298. tests = map(lambda t: self.makeTest(t, parent=module),
  299. test_classes + test_funcs)
  300. # Now, descend into packages
  301. # FIXME can or should this be lazy?
  302. # is this syntax 2.2 compatible?
  303. module_paths = getattr(module, '__path__', [])
  304. if path:
  305. path = os.path.normcase(os.path.realpath(path))
  306. for module_path in module_paths:
  307. log.debug("Load tests from module path %s?", module_path)
  308. log.debug("path: %s os.path.realpath(%s): %s",
  309. path, os.path.normcase(module_path),
  310. os.path.realpath(os.path.normcase(module_path)))
  311. if (self.config.traverseNamespace or not path) or \
  312. os.path.realpath(
  313. os.path.normcase(module_path)).startswith(path):
  314. # Egg files can be on sys.path, so make sure the path is a
  315. # directory before trying to load from it.
  316. if os.path.isdir(module_path):
  317. tests.extend(self.loadTestsFromDir(module_path))
  318. for test in self.config.plugins.loadTestsFromModule(module, path):
  319. tests.append(test)
  320. return self.suiteClass(ContextList(tests, context=module))
  321. def loadTestsFromName(self, name, module=None, discovered=False):
  322. """Load tests from the entity with the given name.
  323. The name may indicate a file, directory, module, or any object
  324. within a module. See `nose.util.split_test_name` for details on
  325. test name parsing.
  326. """
  327. # FIXME refactor this method into little bites?
  328. log.debug("load from %s (%s)", name, module)
  329. suite = self.suiteClass
  330. # give plugins first crack
  331. plug_tests = self.config.plugins.loadTestsFromName(name, module)
  332. if plug_tests:
  333. return suite(plug_tests)
  334. addr = TestAddress(name, workingDir=self.workingDir)
  335. if module:
  336. # Two cases:
  337. # name is class.foo
  338. # The addr will be incorrect, since it thinks class.foo is
  339. # a dotted module name. It's actually a dotted attribute
  340. # name. In this case we want to use the full submitted
  341. # name as the name to load from the module.
  342. # name is module:class.foo
  343. # The addr will be correct. The part we want is the part after
  344. # the :, which is in addr.call.
  345. if addr.call:
  346. name = addr.call
  347. parent, obj = self.resolve(name, module)
  348. if (isclass(parent)
  349. and getattr(parent, '__module__', None) != module.__name__
  350. and not isinstance(obj, Failure)):
  351. parent = transplant_class(parent, module.__name__)
  352. obj = getattr(parent, obj.__name__)
  353. log.debug("parent %s obj %s module %s", parent, obj, module)
  354. if isinstance(obj, Failure):
  355. return suite([obj])
  356. else:
  357. return suite(ContextList([self.makeTest(obj, parent)],
  358. context=parent))
  359. else:
  360. if addr.module:
  361. try:
  362. if addr.filename is None:
  363. module = resolve_name(addr.module)
  364. else:
  365. self.config.plugins.beforeImport(
  366. addr.filename, addr.module)
  367. # FIXME: to support module.name names,
  368. # do what resolve-name does and keep trying to
  369. # import, popping tail of module into addr.call,
  370. # until we either get an import or run out of
  371. # module parts
  372. try:
  373. module = self.importer.importFromPath(
  374. addr.filename, addr.module)
  375. finally:
  376. self.config.plugins.afterImport(
  377. addr.filename, addr.module)
  378. except (KeyboardInterrupt, SystemExit):
  379. raise
  380. except:
  381. exc = sys.exc_info()
  382. return suite([Failure(exc[0], exc[1], exc[2],
  383. address=addr.totuple())])
  384. if addr.call:
  385. return self.loadTestsFromName(addr.call, module)
  386. else:
  387. return self.loadTestsFromModule(
  388. module, addr.filename,
  389. discovered=discovered)
  390. elif addr.filename:
  391. path = addr.filename
  392. if addr.call:
  393. package = getpackage(path)
  394. if package is None:
  395. return suite([
  396. Failure(ValueError,
  397. "Can't find callable %s in file %s: "
  398. "file is not a python module" %
  399. (addr.call, path),
  400. address=addr.totuple())])
  401. return self.loadTestsFromName(addr.call, module=package)
  402. else:
  403. if op_isdir(path):
  404. # In this case we *can* be lazy since we know
  405. # that each module in the dir will be fully
  406. # loaded before its tests are executed; we
  407. # also know that we're not going to be asked
  408. # to load from . and ./some_module.py *as part
  409. # of this named test load*
  410. return LazySuite(
  411. lambda: self.loadTestsFromDir(path))
  412. elif op_isfile(path):
  413. return self.loadTestsFromFile(path)
  414. else:
  415. return suite([
  416. Failure(OSError, "No such file %s" % path,
  417. address=addr.totuple())])
  418. else:
  419. # just a function? what to do? I think it can only be
  420. # handled when module is not None
  421. return suite([
  422. Failure(ValueError, "Unresolvable test name %s" % name,
  423. address=addr.totuple())])
  424. def loadTestsFromNames(self, names, module=None):
  425. """Load tests from all names, returning a suite containing all
  426. tests.
  427. """
  428. plug_res = self.config.plugins.loadTestsFromNames(names, module)
  429. if plug_res:
  430. suite, names = plug_res
  431. if suite:
  432. return self.suiteClass([
  433. self.suiteClass(suite),
  434. unittest.TestLoader.loadTestsFromNames(self, names, module)
  435. ])
  436. return unittest.TestLoader.loadTestsFromNames(self, names, module)
  437. def loadTestsFromTestCase(self, testCaseClass):
  438. """Load tests from a unittest.TestCase subclass.
  439. """
  440. cases = []
  441. plugins = self.config.plugins
  442. for case in plugins.loadTestsFromTestCase(testCaseClass):
  443. cases.append(case)
  444. # For efficiency in the most common case, just call and return from
  445. # super. This avoids having to extract cases and rebuild a context
  446. # suite when there are no plugin-contributed cases.
  447. if not cases:
  448. return super(TestLoader, self).loadTestsFromTestCase(testCaseClass)
  449. cases.extend(
  450. [case for case in
  451. super(TestLoader, self).loadTestsFromTestCase(testCaseClass)])
  452. return self.suiteClass(cases)
  453. def loadTestsFromTestClass(self, cls):
  454. """Load tests from a test class that is *not* a unittest.TestCase
  455. subclass.
  456. In this case, we can't depend on the class's `__init__` taking method
  457. name arguments, so we have to compose a MethodTestCase for each
  458. method in the class that looks testlike.
  459. """
  460. def wanted(attr, cls=cls, sel=self.selector):
  461. item = getattr(cls, attr, None)
  462. if isfunction(item):
  463. item = unbound_method(cls, item)
  464. elif not ismethod(item):
  465. return False
  466. return sel.wantMethod(item)
  467. cases = [self.makeTest(getattr(cls, case), cls)
  468. for case in filter(wanted, dir(cls))]
  469. for test in self.config.plugins.loadTestsFromTestClass(cls):
  470. cases.append(test)
  471. return self.suiteClass(ContextList(cases, context=cls))
  472. def makeTest(self, obj, parent=None):
  473. try:
  474. return self._makeTest(obj, parent)
  475. except (KeyboardInterrupt, SystemExit):
  476. raise
  477. except:
  478. exc = sys.exc_info()
  479. try:
  480. addr = test_address(obj)
  481. except KeyboardInterrupt:
  482. raise
  483. except:
  484. addr = None
  485. return Failure(exc[0], exc[1], exc[2], address=addr)
  486. def _makeTest(self, obj, parent=None):
  487. """Given a test object and its parent, return a test case
  488. or test suite.
  489. """
  490. plug_tests = []
  491. try:
  492. addr = test_address(obj)
  493. except KeyboardInterrupt:
  494. raise
  495. except:
  496. addr = None
  497. for test in self.config.plugins.makeTest(obj, parent):
  498. plug_tests.append(test)
  499. # TODO: is this try/except needed?
  500. try:
  501. if plug_tests:
  502. return self.suiteClass(plug_tests)
  503. except (KeyboardInterrupt, SystemExit):
  504. raise
  505. except:
  506. exc = sys.exc_info()
  507. return Failure(exc[0], exc[1], exc[2], address=addr)
  508. if isfunction(obj) and parent and not isinstance(parent, types.ModuleType):
  509. # This is a Python 3.x 'unbound method'. Wrap it with its
  510. # associated class..
  511. obj = unbound_method(parent, obj)
  512. if isinstance(obj, unittest.TestCase):
  513. return obj
  514. elif isclass(obj):
  515. if parent and obj.__module__ != parent.__name__:
  516. obj = transplant_class(obj, parent.__name__)
  517. if issubclass(obj, unittest.TestCase):
  518. return self.loadTestsFromTestCase(obj)
  519. else:
  520. return self.loadTestsFromTestClass(obj)
  521. elif ismethod(obj):
  522. if parent is None:
  523. parent = obj.__class__
  524. if issubclass(parent, unittest.TestCase):
  525. return parent(obj.__name__)
  526. else:
  527. if isgenerator(obj):
  528. return self.loadTestsFromGeneratorMethod(obj, parent)
  529. else:
  530. return MethodTestCase(obj)
  531. elif isfunction(obj):
  532. if parent and obj.__module__ != parent.__name__:
  533. obj = transplant_func(obj, parent.__name__)
  534. if isgenerator(obj):
  535. return self.loadTestsFromGenerator(obj, parent)
  536. else:
  537. return FunctionTestCase(obj)
  538. else:
  539. return Failure(TypeError,
  540. "Can't make a test from %s" % obj,
  541. address=addr)
  542. def resolve(self, name, module):
  543. """Resolve name within module
  544. """
  545. obj = module
  546. parts = name.split('.')
  547. for part in parts:
  548. parent, obj = obj, getattr(obj, part, None)
  549. if obj is None:
  550. # no such test
  551. obj = Failure(ValueError, "No such test %s" % name)
  552. return parent, obj
  553. def parseGeneratedTest(self, test):
  554. """Given the yield value of a test generator, return a func and args.
  555. This is used in the two loadTestsFromGenerator* methods.
  556. """
  557. if not isinstance(test, tuple): # yield test
  558. test_func, arg = (test, tuple())
  559. elif len(test) == 1: # yield (test,)
  560. test_func, arg = (test[0], tuple())
  561. else: # yield test, foo, bar, ...
  562. assert len(test) > 1 # sanity check
  563. test_func, arg = (test[0], test[1:])
  564. return test_func, arg
  565. defaultTestLoader = TestLoader