From aee874ee1c445dd581a7bbf5183455b7e9e4e86d Mon Sep 17 00:00:00 2001 From: Hans Ulrich Niedermann Date: Fri, 27 Jun 2008 00:38:48 +0200 Subject: Rename newplugins to plugins --- src/Makefile-files | 2 +- src/nbblib/__init__.py | 11 +- src/nbblib/bs.py | 3 +- src/nbblib/commands.py | 2 +- src/nbblib/main.py | 3 +- src/nbblib/newplugin-test.py | 19 --- src/nbblib/newplugins.py | 294 ------------------------------------------- src/nbblib/plugins.py | 294 +++++++++++++++++++++++++++++++++++++++++++ src/nbblib/test-plugins.py | 19 +++ src/nbblib/vcs.py | 3 +- 10 files changed, 325 insertions(+), 325 deletions(-) delete mode 100644 src/nbblib/newplugin-test.py delete mode 100644 src/nbblib/newplugins.py create mode 100644 src/nbblib/plugins.py create mode 100644 src/nbblib/test-plugins.py diff --git a/src/Makefile-files b/src/Makefile-files index bd6ea23..6707adc 100644 --- a/src/Makefile-files +++ b/src/Makefile-files @@ -9,7 +9,7 @@ nbblib_PYTHON += src/nbblib/__init__.py nbblib_PYTHON += src/nbblib/bs.py nbblib_PYTHON += src/nbblib/commands.py nbblib_PYTHON += src/nbblib/main.py -nbblib_PYTHON += src/nbblib/newplugins.py +nbblib_PYTHON += src/nbblib/plugins.py nbblib_PYTHON += src/nbblib/progutils.py nbblib_PYTHON += src/nbblib/vcs.py diff --git a/src/nbblib/__init__.py b/src/nbblib/__init__.py index 0c1a2c2..5f4a254 100644 --- a/src/nbblib/__init__.py +++ b/src/nbblib/__init__.py @@ -1,11 +1,14 @@ import nbblib.bs as bs import nbblib.commands as commands -import nbblib.newplugins as newplugins +import nbblib.plugins as plugins import nbblib.package as package -import nbblib.vcs as plugins +import nbblib.progutils as progutils +import nbblib.vcs as vcs from package import PACKAGE_VERSION -__all__ = ['bs', 'commands', 'newplugins', - 'package', 'plugins', 'vcs', +__all__ = ['bs', 'commands', + 'package', 'plugins', + 'progutils', + 'vcs', 'PACKAGE_VERSION'] diff --git a/src/nbblib/bs.py b/src/nbblib/bs.py index e794037..b5fd865 100644 --- a/src/nbblib/bs.py +++ b/src/nbblib/bs.py @@ -7,8 +7,7 @@ import os import logging from nbblib import progutils - -from nbblib import newplugins as plugins +from nbblib import plugins class NotABSSourceTree(plugins.PluginNoMatch): diff --git a/src/nbblib/commands.py b/src/nbblib/commands.py index 7c8e068..861b8ba 100644 --- a/src/nbblib/commands.py +++ b/src/nbblib/commands.py @@ -4,7 +4,7 @@ import logging import nbblib.package as package -import nbblib.newplugins as plugins +import nbblib.plugins as plugins import nbblib.progutils as progutils import nbblib.vcs as vcs import nbblib.bs as bs diff --git a/src/nbblib/main.py b/src/nbblib/main.py index 7d71e89..6e5d6d5 100644 --- a/src/nbblib/main.py +++ b/src/nbblib/main.py @@ -124,10 +124,9 @@ import logging from nbblib import bs from nbblib import commands from nbblib import package +from nbblib import plugins from nbblib import vcs -import nbblib.newplugins as plugins - def print_version(context): print "%(prog)s (ndim's branch builder) %(PACKAGE_VERSION)s" % context diff --git a/src/nbblib/newplugin-test.py b/src/nbblib/newplugin-test.py deleted file mode 100644 index 8082aec..0000000 --- a/src/nbblib/newplugin-test.py +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/python -"""Test newplugins module""" - -import logging -import sys - -logging.basicConfig(level = logging.DEBUG, - format = "%(levelname)s: %(message)s", - stream = sys.stderr) -if True: - logging.debug("xxx debug") - logging.info("xxx info") - logging.warning("xxx warn") - logging.error("xxx error") - - -import newplugins -newplugins.selftest() - diff --git a/src/nbblib/newplugins.py b/src/nbblib/newplugins.py deleted file mode 100644 index 1cb41cd..0000000 --- a/src/nbblib/newplugins.py +++ /dev/null @@ -1,294 +0,0 @@ -"""\ -newplugins.py - generic plugin system - -Basic plugin architecture (metaclass tricks) by Marty Alchin from -http://gulopine.gamemusic.org/2008/jan/10/simple-plugin-framework/ - -GenericPluginMeta slightly modified to - - store plugins as dict - - support plugin class hierarchies -Extended by GenericDetectPlugin to - - support auto-detection of the adequate plugin - -Example usage of the newplugins module: - -np = __import__(newplugins) - -Example non-auto-detection plugin: - -class NonDetectPluginType(object): - __metaclass__ = np.GenericPluginMeta - -class PluginA(NonDetectPluginType): - name = "PA" -class PluginB(NonDetectPluginType): - name = "PB" - -Example auto-detection plugin: - -class MyPluginType(np.GenericDetectPlugin): - __metaclass__ = np.GenericPluginMeta - - # The calling convention for constructor - # detect(context, ) - # is defined here, and the same is used - # to construct the exceptions. - - [no_match_exception = ...] - [ambigous_match_exception = ...] - [ - @classmethod - def validate(cls, obj, *args, **kwargs): - return True # or False, depending on params - ] - -class MyPluginA(MyPluginType): - name = "MA" - def __init__(self, context): - super(MyPluginA, self).__init__(self, context) - if not some_detection_successful: - raise self.no_match_exception() -class MyPluginB(MyPluginType): - name = "MB" - def __init__(self, context): - super(MyPluginB, self).__init__(self, context) - if not other_detection_successful: - raise self.no_match_exception() - -""" - - -import sys -import logging -import types -import functools - - -class NoPluginsRegistered(Exception): - def __init__(self, cls): - super(NoPluginsRegistered, self).__init__() - self.cls = cls - def __str__(self): - return "No plugins of type %s registered" % (self.cls.__name__) - - -class DuplicatePluginName(Exception): - pass - - -class PluginNoMatch(Exception): - def __init__(self, *args, **kwargs): - super(PluginNoMatch, self).__init__() - self.args = args - self.kwargs = kwargs - def __str__(self): - return "%s(%s,%s)" % (self.__class__.__name__, - self.args, self.kwargs) - - -class AmbigousPluginDetection(Exception): - def __init__(self, matches, cls, context, *args, **kwargs): - self.matches = matches - self.cls = cls - self.context = context - self.args = args - self.kwargs = kwargs - def __str__(self): - return "%s(%s.%s, %s, %s, %s, %s)" % (self.__class__.__name__, - self.cls.__module__, - self.cls.__name__, - self.matches, - self.context, - self.args, - self.kwargs) - - -# Might be used later when we do class introspection looking for -# abstract methods. -class UNUSED_AbstractMethodsInConcreteClass(Exception): - def __init__(self, cls, methods): - self.cls = cls - self.methods = methods - def __str__(self): - methods = "\n ".join(self.methods) - return "Concrete class %s.%s must implement these methods:\n %s" \ - % (self.cls.__module__, - self.cls.__name__, - methods) - - -class AbstractMethodError(Exception): - def __init__(self, name, module): - self.name = name - self.module = module - def __str__(self): - # FIXME: Class name? - return "Abstract method %s called someplace in %s" \ - % (repr(self.name), repr(self.module)) - - -def abstractmethod(fun): - @functools.wraps(fun) - def f(self, *args, **kwargs): - # fun(self, *args, **kwargs) - raise AbstractMethodError(name=fun.__name__, - module=fun.__module__) - # We might add some introspection tool later, to be run - # in e.g. GenericPluginMeta.__init__(...), which makes sure - # that there are no abstract methods in a non-abstract class. - # f.abstract_method = True - return f - - -class PluginDict(dict): - """Helper for GenericPluginMeta class - - Behaves basically like a standard dict, but will raise an exception - when asked to update an existing value. - """ - - # This is the important difference between PluginDict and dict. - def __setitem__(self, key, value): - if self.has_key(key): - raise DuplicatePluginName() - else: - super(PluginDict, self).__setitem__(key, value) - - -class GenericPluginMeta(type): - def __init__(cls, name, bases, attrs): - logging.debug("META_INIT %s %s %s %s", cls, name, bases, attrs) - if not hasattr(cls, 'plugins'): - # This branch only executes when processing the mount point itself. - # So, since this is a new plugin type, not an implementation, this - # class shouldn't be registered as a plugin. Instead, it sets up a - # list where plugins can be registered later. - cls.plugins = PluginDict() - elif cls.name is not None: - # This must be a plugin implementation, which should be registered. - # Simply appending it to the list is all that's needed to keep - # track of it later. - logging.debug("Registering %s together with %s", cls, cls.plugins) - cls.plugins[cls.name] = cls - else: - # This must be an abstract subclass of plugins. - pass - - -class GenericDetectPlugin(object): - no_match_exception = PluginNoMatch - ambigous_match_exception = AmbigousPluginDetection - - def __init__(self, context): - super(GenericDetectPlugin, self).__init__() - self.context = context - - @classmethod - def validate(cls, obj, *args, **kwargs): - logging.debug("GDval") - return True - - @classmethod - def detect(cls, context, *args, **kwargs): - """Detect stuff""" - logging.debug("DETECT %s", cls) - if len(cls.plugins) < 1: - raise NoPluginsRegistered(cls) - matches = PluginDict() - for key, klass in cls.plugins.iteritems(): - try: - t = klass(context, *args, **kwargs) - logging.debug("KLASS %s unvalidated, %s", klass, - klass.validate) - if klass.validate(t, *args, **kwargs): - logging.debug("KLASS %s validated", klass) - matches[key] = t - except PluginNoMatch, e: - pass - if len(matches) > 1: - raise cls.ambigous_match_exception(matches, - cls, context, - *args, **kwargs) - elif len(matches) < 1: - raise cls.no_match_exception(*args, **kwargs) - return matches[matches.keys()[0]] - - -def selftest(): - - class PluginNoMatchA(PluginNoMatch): - pass - class AmbigousPluginDetectionA(AmbigousPluginDetection): - pass - - - class TestDetectPluginA(GenericDetectPlugin): - __metaclass__ = GenericPluginMeta - no_match_exception = PluginNoMatchA - ambigous_match_exception = AmbigousPluginDetectionA - @classmethod - def validate(cls, obj, *args, **kwargs): - logging.debug("Aval") - return False - - - class TestDetectPluginB(GenericDetectPlugin): - __metaclass__ = GenericPluginMeta - - - class TestDetectPluginC(GenericDetectPlugin): - __metaclass__ = GenericPluginMeta - @classmethod - def validate(cls, obj, *args, **kwargs): - logging.debug("Cval") - return False - - - class TestDetectPluginA1(TestDetectPluginA): - name = "A1" - class TestDetectPluginA2(TestDetectPluginA): - name = "A2" - class TestDetectPluginA3(TestDetectPluginA): - name = "A3" - - class TestDetectPluginB1(TestDetectPluginB): - name = "B1" - class TestDetectPluginB2(TestDetectPluginB): - name = "B2" - class TestDetectPluginB3(TestDetectPluginB): - name = "B3" - - class TestDetectPluginC1(TestDetectPluginC): - name = "C1" - class TestDetectPluginC2(TestDetectPluginC): - name = "C2" - class TestDetectPluginC3(TestDetectPluginC): - name = "C3" - @classmethod - def validate(cls, obj, *args, **kwargs): - logging.debug("C3val") - return True - - ctx = None - - print "GenericPluginMeta", dir(GenericPluginMeta) - print "GenericDetectPlugin", dir(GenericDetectPlugin) - print "TestDetectPluginA", dir(TestDetectPluginA) - print "TestDetectPluginA", dir(TestDetectPluginA) - print "TestDetectPluginB", dir(TestDetectPluginB) - print "TestDetectPluginC", dir(TestDetectPluginC) - - try: - a = TestDetectPluginA.detect(ctx) - except: - logging.error("aaaa", exc_info=True) - - try: - b = TestDetectPluginB.detect(ctx) - except: - logging.error("bbbb", exc_info=True) - - try: - c = TestDetectPluginC.detect(ctx) - except: - logging.error("cccc", exc_info=True) diff --git a/src/nbblib/plugins.py b/src/nbblib/plugins.py new file mode 100644 index 0000000..1cb41cd --- /dev/null +++ b/src/nbblib/plugins.py @@ -0,0 +1,294 @@ +"""\ +newplugins.py - generic plugin system + +Basic plugin architecture (metaclass tricks) by Marty Alchin from +http://gulopine.gamemusic.org/2008/jan/10/simple-plugin-framework/ + +GenericPluginMeta slightly modified to + - store plugins as dict + - support plugin class hierarchies +Extended by GenericDetectPlugin to + - support auto-detection of the adequate plugin + +Example usage of the newplugins module: + +np = __import__(newplugins) + +Example non-auto-detection plugin: + +class NonDetectPluginType(object): + __metaclass__ = np.GenericPluginMeta + +class PluginA(NonDetectPluginType): + name = "PA" +class PluginB(NonDetectPluginType): + name = "PB" + +Example auto-detection plugin: + +class MyPluginType(np.GenericDetectPlugin): + __metaclass__ = np.GenericPluginMeta + + # The calling convention for constructor + # detect(context, ) + # is defined here, and the same is used + # to construct the exceptions. + + [no_match_exception = ...] + [ambigous_match_exception = ...] + [ + @classmethod + def validate(cls, obj, *args, **kwargs): + return True # or False, depending on params + ] + +class MyPluginA(MyPluginType): + name = "MA" + def __init__(self, context): + super(MyPluginA, self).__init__(self, context) + if not some_detection_successful: + raise self.no_match_exception() +class MyPluginB(MyPluginType): + name = "MB" + def __init__(self, context): + super(MyPluginB, self).__init__(self, context) + if not other_detection_successful: + raise self.no_match_exception() + +""" + + +import sys +import logging +import types +import functools + + +class NoPluginsRegistered(Exception): + def __init__(self, cls): + super(NoPluginsRegistered, self).__init__() + self.cls = cls + def __str__(self): + return "No plugins of type %s registered" % (self.cls.__name__) + + +class DuplicatePluginName(Exception): + pass + + +class PluginNoMatch(Exception): + def __init__(self, *args, **kwargs): + super(PluginNoMatch, self).__init__() + self.args = args + self.kwargs = kwargs + def __str__(self): + return "%s(%s,%s)" % (self.__class__.__name__, + self.args, self.kwargs) + + +class AmbigousPluginDetection(Exception): + def __init__(self, matches, cls, context, *args, **kwargs): + self.matches = matches + self.cls = cls + self.context = context + self.args = args + self.kwargs = kwargs + def __str__(self): + return "%s(%s.%s, %s, %s, %s, %s)" % (self.__class__.__name__, + self.cls.__module__, + self.cls.__name__, + self.matches, + self.context, + self.args, + self.kwargs) + + +# Might be used later when we do class introspection looking for +# abstract methods. +class UNUSED_AbstractMethodsInConcreteClass(Exception): + def __init__(self, cls, methods): + self.cls = cls + self.methods = methods + def __str__(self): + methods = "\n ".join(self.methods) + return "Concrete class %s.%s must implement these methods:\n %s" \ + % (self.cls.__module__, + self.cls.__name__, + methods) + + +class AbstractMethodError(Exception): + def __init__(self, name, module): + self.name = name + self.module = module + def __str__(self): + # FIXME: Class name? + return "Abstract method %s called someplace in %s" \ + % (repr(self.name), repr(self.module)) + + +def abstractmethod(fun): + @functools.wraps(fun) + def f(self, *args, **kwargs): + # fun(self, *args, **kwargs) + raise AbstractMethodError(name=fun.__name__, + module=fun.__module__) + # We might add some introspection tool later, to be run + # in e.g. GenericPluginMeta.__init__(...), which makes sure + # that there are no abstract methods in a non-abstract class. + # f.abstract_method = True + return f + + +class PluginDict(dict): + """Helper for GenericPluginMeta class + + Behaves basically like a standard dict, but will raise an exception + when asked to update an existing value. + """ + + # This is the important difference between PluginDict and dict. + def __setitem__(self, key, value): + if self.has_key(key): + raise DuplicatePluginName() + else: + super(PluginDict, self).__setitem__(key, value) + + +class GenericPluginMeta(type): + def __init__(cls, name, bases, attrs): + logging.debug("META_INIT %s %s %s %s", cls, name, bases, attrs) + if not hasattr(cls, 'plugins'): + # This branch only executes when processing the mount point itself. + # So, since this is a new plugin type, not an implementation, this + # class shouldn't be registered as a plugin. Instead, it sets up a + # list where plugins can be registered later. + cls.plugins = PluginDict() + elif cls.name is not None: + # This must be a plugin implementation, which should be registered. + # Simply appending it to the list is all that's needed to keep + # track of it later. + logging.debug("Registering %s together with %s", cls, cls.plugins) + cls.plugins[cls.name] = cls + else: + # This must be an abstract subclass of plugins. + pass + + +class GenericDetectPlugin(object): + no_match_exception = PluginNoMatch + ambigous_match_exception = AmbigousPluginDetection + + def __init__(self, context): + super(GenericDetectPlugin, self).__init__() + self.context = context + + @classmethod + def validate(cls, obj, *args, **kwargs): + logging.debug("GDval") + return True + + @classmethod + def detect(cls, context, *args, **kwargs): + """Detect stuff""" + logging.debug("DETECT %s", cls) + if len(cls.plugins) < 1: + raise NoPluginsRegistered(cls) + matches = PluginDict() + for key, klass in cls.plugins.iteritems(): + try: + t = klass(context, *args, **kwargs) + logging.debug("KLASS %s unvalidated, %s", klass, + klass.validate) + if klass.validate(t, *args, **kwargs): + logging.debug("KLASS %s validated", klass) + matches[key] = t + except PluginNoMatch, e: + pass + if len(matches) > 1: + raise cls.ambigous_match_exception(matches, + cls, context, + *args, **kwargs) + elif len(matches) < 1: + raise cls.no_match_exception(*args, **kwargs) + return matches[matches.keys()[0]] + + +def selftest(): + + class PluginNoMatchA(PluginNoMatch): + pass + class AmbigousPluginDetectionA(AmbigousPluginDetection): + pass + + + class TestDetectPluginA(GenericDetectPlugin): + __metaclass__ = GenericPluginMeta + no_match_exception = PluginNoMatchA + ambigous_match_exception = AmbigousPluginDetectionA + @classmethod + def validate(cls, obj, *args, **kwargs): + logging.debug("Aval") + return False + + + class TestDetectPluginB(GenericDetectPlugin): + __metaclass__ = GenericPluginMeta + + + class TestDetectPluginC(GenericDetectPlugin): + __metaclass__ = GenericPluginMeta + @classmethod + def validate(cls, obj, *args, **kwargs): + logging.debug("Cval") + return False + + + class TestDetectPluginA1(TestDetectPluginA): + name = "A1" + class TestDetectPluginA2(TestDetectPluginA): + name = "A2" + class TestDetectPluginA3(TestDetectPluginA): + name = "A3" + + class TestDetectPluginB1(TestDetectPluginB): + name = "B1" + class TestDetectPluginB2(TestDetectPluginB): + name = "B2" + class TestDetectPluginB3(TestDetectPluginB): + name = "B3" + + class TestDetectPluginC1(TestDetectPluginC): + name = "C1" + class TestDetectPluginC2(TestDetectPluginC): + name = "C2" + class TestDetectPluginC3(TestDetectPluginC): + name = "C3" + @classmethod + def validate(cls, obj, *args, **kwargs): + logging.debug("C3val") + return True + + ctx = None + + print "GenericPluginMeta", dir(GenericPluginMeta) + print "GenericDetectPlugin", dir(GenericDetectPlugin) + print "TestDetectPluginA", dir(TestDetectPluginA) + print "TestDetectPluginA", dir(TestDetectPluginA) + print "TestDetectPluginB", dir(TestDetectPluginB) + print "TestDetectPluginC", dir(TestDetectPluginC) + + try: + a = TestDetectPluginA.detect(ctx) + except: + logging.error("aaaa", exc_info=True) + + try: + b = TestDetectPluginB.detect(ctx) + except: + logging.error("bbbb", exc_info=True) + + try: + c = TestDetectPluginC.detect(ctx) + except: + logging.error("cccc", exc_info=True) diff --git a/src/nbblib/test-plugins.py b/src/nbblib/test-plugins.py new file mode 100644 index 0000000..8082aec --- /dev/null +++ b/src/nbblib/test-plugins.py @@ -0,0 +1,19 @@ +#!/usr/bin/python +"""Test newplugins module""" + +import logging +import sys + +logging.basicConfig(level = logging.DEBUG, + format = "%(levelname)s: %(message)s", + stream = sys.stderr) +if True: + logging.debug("xxx debug") + logging.info("xxx info") + logging.warning("xxx warn") + logging.error("xxx error") + + +import newplugins +newplugins.selftest() + diff --git a/src/nbblib/vcs.py b/src/nbblib/vcs.py index c21b81e..8830cf3 100644 --- a/src/nbblib/vcs.py +++ b/src/nbblib/vcs.py @@ -4,8 +4,7 @@ import urlparse from nbblib import package from nbblib import progutils - -from nbblib import newplugins as plugins +from nbblib import plugins class AbstractConfig(object): -- cgit