core.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. """Implements nose test program and collector.
  2. """
  3. from __future__ import generators
  4. import logging
  5. import os
  6. import sys
  7. import time
  8. import unittest
  9. from nose.config import Config, all_config_files
  10. from nose.loader import defaultTestLoader
  11. from nose.plugins.manager import PluginManager, DefaultPluginManager, \
  12. RestrictedPluginManager
  13. from nose.result import TextTestResult
  14. from nose.suite import FinalizingSuiteWrapper
  15. from nose.util import isclass, tolist
  16. log = logging.getLogger('nose.core')
  17. compat_24 = sys.version_info >= (2, 4)
  18. __all__ = ['TestProgram', 'main', 'run', 'run_exit', 'runmodule', 'collector',
  19. 'TextTestRunner']
  20. class TextTestRunner(unittest.TextTestRunner):
  21. """Test runner that uses nose's TextTestResult to enable errorClasses,
  22. as well as providing hooks for plugins to override or replace the test
  23. output stream, results, and the test case itself.
  24. """
  25. def __init__(self, stream=sys.stderr, descriptions=1, verbosity=1,
  26. config=None):
  27. if config is None:
  28. config = Config()
  29. self.config = config
  30. unittest.TextTestRunner.__init__(self, stream, descriptions, verbosity)
  31. def _makeResult(self):
  32. return TextTestResult(self.stream,
  33. self.descriptions,
  34. self.verbosity,
  35. self.config)
  36. def run(self, test):
  37. """Overrides to provide plugin hooks and defer all output to
  38. the test result class.
  39. """
  40. wrapper = self.config.plugins.prepareTest(test)
  41. if wrapper is not None:
  42. test = wrapper
  43. # plugins can decorate or capture the output stream
  44. wrapped = self.config.plugins.setOutputStream(self.stream)
  45. if wrapped is not None:
  46. self.stream = wrapped
  47. result = self._makeResult()
  48. start = time.time()
  49. try:
  50. test(result)
  51. except KeyboardInterrupt:
  52. pass
  53. stop = time.time()
  54. result.printErrors()
  55. result.printSummary(start, stop)
  56. self.config.plugins.finalize(result)
  57. return result
  58. class TestProgram(unittest.TestProgram):
  59. """Collect and run tests, returning success or failure.
  60. The arguments to TestProgram() are the same as to
  61. :func:`main()` and :func:`run()`:
  62. * module: All tests are in this module (default: None)
  63. * defaultTest: Tests to load (default: '.')
  64. * argv: Command line arguments (default: None; sys.argv is read)
  65. * testRunner: Test runner instance (default: None)
  66. * testLoader: Test loader instance (default: None)
  67. * env: Environment; ignored if config is provided (default: None;
  68. os.environ is read)
  69. * config: :class:`nose.config.Config` instance (default: None)
  70. * suite: Suite or list of tests to run (default: None). Passing a
  71. suite or lists of tests will bypass all test discovery and
  72. loading. *ALSO NOTE* that if you pass a unittest.TestSuite
  73. instance as the suite, context fixtures at the class, module and
  74. package level will not be used, and many plugin hooks will not
  75. be called. If you want normal nose behavior, either pass a list
  76. of tests, or a fully-configured :class:`nose.suite.ContextSuite`.
  77. * exit: Exit after running tests and printing report (default: True)
  78. * plugins: List of plugins to use; ignored if config is provided
  79. (default: load plugins with DefaultPluginManager)
  80. * addplugins: List of **extra** plugins to use. Pass a list of plugin
  81. instances in this argument to make custom plugins available while
  82. still using the DefaultPluginManager.
  83. """
  84. verbosity = 1
  85. def __init__(self, module=None, defaultTest='.', argv=None,
  86. testRunner=None, testLoader=None, env=None, config=None,
  87. suite=None, exit=True, plugins=None, addplugins=None):
  88. if env is None:
  89. env = os.environ
  90. if config is None:
  91. config = self.makeConfig(env, plugins)
  92. if addplugins:
  93. config.plugins.addPlugins(extraplugins=addplugins)
  94. self.config = config
  95. self.suite = suite
  96. self.exit = exit
  97. extra_args = {}
  98. version = sys.version_info[0:2]
  99. if version >= (2,7) and version != (3,0):
  100. extra_args['exit'] = exit
  101. unittest.TestProgram.__init__(
  102. self, module=module, defaultTest=defaultTest,
  103. argv=argv, testRunner=testRunner, testLoader=testLoader,
  104. **extra_args)
  105. def getAllConfigFiles(self, env=None):
  106. env = env or {}
  107. if env.get('NOSE_IGNORE_CONFIG_FILES', False):
  108. return []
  109. else:
  110. return all_config_files()
  111. def makeConfig(self, env, plugins=None):
  112. """Load a Config, pre-filled with user config files if any are
  113. found.
  114. """
  115. cfg_files = self.getAllConfigFiles(env)
  116. if plugins:
  117. manager = PluginManager(plugins=plugins)
  118. else:
  119. manager = DefaultPluginManager()
  120. return Config(
  121. env=env, files=cfg_files, plugins=manager)
  122. def parseArgs(self, argv):
  123. """Parse argv and env and configure running environment.
  124. """
  125. self.config.configure(argv, doc=self.usage())
  126. log.debug("configured %s", self.config)
  127. # quick outs: version, plugins (optparse would have already
  128. # caught and exited on help)
  129. if self.config.options.version:
  130. from nose import __version__
  131. sys.stdout = sys.__stdout__
  132. print "%s version %s" % (os.path.basename(sys.argv[0]), __version__)
  133. sys.exit(0)
  134. if self.config.options.showPlugins:
  135. self.showPlugins()
  136. sys.exit(0)
  137. if self.testLoader is None:
  138. self.testLoader = defaultTestLoader(config=self.config)
  139. elif isclass(self.testLoader):
  140. self.testLoader = self.testLoader(config=self.config)
  141. plug_loader = self.config.plugins.prepareTestLoader(self.testLoader)
  142. if plug_loader is not None:
  143. self.testLoader = plug_loader
  144. log.debug("test loader is %s", self.testLoader)
  145. # FIXME if self.module is a string, add it to self.testNames? not sure
  146. if self.config.testNames:
  147. self.testNames = self.config.testNames
  148. else:
  149. self.testNames = tolist(self.defaultTest)
  150. log.debug('defaultTest %s', self.defaultTest)
  151. log.debug('Test names are %s', self.testNames)
  152. if self.config.workingDir is not None:
  153. os.chdir(self.config.workingDir)
  154. self.createTests()
  155. def createTests(self):
  156. """Create the tests to run. If a self.suite
  157. is set, then that suite will be used. Otherwise, tests will be
  158. loaded from the given test names (self.testNames) using the
  159. test loader.
  160. """
  161. log.debug("createTests called with %s", self.suite)
  162. if self.suite is not None:
  163. # We were given an explicit suite to run. Make sure it's
  164. # loaded and wrapped correctly.
  165. self.test = self.testLoader.suiteClass(self.suite)
  166. else:
  167. self.test = self.testLoader.loadTestsFromNames(self.testNames)
  168. def runTests(self):
  169. """Run Tests. Returns true on success, false on failure, and sets
  170. self.success to the same value.
  171. """
  172. log.debug("runTests called")
  173. if self.testRunner is None:
  174. self.testRunner = TextTestRunner(stream=self.config.stream,
  175. verbosity=self.config.verbosity,
  176. config=self.config)
  177. plug_runner = self.config.plugins.prepareTestRunner(self.testRunner)
  178. if plug_runner is not None:
  179. self.testRunner = plug_runner
  180. result = self.testRunner.run(self.test)
  181. self.success = result.wasSuccessful()
  182. if self.exit:
  183. sys.exit(not self.success)
  184. return self.success
  185. def showPlugins(self):
  186. """Print list of available plugins.
  187. """
  188. import textwrap
  189. class DummyParser:
  190. def __init__(self):
  191. self.options = []
  192. def add_option(self, *arg, **kw):
  193. self.options.append((arg, kw.pop('help', '')))
  194. v = self.config.verbosity
  195. self.config.plugins.sort()
  196. for p in self.config.plugins:
  197. print "Plugin %s" % p.name
  198. if v >= 2:
  199. print " score: %s" % p.score
  200. print '\n'.join(textwrap.wrap(p.help().strip(),
  201. initial_indent=' ',
  202. subsequent_indent=' '))
  203. if v >= 3:
  204. parser = DummyParser()
  205. p.addOptions(parser)
  206. if len(parser.options):
  207. print
  208. print " Options:"
  209. for opts, help in parser.options:
  210. print ' %s' % (', '.join(opts))
  211. if help:
  212. print '\n'.join(
  213. textwrap.wrap(help.strip(),
  214. initial_indent=' ',
  215. subsequent_indent=' '))
  216. print
  217. def usage(cls):
  218. import nose
  219. try:
  220. ld = nose.__loader__
  221. text = ld.get_data(os.path.join(
  222. os.path.dirname(__file__), 'usage.txt'))
  223. except AttributeError:
  224. f = open(os.path.join(
  225. os.path.dirname(__file__), 'usage.txt'), 'r')
  226. try:
  227. text = f.read()
  228. finally:
  229. f.close()
  230. # Ensure that we return str, not bytes.
  231. if not isinstance(text, str):
  232. text = text.decode('utf-8')
  233. return text
  234. usage = classmethod(usage)
  235. # backwards compatibility
  236. run_exit = main = TestProgram
  237. def run(*arg, **kw):
  238. """Collect and run tests, returning success or failure.
  239. The arguments to `run()` are the same as to `main()`:
  240. * module: All tests are in this module (default: None)
  241. * defaultTest: Tests to load (default: '.')
  242. * argv: Command line arguments (default: None; sys.argv is read)
  243. * testRunner: Test runner instance (default: None)
  244. * testLoader: Test loader instance (default: None)
  245. * env: Environment; ignored if config is provided (default: None;
  246. os.environ is read)
  247. * config: :class:`nose.config.Config` instance (default: None)
  248. * suite: Suite or list of tests to run (default: None). Passing a
  249. suite or lists of tests will bypass all test discovery and
  250. loading. *ALSO NOTE* that if you pass a unittest.TestSuite
  251. instance as the suite, context fixtures at the class, module and
  252. package level will not be used, and many plugin hooks will not
  253. be called. If you want normal nose behavior, either pass a list
  254. of tests, or a fully-configured :class:`nose.suite.ContextSuite`.
  255. * plugins: List of plugins to use; ignored if config is provided
  256. (default: load plugins with DefaultPluginManager)
  257. * addplugins: List of **extra** plugins to use. Pass a list of plugin
  258. instances in this argument to make custom plugins available while
  259. still using the DefaultPluginManager.
  260. With the exception that the ``exit`` argument is always set
  261. to False.
  262. """
  263. kw['exit'] = False
  264. return TestProgram(*arg, **kw).success
  265. def runmodule(name='__main__', **kw):
  266. """Collect and run tests in a single module only. Defaults to running
  267. tests in __main__. Additional arguments to TestProgram may be passed
  268. as keyword arguments.
  269. """
  270. main(defaultTest=name, **kw)
  271. def collector():
  272. """TestSuite replacement entry point. Use anywhere you might use a
  273. unittest.TestSuite. The collector will, by default, load options from
  274. all config files and execute loader.loadTestsFromNames() on the
  275. configured testNames, or '.' if no testNames are configured.
  276. """
  277. # plugins that implement any of these methods are disabled, since
  278. # we don't control the test runner and won't be able to run them
  279. # finalize() is also not called, but plugins that use it aren't disabled,
  280. # because capture needs it.
  281. setuptools_incompat = ('report', 'prepareTest',
  282. 'prepareTestLoader', 'prepareTestRunner',
  283. 'setOutputStream')
  284. plugins = RestrictedPluginManager(exclude=setuptools_incompat)
  285. conf = Config(files=all_config_files(),
  286. plugins=plugins)
  287. conf.configure(argv=['collector'])
  288. loader = defaultTestLoader(conf)
  289. if conf.testNames:
  290. suite = loader.loadTestsFromNames(conf.testNames)
  291. else:
  292. suite = loader.loadTestsFromNames(('.',))
  293. return FinalizingSuiteWrapper(suite, plugins.finalize)
  294. if __name__ == '__main__':
  295. main()