diff options
Diffstat (limited to 'nose')
-rw-r--r-- | nose/config.py | 24 | ||||
-rw-r--r-- | nose/core.py | 38 | ||||
-rw-r--r-- | nose/plugins/manager.py | 34 |
3 files changed, 60 insertions, 36 deletions
diff --git a/nose/config.py b/nose/config.py index d787fed..e110b7a 100644 --- a/nose/config.py +++ b/nose/config.py @@ -169,7 +169,7 @@ class Config(object): self.verbosity = int(env.get('NOSE_VERBOSE', 1)) self.where = () self.py3where = () - self.workingDir = None + self.workingDir = None """ def __init__(self, **kw): @@ -210,7 +210,7 @@ class Config(object): self.firstPackageWins = False self.parserClass = OptionParser self.worker = False - + self._default = self.__dict__.copy() self.update(kw) self._orig = self.__dict__.copy() @@ -237,7 +237,7 @@ class Config(object): dummy_parser = self.parserClass() self.plugins.addOptions(dummy_parser, {}) self.plugins.configure(self.options, self) - + def __repr__(self): d = self.__dict__.copy() # don't expose env, could include sensitive info @@ -289,7 +289,7 @@ class Config(object): if sys.version_info >= (3,): options.where = options.py3where - # `where` is an append action, so it can't have a default value + # `where` is an append action, so it can't have a default value # in the parser, or that default will always be in the list if not options.where: options.where = env.get('NOSE_WHERE', None) @@ -315,16 +315,16 @@ class Config(object): if options.where is not None: self.configureWhere(options.where) - + if options.testMatch: self.testMatch = re.compile(options.testMatch) - + if options.ignoreFiles: self.ignoreFiles = map(re.compile, tolist(options.ignoreFiles)) log.info("Ignoring files matching %s", options.ignoreFiles) else: log.info("Ignoring files matching %s", self.ignoreFilesDefaultStrings) - + if options.include: self.include = map(re.compile, tolist(options.include)) log.info("Including tests matching %s", options.include) @@ -348,7 +348,7 @@ class Config(object): from logging.config import fileConfig fileConfig(self.loggingConfig) return - + format = logging.Formatter('%(name)s: %(levelname)s: %(message)s') if self.debugLog: handler = logging.FileHandler(self.debugLog) @@ -364,7 +364,7 @@ class Config(object): if handler not in logger.handlers: logger.addHandler(handler) - # default level + # default level lvl = logging.WARNING if self.verbosity >= 5: lvl = 0 @@ -580,7 +580,7 @@ class Config(object): def todict(self): return self.__dict__.copy() - + def update(self, d): self.__dict__.update(d) @@ -590,13 +590,13 @@ class NoOptions(object): """ def __getstate__(self): return {} - + def __setstate__(self, state): pass def __getnewargs__(self): return () - + def __getattr__(self, attr): return None diff --git a/nose/core.py b/nose/core.py index e219903..36d966d 100644 --- a/nose/core.py +++ b/nose/core.py @@ -11,7 +11,7 @@ import unittest from nose.config import Config, all_config_files from nose.loader import defaultTestLoader from nose.plugins.manager import PluginManager, DefaultPluginManager, \ - RestrictedPluginManager + RestrictedPluginManager, ExtraPluginManager from nose.result import TextTestResult from nose.suite import FinalizingSuiteWrapper from nose.util import isclass, tolist @@ -23,12 +23,12 @@ compat_24 = sys.version_info >= (2, 4) __all__ = ['TestProgram', 'main', 'run', 'run_exit', 'runmodule', 'collector', 'TextTestRunner'] - + class TextTestRunner(unittest.TextTestRunner): """Test runner that uses nose's TextTestResult to enable errorClasses, as well as providing hooks for plugins to override or replace the test output stream, results, and the test case itself. - """ + """ def __init__(self, stream=sys.stderr, descriptions=1, verbosity=1, config=None): if config is None: @@ -36,7 +36,7 @@ class TextTestRunner(unittest.TextTestRunner): self.config = config unittest.TextTestRunner.__init__(self, stream, descriptions, verbosity) - + def _makeResult(self): return TextTestResult(self.stream, self.descriptions, @@ -50,12 +50,12 @@ class TextTestRunner(unittest.TextTestRunner): wrapper = self.config.plugins.prepareTest(test) if wrapper is not None: test = wrapper - + # plugins can decorate or capture the output stream wrapped = self.config.plugins.setOutputStream(self.stream) if wrapped is not None: self.stream = wrapped - + result = self._makeResult() start = time.time() test(result) @@ -65,7 +65,7 @@ class TextTestRunner(unittest.TextTestRunner): self.config.plugins.finalize(result) return result - + class TestProgram(unittest.TestProgram): """Collect and run tests, returning success or failure. @@ -104,7 +104,7 @@ class TestProgram(unittest.TestProgram): if config is None: config = self.makeConfig(env, plugins) if addplugins: - config.plugins.addPlugins(addplugins) + config.plugins.addPlugins(extraplugins=addplugins) self.config = config self.suite = suite self.exit = exit @@ -121,14 +121,14 @@ class TestProgram(unittest.TestProgram): """Load a Config, pre-filled with user config files if any are found. """ - cfg_files = all_config_files() + cfg_files = all_config_files() if plugins: manager = PluginManager(plugins=plugins) else: manager = DefaultPluginManager() return Config( env=env, files=cfg_files, plugins=manager) - + def parseArgs(self, argv): """Parse argv and env and configure running environment. """ @@ -146,7 +146,7 @@ class TestProgram(unittest.TestProgram): if self.config.options.showPlugins: self.showPlugins() sys.exit(0) - + if self.testLoader is None: self.testLoader = defaultTestLoader(config=self.config) elif isclass(self.testLoader): @@ -155,7 +155,7 @@ class TestProgram(unittest.TestProgram): if plug_loader is not None: self.testLoader = plug_loader log.debug("test loader is %s", self.testLoader) - + # FIXME if self.module is a string, add it to self.testNames? not sure if self.config.testNames: @@ -167,7 +167,7 @@ class TestProgram(unittest.TestProgram): if self.config.workingDir is not None: os.chdir(self.config.workingDir) self.createTests() - + def createTests(self): """Create the tests to run. If a self.suite is set, then that suite will be used. Otherwise, tests will be @@ -210,10 +210,10 @@ class TestProgram(unittest.TestProgram): self.options = [] def add_option(self, *arg, **kw): self.options.append((arg, kw.pop('help', ''))) - + v = self.config.verbosity self.config.plugins.sort() - for p in self.config.plugins: + for p in self.config.plugins: print "Plugin %s" % p.name if v >= 2: print " score: %s" % p.score @@ -234,7 +234,7 @@ class TestProgram(unittest.TestProgram): initial_indent=' ', subsequent_indent=' ')) print - + def usage(cls): import nose if hasattr(nose, '__loader__'): @@ -276,9 +276,9 @@ def run(*arg, **kw): * addplugins: List of **extra** plugins to use. Pass a list of plugin instances in this argument to make custom plugins available while still using the DefaultPluginManager. - + With the exception that the ``exit`` argument is always set - to False. + to False. """ kw['exit'] = False return TestProgram(*arg, **kw).success @@ -297,7 +297,7 @@ def collector(): unittest.TestSuite. The collector will, by default, load options from all config files and execute loader.loadTestsFromNames() on the configured testNames, or '.' if no testNames are configured. - """ + """ # plugins that implement any of these methods are disabled, since # we don't control the test runner and won't be able to run them # finalize() is also not called, but plugins that use it aren't disabled, diff --git a/nose/plugins/manager.py b/nose/plugins/manager.py index ce3e48a..5f1f1ea 100644 --- a/nose/plugins/manager.py +++ b/nose/plugins/manager.py @@ -17,6 +17,10 @@ The plugin managers provided with nose are: :class:`EntryPointPluginManager` This manager uses setuptools entrypoints to load plugins. +:class:`ExtraPluginsPluginManager` + This manager loads extra plugins specified with the keyword + `addplugins`. + :class:`DefaultPluginMananger` This is the manager class that will be used by default. If setuptools is installed, it is a subclass of @@ -361,9 +365,7 @@ class EntryPointPluginManager(PluginManager): def loadPlugins(self): """Load plugins by iterating the `nose.plugins` entry point. """ - super(EntryPointPluginManager, self).loadPlugins() from pkg_resources import iter_entry_points - loaded = {} for entry_point, adapt in self.entry_points: for ep in iter_entry_points(entry_point): @@ -387,6 +389,7 @@ class EntryPointPluginManager(PluginManager): else: plug = plugcls() self.addPlugin(plug) + super(EntryPointPluginManager, self).loadPlugins() class BuiltinPluginManager(PluginManager): @@ -401,13 +404,34 @@ class BuiltinPluginManager(PluginManager): self.addPlugin(plug()) super(BuiltinPluginManager, self).loadPlugins() +class ExtraPluginManager(PluginManager): + """Plugin manager that loads extra plugins specified + with the keyword `addplugins` + """ + def __init__(self, plugins=(), proxyClass=None): + super(ExtraPluginManager, self).__init__(plugins, proxyClass) + self._proxies['_extraplugins'] = () + + def addPlugins(self, plugins=(), extraplugins=()): + self._extraplugins = extraplugins + super(ExtraPluginManager, self).addPlugins(plugins) + + def loadPlugins(self): + for plug in self._extraplugins: + self.addPlugin(plug) + super(ExtraPluginManager, self).loadPlugins() + try: import pkg_resources - class DefaultPluginManager(BuiltinPluginManager, EntryPointPluginManager): + class DefaultPluginManager(BuiltinPluginManager, + EntryPointPluginManager, + ExtraPluginManager, + ): pass -except ImportError: - DefaultPluginManager = BuiltinPluginManager +except ImportError: + class DefaultPluginManager(BuiltinPluginManager, ExtraPluginManager): + pass class RestrictedPluginManager(DefaultPluginManager): """Plugin manager that restricts the plugin list to those not |