summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorHans Ulrich Niedermann <hun@n-dimensional.de>2008-06-26 00:52:07 +0200
committerHans Ulrich Niedermann <hun@n-dimensional.de>2008-07-15 12:28:53 +0200
commitc50d6f6dee9a95266c795cd1e7d0bf82863248d8 (patch)
tree5fd15d803c33c4473ca3bd21b1021caf2daa94e7 /src
parent6eeb92ef8674b1d71bceadf88c0645bccd57f20b (diff)
downloadnbb-c50d6f6dee9a95266c795cd1e7d0bf82863248d8.tar.gz
nbb-c50d6f6dee9a95266c795cd1e7d0bf82863248d8.tar.xz
nbb-c50d6f6dee9a95266c795cd1e7d0bf82863248d8.zip
Add newplugins.py
Diffstat (limited to 'src')
-rw-r--r--src/nbblib/newplugin-test.py19
-rw-r--r--src/nbblib/newplugins.py242
2 files changed, 261 insertions, 0 deletions
diff --git a/src/nbblib/newplugin-test.py b/src/nbblib/newplugin-test.py
new file mode 100644
index 0000000..8082aec
--- /dev/null
+++ b/src/nbblib/newplugin-test.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/newplugins.py b/src/nbblib/newplugins.py
new file mode 100644
index 0000000..06905fe
--- /dev/null
+++ b/src/nbblib/newplugins.py
@@ -0,0 +1,242 @@
+"""Usage of newplugins module:
+
+np = __import__(newplugins)
+
+class NonDetectPluginType(object):
+ __metaclass__ = np.GenericPluginMeta
+
+class PluginA(NonDetectPluginType):
+ name = "PA"
+class PluginB(NonDetectPluginType):
+ name = "PB"
+
+class MyPluginType(np.GenericDetectPlugin):
+ __metaclass__ = np.GenericPluginMeta
+ [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 np.PluginNoMatch()
+class MyPluginB(MyPluginType):
+ name = "MB"
+ def __init__(self, context):
+ super(MyPluginB, self).__init__(self, context)
+ if not other_detection_successful:
+ raise np.PluginNoMatch()
+
+"""
+
+
+import sys
+import logging
+
+
+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)
+
+
+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)
+
+
+########################################################################
+# Generic plugin system
+########################################################################
+# Plugin architecture (metaclass tricks) by Marty Alchin from
+# http://gulopine.gamemusic.org/2008/jan/10/simple-plugin-framework/
+# Slightly modified go store plugins as dict.
+########################################################################
+
+
+class GenericPluginMeta(type):
+ def __init__(cls, name, bases, attrs):
+ logging.debug("%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("%s %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)