PageRenderTime 30ms CodeModel.GetById 10ms app.highlight 14ms RepoModel.GetById 1ms app.codeStats 0ms

/nose/plugins/base.py

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