/nose/plugins/base.py

https://bitbucket.org/jpellerin/nose/ · Python · 728 lines · 525 code · 39 blank · 164 comment · 39 complexity · 41b7950447ebf84f0ac2aa8470634714 MD5 · raw file

  1. import os
  2. import textwrap
  3. from optparse import OptionConflictError
  4. from warnings import warn
  5. from nose.util import tolist
  6. class Plugin(object):
  7. """Base class for nose plugins. It's recommended but not *necessary* to
  8. subclass this class to create a plugin, but all plugins *must* implement
  9. `options(self, parser, env)` and `configure(self, options, conf)`, and
  10. must have the attributes `enabled`, `name` and `score`. The `name`
  11. attribute may contain hyphens ('-').
  12. Plugins should not be enabled by default.
  13. Subclassing Plugin (and calling the superclass methods in
  14. __init__, configure, and options, if you override them) will give
  15. your plugin some friendly default behavior:
  16. * A --with-$name option will be added to the command line interface
  17. to enable the plugin, and a corresponding environment variable
  18. will be used as the default value. The plugin class's docstring
  19. will be used as the help for this option.
  20. * The plugin will not be enabled unless this option is selected by
  21. the user.
  22. """
  23. can_configure = False
  24. enabled = False
  25. enableOpt = None
  26. name = None
  27. score = 100
  28. def __init__(self):
  29. if self.name is None:
  30. self.name = self.__class__.__name__.lower()
  31. if self.enableOpt is None:
  32. self.enableOpt = "enable_plugin_%s" % self.name.replace('-', '_')
  33. def addOptions(self, parser, env=None):
  34. """Add command-line options for this plugin.
  35. The base plugin class adds --with-$name by default, used to enable the
  36. plugin.
  37. .. warning :: Don't implement addOptions unless you want to override
  38. all default option handling behavior, including
  39. warnings for conflicting options. Implement
  40. :meth:`options
  41. <nose.plugins.base.IPluginInterface.options>`
  42. instead.
  43. """
  44. self.add_options(parser, env)
  45. def add_options(self, parser, env=None):
  46. """Non-camel-case version of func name for backwards compatibility.
  47. .. warning ::
  48. DEPRECATED: Do not use this method,
  49. use :meth:`options <nose.plugins.base.IPluginInterface.options>`
  50. instead.
  51. """
  52. # FIXME raise deprecation warning if wasn't called by wrapper
  53. if env is None:
  54. env = os.environ
  55. try:
  56. self.options(parser, env)
  57. self.can_configure = True
  58. except OptionConflictError, e:
  59. warn("Plugin %s has conflicting option string: %s and will "
  60. "be disabled" % (self, e), RuntimeWarning)
  61. self.enabled = False
  62. self.can_configure = False
  63. def options(self, parser, env):
  64. """Register commandline options.
  65. Implement this method for normal options behavior with protection from
  66. OptionConflictErrors. If you override this method and want the default
  67. --with-$name option to be registered, be sure to call super().
  68. """
  69. env_opt = 'NOSE_WITH_%s' % self.name.upper()
  70. env_opt = env_opt.replace('-', '_')
  71. parser.add_option("--with-%s" % self.name,
  72. action="store_true",
  73. dest=self.enableOpt,
  74. default=env.get(env_opt),
  75. help="Enable plugin %s: %s [%s]" %
  76. (self.__class__.__name__, self.help(), env_opt))
  77. def configure(self, options, conf):
  78. """Configure the plugin and system, based on selected options.
  79. The base plugin class sets the plugin to enabled if the enable option
  80. for the plugin (self.enableOpt) is true.
  81. """
  82. if not self.can_configure:
  83. return
  84. self.conf = conf
  85. if hasattr(options, self.enableOpt):
  86. self.enabled = getattr(options, self.enableOpt)
  87. def help(self):
  88. """Return help for this plugin. This will be output as the help
  89. section of the --with-$name option that enables the plugin.
  90. """
  91. if self.__class__.__doc__:
  92. # doc sections are often indented; compress the spaces
  93. return textwrap.dedent(self.__class__.__doc__)
  94. return "(no help available)"
  95. # Compatiblity shim
  96. def tolist(self, val):
  97. warn("Plugin.tolist is deprecated. Use nose.util.tolist instead",
  98. DeprecationWarning)
  99. return tolist(val)
  100. class IPluginInterface(object):
  101. """
  102. IPluginInterface describes the plugin API. Do not subclass or use this
  103. class directly.
  104. """
  105. def __new__(cls, *arg, **kw):
  106. raise TypeError("IPluginInterface class is for documentation only")
  107. def addOptions(self, parser, env):
  108. """Called to allow plugin to register command-line options with the
  109. parser. DO NOT return a value from this method unless you want to stop
  110. all other plugins from setting their options.
  111. .. warning ::
  112. DEPRECATED -- implement
  113. :meth:`options <nose.plugins.base.IPluginInterface.options>` instead.
  114. """
  115. pass
  116. add_options = addOptions
  117. add_options.deprecated = True
  118. def addDeprecated(self, test):
  119. """Called when a deprecated test is seen. DO NOT return a value
  120. unless you want to stop other plugins from seeing the deprecated
  121. test.
  122. .. warning :: DEPRECATED -- check error class in addError instead
  123. """
  124. pass
  125. addDeprecated.deprecated = True
  126. def addError(self, test, err):
  127. """Called when a test raises an uncaught exception. DO NOT return a
  128. value unless you want to stop other plugins from seeing that the
  129. test has raised an error.
  130. :param test: the test case
  131. :type test: :class:`nose.case.Test`
  132. :param err: sys.exc_info() tuple
  133. :type err: 3-tuple
  134. """
  135. pass
  136. addError.changed = True
  137. def addFailure(self, test, err):
  138. """Called when a test fails. DO NOT return a value unless you
  139. want to stop other plugins from seeing that the test has failed.
  140. :param test: the test case
  141. :type test: :class:`nose.case.Test`
  142. :param err: 3-tuple
  143. :type err: sys.exc_info() tuple
  144. """
  145. pass
  146. addFailure.changed = True
  147. def addSkip(self, test):
  148. """Called when a test is skipped. DO NOT return a value unless
  149. you want to stop other plugins from seeing the skipped test.
  150. .. warning:: DEPRECATED -- check error class in addError instead
  151. """
  152. pass
  153. addSkip.deprecated = True
  154. def addSuccess(self, test):
  155. """Called when a test passes. DO NOT return a value unless you
  156. want to stop other plugins from seeing the passing test.
  157. :param test: the test case
  158. :type test: :class:`nose.case.Test`
  159. """
  160. pass
  161. addSuccess.changed = True
  162. def afterContext(self):
  163. """Called after a context (generally a module) has been
  164. lazy-loaded, imported, setup, had its tests loaded and
  165. executed, and torn down.
  166. """
  167. pass
  168. afterContext._new = True
  169. def afterDirectory(self, path):
  170. """Called after all tests have been loaded from directory at path
  171. and run.
  172. :param path: the directory that has finished processing
  173. :type path: string
  174. """
  175. pass
  176. afterDirectory._new = True
  177. def afterImport(self, filename, module):
  178. """Called after module is imported from filename. afterImport
  179. is called even if the import failed.
  180. :param filename: The file that was loaded
  181. :type filename: string
  182. :param filename: The name of the module
  183. :type module: string
  184. """
  185. pass
  186. afterImport._new = True
  187. def afterTest(self, test):
  188. """Called after the test has been run and the result recorded
  189. (after stopTest).
  190. :param test: the test case
  191. :type test: :class:`nose.case.Test`
  192. """
  193. pass
  194. afterTest._new = True
  195. def beforeContext(self):
  196. """Called before a context (generally a module) is
  197. examined. Because the context is not yet loaded, plugins don't
  198. get to know what the context is; so any context operations
  199. should use a stack that is pushed in `beforeContext` and popped
  200. in `afterContext` to ensure they operate symmetrically.
  201. `beforeContext` and `afterContext` are mainly useful for tracking
  202. and restoring global state around possible changes from within a
  203. context, whatever the context may be. If you need to operate on
  204. contexts themselves, see `startContext` and `stopContext`, which
  205. are passed the context in question, but are called after
  206. it has been loaded (imported in the module case).
  207. """
  208. pass
  209. beforeContext._new = True
  210. def beforeDirectory(self, path):
  211. """Called before tests are loaded from directory at path.
  212. :param path: the directory that is about to be processed
  213. """
  214. pass
  215. beforeDirectory._new = True
  216. def beforeImport(self, filename, module):
  217. """Called before module is imported from filename.
  218. :param filename: The file that will be loaded
  219. :param module: The name of the module found in file
  220. :type module: string
  221. """
  222. beforeImport._new = True
  223. def beforeTest(self, test):
  224. """Called before the test is run (before startTest).
  225. :param test: the test case
  226. :type test: :class:`nose.case.Test`
  227. """
  228. pass
  229. beforeTest._new = True
  230. def begin(self):
  231. """Called before any tests are collected or run. Use this to
  232. perform any setup needed before testing begins.
  233. """
  234. pass
  235. def configure(self, options, conf):
  236. """Called after the command line has been parsed, with the
  237. parsed options and the config container. Here, implement any
  238. config storage or changes to state or operation that are set
  239. by command line options.
  240. DO NOT return a value from this method unless you want to
  241. stop all other plugins from being configured.
  242. """
  243. pass
  244. def finalize(self, result):
  245. """Called after all report output, including output from all
  246. plugins, has been sent to the stream. Use this to print final
  247. test results or perform final cleanup. Return None to allow
  248. other plugins to continue printing, or any other value to stop
  249. them.
  250. :param result: test result object
  251. .. Note:: When tests are run under a test runner other than
  252. :class:`nose.core.TextTestRunner`, such as
  253. via ``python setup.py test``, this method may be called
  254. **before** the default report output is sent.
  255. """
  256. pass
  257. def describeTest(self, test):
  258. """Return a test description.
  259. Called by :meth:`nose.case.Test.shortDescription`.
  260. :param test: the test case
  261. :type test: :class:`nose.case.Test`
  262. """
  263. pass
  264. describeTest._new = True
  265. def formatError(self, test, err):
  266. """Called in result.addError, before plugin.addError. If you
  267. want to replace or modify the error tuple, return a new error
  268. tuple.
  269. :param test: the test case
  270. :type test: :class:`nose.case.Test`
  271. :param err: sys.exc_info() tuple
  272. :type err: 3-tuple
  273. """
  274. pass
  275. formatError._new = True
  276. formatError.chainable = True
  277. # test arg is not chainable
  278. formatError.static_args = (True, False)
  279. def formatFailure(self, test, err):
  280. """Called in result.addFailure, before plugin.addFailure. If you
  281. want to replace or modify the error tuple, return a new error
  282. tuple. Because this method is chainable, you must return the
  283. test as well, so you'll return something like::
  284. return (test, err)
  285. :param test: the test case
  286. :type test: :class:`nose.case.Test`
  287. :param err: sys.exc_info() tuple
  288. :type err: 3-tuple
  289. """
  290. pass
  291. formatFailure._new = True
  292. formatFailure.chainable = True
  293. # test arg is not chainable
  294. formatFailure.static_args = (True, False)
  295. def handleError(self, test, err):
  296. """Called on addError. To handle the error yourself and prevent normal
  297. error processing, return a true value.
  298. :param test: the test case
  299. :type test: :class:`nose.case.Test`
  300. :param err: sys.exc_info() tuple
  301. :type err: 3-tuple
  302. """
  303. pass
  304. handleError._new = True
  305. def handleFailure(self, test, err):
  306. """Called on addFailure. To handle the failure yourself and
  307. prevent normal failure processing, return a true value.
  308. :param test: the test case
  309. :type test: :class:`nose.case.Test`
  310. :param err: sys.exc_info() tuple
  311. :type err: 3-tuple
  312. """
  313. pass
  314. handleFailure._new = True
  315. def loadTestsFromDir(self, path):
  316. """Return iterable of tests from a directory. May be a
  317. generator. Each item returned must be a runnable
  318. unittest.TestCase (or subclass) instance or suite instance.
  319. Return None if your plugin cannot collect any tests from
  320. directory.
  321. :param path: The path to the directory.
  322. """
  323. pass
  324. loadTestsFromDir.generative = True
  325. loadTestsFromDir._new = True
  326. def loadTestsFromModule(self, module, path=None):
  327. """Return iterable of tests in a module. May be a
  328. generator. Each item returned must be a runnable
  329. unittest.TestCase (or subclass) instance.
  330. Return None if your plugin cannot
  331. collect any tests from module.
  332. :param module: The module object
  333. :type module: python module
  334. :param path: the path of the module to search, to distinguish from
  335. namespace package modules
  336. .. note::
  337. NEW. The ``path`` parameter will only be passed by nose 0.11
  338. or above.
  339. """
  340. pass
  341. loadTestsFromModule.generative = True
  342. def loadTestsFromName(self, name, module=None, importPath=None):
  343. """Return tests in this file or module. Return None if you are not able
  344. to load any tests, or an iterable if you are. May be a
  345. generator.
  346. :param name: The test name. May be a file or module name plus a test
  347. callable. Use split_test_name to split into parts. Or it might
  348. be some crazy name of your own devising, in which case, do
  349. whatever you want.
  350. :param module: Module from which the name is to be loaded
  351. :param importPath: Path from which file (must be a python module) was
  352. found
  353. .. warning:: DEPRECATED: this argument will NOT be passed.
  354. """
  355. pass
  356. loadTestsFromName.generative = True
  357. def loadTestsFromNames(self, names, module=None):
  358. """Return a tuple of (tests loaded, remaining names). Return
  359. None if you are not able to load any tests. Multiple plugins
  360. may implement loadTestsFromNames; the remaining name list from
  361. each will be passed to the next as input.
  362. :param names: List of test names.
  363. :type names: iterable
  364. :param module: Module from which the names are to be loaded
  365. """
  366. pass
  367. loadTestsFromNames._new = True
  368. loadTestsFromNames.chainable = True
  369. def loadTestsFromFile(self, filename):
  370. """Return tests in this file. Return None if you are not
  371. interested in loading any tests, or an iterable if you are and
  372. can load some. May be a generator. *If you are interested in
  373. loading tests from the file and encounter no errors, but find
  374. no tests, yield False or return [False].*
  375. .. Note:: This method replaces loadTestsFromPath from the 0.9
  376. API.
  377. :param filename: The full path to the file or directory.
  378. """
  379. pass
  380. loadTestsFromFile.generative = True
  381. loadTestsFromFile._new = True
  382. def loadTestsFromPath(self, path):
  383. """
  384. .. warning:: DEPRECATED -- use loadTestsFromFile instead
  385. """
  386. pass
  387. loadTestsFromPath.deprecated = True
  388. def loadTestsFromTestCase(self, cls):
  389. """Return tests in this test case class. Return None if you are
  390. not able to load any tests, or an iterable if you are. May be a
  391. generator.
  392. :param cls: The test case class. Must be subclass of
  393. :class:`unittest.TestCase`.
  394. """
  395. pass
  396. loadTestsFromTestCase.generative = True
  397. def loadTestsFromTestClass(self, cls):
  398. """Return tests in this test class. Class will *not* be a
  399. unittest.TestCase subclass. Return None if you are not able to
  400. load any tests, an iterable if you are. May be a generator.
  401. :param cls: The test case class. Must be **not** be subclass of
  402. :class:`unittest.TestCase`.
  403. """
  404. pass
  405. loadTestsFromTestClass._new = True
  406. loadTestsFromTestClass.generative = True
  407. def makeTest(self, obj, parent):
  408. """Given an object and its parent, return or yield one or more
  409. test cases. Each test must be a unittest.TestCase (or subclass)
  410. instance. This is called before default test loading to allow
  411. plugins to load an alternate test case or cases for an
  412. object. May be a generator.
  413. :param obj: The object to be made into a test
  414. :param parent: The parent of obj (eg, for a method, the class)
  415. """
  416. pass
  417. makeTest._new = True
  418. makeTest.generative = True
  419. def options(self, parser, env):
  420. """Called to allow plugin to register command line
  421. options with the parser.
  422. DO NOT return a value from this method unless you want to stop
  423. all other plugins from setting their options.
  424. :param parser: options parser instance
  425. :type parser: :class:`ConfigParser.ConfigParser`
  426. :param env: environment, default is os.environ
  427. """
  428. pass
  429. options._new = True
  430. def prepareTest(self, test):
  431. """Called before the test is run by the test runner. Please
  432. note the article *the* in the previous sentence: prepareTest
  433. is called *only once*, and is passed the test case or test
  434. suite that the test runner will execute. It is *not* called
  435. for each individual test case. If you return a non-None value,
  436. that return value will be run as the test. Use this hook to
  437. wrap or decorate the test with another function. If you need
  438. to modify or wrap individual test cases, use `prepareTestCase`
  439. instead.
  440. :param test: the test case
  441. :type test: :class:`nose.case.Test`
  442. """
  443. pass
  444. def prepareTestCase(self, test):
  445. """Prepare or wrap an individual test case. Called before
  446. execution of the test. The test passed here is a
  447. nose.case.Test instance; the case to be executed is in the
  448. test attribute of the passed case. To modify the test to be
  449. run, you should return a callable that takes one argument (the
  450. test result object) -- it is recommended that you *do not*
  451. side-effect the nose.case.Test instance you have been passed.
  452. Keep in mind that when you replace the test callable you are
  453. replacing the run() method of the test case -- including the
  454. exception handling and result calls, etc.
  455. :param test: the test case
  456. :type test: :class:`nose.case.Test`
  457. """
  458. pass
  459. prepareTestCase._new = True
  460. def prepareTestLoader(self, loader):
  461. """Called before tests are loaded. To replace the test loader,
  462. return a test loader. To allow other plugins to process the
  463. test loader, return None. Only one plugin may replace the test
  464. loader. Only valid when using nose.TestProgram.
  465. :param loader: :class:`nose.loader.TestLoader`
  466. (or other loader) instance
  467. """
  468. pass
  469. prepareTestLoader._new = True
  470. def prepareTestResult(self, result):
  471. """Called before the first test is run. To use a different
  472. test result handler for all tests than the given result,
  473. return a test result handler. NOTE however that this handler
  474. will only be seen by tests, that is, inside of the result
  475. proxy system. The TestRunner and TestProgram -- whether nose's
  476. or other -- will continue to see the original result
  477. handler. For this reason, it is usually better to monkeypatch
  478. the result (for instance, if you want to handle some
  479. exceptions in a unique way). Only one plugin may replace the
  480. result, but many may monkeypatch it. If you want to
  481. monkeypatch and stop other plugins from doing so, monkeypatch
  482. and return the patched result.
  483. :param result: :class:`nose.result.TextTestResult`
  484. (or other result) instance
  485. """
  486. pass
  487. prepareTestResult._new = True
  488. def prepareTestRunner(self, runner):
  489. """Called before tests are run. To replace the test runner,
  490. return a test runner. To allow other plugins to process the
  491. test runner, return None. Only valid when using nose.TestProgram.
  492. :param runner: :class:`nose.core.TextTestRunner`
  493. (or other runner) instance
  494. """
  495. pass
  496. prepareTestRunner._new = True
  497. def report(self, stream):
  498. """Called after all error output has been printed. Print your
  499. plugin's report to the provided stream. Return None to allow
  500. other plugins to print reports, any other value to stop them.
  501. :param stream: stream object; send your output here
  502. :type stream: file-like object
  503. """
  504. pass
  505. def setOutputStream(self, stream):
  506. """Called before test output begins. To direct test output to a
  507. new stream, return a stream object, which must implement a
  508. `write(msg)` method. If you only want to note the stream, not
  509. capture or redirect it, then return None.
  510. :param stream: stream object; send your output here
  511. :type stream: file-like object
  512. """
  513. def startContext(self, context):
  514. """Called before context setup and the running of tests in the
  515. context. Note that tests have already been *loaded* from the
  516. context before this call.
  517. :param context: the context about to be setup. May be a module or
  518. class, or any other object that contains tests.
  519. """
  520. pass
  521. startContext._new = True
  522. def startTest(self, test):
  523. """Called before each test is run. DO NOT return a value unless
  524. you want to stop other plugins from seeing the test start.
  525. :param err: sys.exc_info() tuple
  526. :type err: 3-tuple
  527. """
  528. pass
  529. def stopContext(self, context):
  530. """Called after the tests in a context have run and the
  531. context has been torn down.
  532. :param context: the context about to be setup. May be a module or
  533. class, or any other object that contains tests.
  534. """
  535. pass
  536. stopContext._new = True
  537. def stopTest(self, test):
  538. """Called after each test is run. DO NOT return a value unless
  539. you want to stop other plugins from seeing that the test has stopped.
  540. :param err: sys.exc_info() tuple
  541. :type err: 3-tuple
  542. """
  543. pass
  544. def testName(self, test):
  545. """Return a short test name. Called by `nose.case.Test.__str__`.
  546. :param err: sys.exc_info() tuple
  547. :type err: 3-tuple
  548. """
  549. pass
  550. testName._new = True
  551. def wantClass(self, cls):
  552. """Return true if you want the main test selector to collect
  553. tests from this class, false if you don't, and None if you don't
  554. care.
  555. :param cls: The class being examined by the selector
  556. """
  557. pass
  558. def wantDirectory(self, dirname):
  559. """Return true if you want test collection to descend into this
  560. directory, false if you do not, and None if you don't care.
  561. :param dirname: Full path to directory being examined by the selector
  562. """
  563. pass
  564. def wantFile(self, file):
  565. """Return true if you want to collect tests from this file,
  566. false if you do not and None if you don't care.
  567. Change from 0.9: The optional package parameter is no longer passed.
  568. :param file: Full path to file being examined by the selector
  569. """
  570. pass
  571. def wantFunction(self, function):
  572. """Return true to collect this function as a test, false to
  573. prevent it from being collected, and None if you don't care.
  574. :param function: The function object being examined by the selector
  575. """
  576. pass
  577. def wantMethod(self, method):
  578. """Return true to collect this method as a test, false to
  579. prevent it from being collected, and None if you don't care.
  580. :param method: The method object being examined by the selector
  581. :type method: unbound method
  582. """
  583. pass
  584. def wantModule(self, module):
  585. """Return true if you want to collection to descend into this
  586. module, false to prevent the collector from descending into the
  587. module, and None if you don't care.
  588. :param module: The module object being examined by the selector
  589. :type module: python module
  590. """
  591. pass
  592. def wantModuleTests(self, module):
  593. """
  594. .. warning:: DEPRECATED -- this method will not be called, it has
  595. been folded into wantModule.
  596. """
  597. pass
  598. wantModuleTests.deprecated = True