Commits

Brendan McCollam  committed ea4ea8f

Changes to plugins.manager.py to allow plugins included with addplugins keyword to take precedence

  • Participants
  • Parent commits 1efe5b5

Comments (0)

Files changed (4)

File functional_tests/test_defaultpluginmanager.py

+import unittest
+from nose.plugins import Plugin
+from nose.plugins.manager import DefaultPluginManager, ExtraPluginManager
+
+class OverridesSkip(Plugin):
+    """Plugin to override the built-in Skip"""
+    enabled = True
+    name = 'skip'
+    is_overridden = True
+
+class TestDefaultPluginManager(unittest.TestCase):
+
+    def setUp(self):
+        ExtraPluginManager.extraplugins = [OverridesSkip()]
+
+    def test_extraplugins_override_builtins(self):
+        pm = DefaultPluginManager()
+        pm.loadPlugins()
+        skip_plugin = next(p for p in pm.plugins if p.name == "skip")
+        overridden = getattr(skip_plugin, 'is_overridden', False)
+        self.assertTrue(overridden)
+
+    def tearDown(self):
+        ExtraPluginManager.extraplugins = []

File nose/config.py

       self.verbosity = int(env.get('NOSE_VERBOSE', 1))
       self.where = ()
       self.py3where = ()
-      self.workingDir = None   
+      self.workingDir = None
     """
 
     def __init__(self, **kw):
         self.firstPackageWins = False
         self.parserClass = OptionParser
         self.worker = False
-        
+
         self._default = self.__dict__.copy()
         self.update(kw)
         self._orig = self.__dict__.copy()
         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
             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)
 
         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)
             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)
         if handler not in logger.handlers:
             logger.addHandler(handler)
 
-        # default level    
+        # default level
         lvl = logging.WARNING
         if self.verbosity >= 5:
             lvl = 0
 
     def todict(self):
         return self.__dict__.copy()
-        
+
     def update(self, d):
         self.__dict__.update(d)
 
     """
     def __getstate__(self):
         return {}
-    
+
     def __setstate__(self, state):
         pass
 
     def __getnewargs__(self):
         return ()
-    
+
     def __getattr__(self, attr):
         return None
 

File nose/core.py

 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
 __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:
         self.config = config
         unittest.TextTestRunner.__init__(self, stream, descriptions, verbosity)
 
-    
+
     def _makeResult(self):
         return TextTestResult(self.stream,
                               self.descriptions,
         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)
         self.config.plugins.finalize(result)
         return result
 
-    
+
 class TestProgram(unittest.TestProgram):
     """Collect and run tests, returning success or failure.
 
         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
         """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.
         """
         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):
         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:
         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
                 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
                                                   initial_indent='    ',
                                                   subsequent_indent='    '))
                 print
-            
+
     def usage(cls):
         import nose
         if hasattr(nose, '__loader__'):
     * 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
     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,

File nose/plugins/manager.py

 :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
     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):
                 else:
                     plug = plugcls()
                 self.addPlugin(plug)
+        super(EntryPointPluginManager, self).loadPlugins()
 
 
 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
-
+    class DefaultPluginManager(BuiltinPluginManager, ExtraPluginManager):
+        pass
 
 class RestrictedPluginManager(DefaultPluginManager):
     """Plugin manager that restricts the plugin list to those not