summaryrefslogtreecommitdiff
path: root/nose
diff options
context:
space:
mode:
authorBrendan McCollam <bmccollam@leapfrogonline.com>2011-11-09 16:17:53 -0600
committerBrendan McCollam <bmccollam@leapfrogonline.com>2011-11-09 16:17:53 -0600
commit43b6ada7c7ab612ffaef223affe3e66ff14a09fa (patch)
tree103c4a4e5e712a5818d7972b3dc75535ce0e5f62 /nose
parent0d9a2e01e228b8d143dd2c55da6443f3f533950b (diff)
downloadnose-43b6ada7c7ab612ffaef223affe3e66ff14a09fa.tar.gz
Changes to plugins.manager.py to allow plugins included with addplugins keyword to take precedence
Diffstat (limited to 'nose')
-rw-r--r--nose/config.py24
-rw-r--r--nose/core.py38
-rw-r--r--nose/plugins/manager.py27
3 files changed, 53 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..99b3e90 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)
+ ExtraPluginManager.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..5005b40 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,27 @@ class BuiltinPluginManager(PluginManager):
self.addPlugin(plug())
super(BuiltinPluginManager, self).loadPlugins()
+class ExtraPluginManager(PluginManager):
+ extraplugins = []
+ """Plugin manager that loads extra plugins specified
+ with the keyword `addplugins`
+ """
+ def loadPlugins(self):
+ for plug in self.__class__.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