summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Ulrich Niedermann <hun@n-dimensional.de>2008-06-30 22:44:37 +0200
committerHans Ulrich Niedermann <hun@n-dimensional.de>2008-07-15 12:28:55 +0200
commit3b9f0935346fd25700c3c2e82116d1665bdb1035 (patch)
tree33e8a3262e773fd260edf5e0d0bd7745d2433034
parent70708c53812eda6cf6021fb3818a50fc81beac67 (diff)
downloadnbb-3b9f0935346fd25700c3c2e82116d1665bdb1035.tar.gz
nbb-3b9f0935346fd25700c3c2e82116d1665bdb1035.tar.xz
nbb-3b9f0935346fd25700c3c2e82116d1665bdb1035.zip
Add docstrings to nbblib.plugins
-rw-r--r--src/nbblib/plugins.py81
1 files changed, 80 insertions, 1 deletions
diff --git a/src/nbblib/plugins.py b/src/nbblib/plugins.py
index 55251ba..964f5cc 100644
--- a/src/nbblib/plugins.py
+++ b/src/nbblib/plugins.py
@@ -66,6 +66,7 @@ import inspect
class NoPluginsRegistered(Exception):
+ """Raised when looking for plugins but none are registered"""
def __init__(self, cls):
super(NoPluginsRegistered, self).__init__()
self.cls = cls
@@ -74,10 +75,12 @@ class NoPluginsRegistered(Exception):
class DuplicatePluginName(Exception):
+ """Raised when another plugin tries to register the same name"""
pass
class PluginNoMatch(Exception):
+ """Raised when no registered plugin matches the given args"""
def __init__(self, *args, **kwargs):
super(PluginNoMatch, self).__init__()
self.args = args
@@ -88,6 +91,7 @@ class PluginNoMatch(Exception):
class AmbigousPluginDetection(Exception):
+ """Raised when more than one registered plugin matches the given args"""
def __init__(self, matches, cls, context, *args, **kwargs):
self.matches = matches
self.cls = cls
@@ -105,6 +109,11 @@ class AmbigousPluginDetection(Exception):
class AbstractMethodsInConcreteClass(Exception):
+ """Raised when an abstract method is detected in a non-abstract class
+
+ The method has been marked @abstractmethod in an ancestor, and must be
+ implemented if this class is not abstract itself.
+ """
def __init__(self, cls, methods):
self.cls = cls
self.methods = methods
@@ -117,6 +126,7 @@ class AbstractMethodsInConcreteClass(Exception):
class AbstractMethodError(Exception):
+ """Raised when an abstract method is called"""
def __init__(self, name, module):
self.name = name
self.module = module
@@ -127,6 +137,18 @@ class AbstractMethodError(Exception):
def abstractmethod(fun):
+ """The decorator for abstract methods in plugins
+
+ This decorator has two effects:
+ * If the abstract method should ever be called, it will raise
+ an AbstractMethodError.
+ * If the class the method is defined has GenericPluginMeta as
+ __metaclass__, __name__ is not None (i.e. it is a non-abstract
+ Plugin class), and the method has not been overwritten with a
+ method without @abstractmethod, there will be a
+ AbstractMethodsInConcreteClass at module loading time, i.e.
+ before the actual program is run!
+ """
@functools.wraps(fun)
def f(self, *args, **kwargs):
# fun(self, *args, **kwargs)
@@ -152,6 +174,25 @@ class PluginDict(dict):
class GenericPluginMeta(type):
+ """Simple plugin metaclass with named plugins
+
+ Simple usage:
+ >>> class Plugin(object):
+ ... pass
+ ...
+ >>> class PluginA(Plugin):
+ ... __name__ = 'a'
+ ...
+ >>> class PluginA(Plugin):
+ ... __name__ = 'b'
+ ...
+ >>> print Plugin.plugins.keys()
+ ['a', 'b']
+
+ Advanced features:
+ You can add abstract subclasses of Plugin by giving them a __name__ = None,
+ define an @abstractmethod method in that abstract subclass, and much more.
+ """
def __init__(cls, name, bases, attrs):
logging.debug("META_INIT %s %s %s %s", cls, name, bases, attrs)
if not hasattr(cls, 'plugins'):
@@ -178,7 +219,28 @@ class GenericPluginMeta(type):
class GenericDetectPlugin(object):
+ """Advanced plugin class where the plugins detect whether they apply
+
+ Use it by defining a subclass with the proper properties and methods overwritten.
+
+ Example:
+ >>> class FooDetectPlugin(GenericDetectPlugin):
+ ... @classmethod
+ ... def validate(cls, obj, foo, bar):
+ ... return cls.__name__ == 'A'
+ ...
+ >>> class FooDetectPluginA(FooDetectPlugin):
+ ... __name__ = 'A'
+ ...
+ >>> class FooDetectPluginB(FooDetectPlugin):
+ ... __name__ = 'B'
+ ...
+ >>> FooDetectPlugin.detect('FOO', 'BAR')
+ """
+
+ """You may override this with a more plugin specific subclass of PluginNoMatch"""
no_match_exception = PluginNoMatch
+ """You may override this with a more plugin specific subclass of AmbigousPluginDetection"""
ambigous_match_exception = AmbigousPluginDetection
def __init__(self, context):
@@ -187,12 +249,29 @@ class GenericDetectPlugin(object):
@classmethod
def validate(cls, obj, *args, **kwargs):
+ """Override this in subclass to validate the given args
+
+ @param cls subclass of GenericDetectPlugin and type of obj
+ @param obj instance of cls which is to be validated
+ @param args the same args as given to detect()
+ @param kwargs the same kwargs as given to detect()
+ """
logging.debug("GDval")
return True
@classmethod
def detect(cls, context, *args, **kwargs):
- """Detect stuff"""
+ """Detect which plugin matches the given arguments
+
+ It might make sense to document the exact calling conventions in
+ derived classes:
+
+ >>> class FooDetectPlugin(GenericDetectPlugin):
+ ... @classmethod
+ ... def detect(cls, context, foo, bar):
+ ... "detect plugin from foo and bar values yadda yadda"
+ ... return super(FooDetectPlugin, cls).detect(cls, context, foo, bar)
+ """
logging.debug("DETECT %s", cls)
if len(cls.plugins) < 1:
raise NoPluginsRegistered(cls)