from .utils import listify
[docs]class Runnable(object):
[docs] def run(self):
"""
**Must** be implemented by inheriting classes.
"""
raise NotImplementedError
def __call__(self):
self.run()
[docs]class WrapperRun(object):
"""docstring for WrapperRun"""
[docs] def w_run(self):
self._run()
[docs] def run(self):
self.w_run()
[docs]class Constructible(object):
"""docstring for Constructible"""
[docs] class Constructor(object):
def __init__(self, obj):
super(Constructible.Constructor, self).__init__()
self._obj = obj
def __init__(self):
super(Constructible, self).__init__()
self.__constructor_func = None
self.__constructed = False
[docs] def constructor_func(self, constructor_func):
self.__constructor_func = constructor_func
[docs] def constructed(self):
return self.__constructed
[docs] def construct(self):
if self.__constructed:
return
cons = self.Constructor(self)
self.__constructor_func(cons)
self.__constructed = True
[docs] def w_run(self):
self.construct()
super(Constructible, self).w_run()
[docs]class Artefactor(object):
"""docstring for Artefactor
Todo:
* Policy on artefact() calls after artefact propagation
"""
[docs] class Constructor(object):
[docs] def artefact(self, **kwargs):
self._obj._artefact_funcs.update(kwargs)
def __init__(self):
super(Artefactor, self).__init__()
self._artefact_funcs = dict()
self.artefacts = dict()
[docs] def artefact(self, **kwargs):
self._artefact_funcs.update(kwargs)
def _propagate_artefacts(self):
for key, val in self._artefact_funcs.items():
self.artefacts[key] = val()
[docs] def w_run(self):
super(Artefactor, self).w_run()
self._propagate_artefacts()
[docs]class Registerable(object):
def __init__(self):
super(Registerable, self).__init__()
self.__masters = list()
[docs] def registered_with(self, master):
self.__masters.append(master)
def _resolve(self, key):
for m in self.__masters:
try:
return m[key]
except KeyError:
pass
raise KeyError("Could not resolve key '{}'".format(repr(key)))
[docs]class Dependency(Registerable):
"""docstring for Dependency
Dependency has two different Constructor variants:
``SetUpConstructor`` allows adding dependencies to the object, while
``ResolveConstructor`` makes resolved dependencies available with its
`dependencies` attribute.
Todo:
* Policy on depends() calls after dependency fulfillment
* 2 Constructors: a) Dependencies resolved and available
"""
[docs] class SetUpConstructor(object):
[docs] def depends(self, *args):
self._obj.depends(*args)
[docs] class ResolveConstructor(object):
@property
def dependencies(self):
return self._obj.dependencies
class __Resolver(object):
def __init__(self, parent, resolvable):
super(Dependency._Dependency__Resolver, self).__init__()
self.__parent = parent
self.__resolvable = resolvable
def __getitem__(self, key):
item = self.__parent._resolve(key)
if item in self.__resolvable:
return item
else:
raise KeyError("Could not resolve key '{}'".format(repr(key)))
def __init__(self):
super(Dependency, self).__init__()
self.__fulfilled = False
self.__depends = list()
self.dependencies = None
[docs] def depends(self, *args):
self.__depends.extend(listify(args))
[docs] def fulfilled(self):
return self.__fulfilled
def _mark_fulfilled(self):
self.__fulfilled = True
def _fulfill_dependencies(self):
resolvable = []
for decl in self.__depends:
try:
dependency = self._resolve(decl)
except KeyError:
raise KeyError(
"Could not resolve dependency declaration '{}'"
.format(repr(decl))
)
resolvable.append(dependency)
if not dependency.fulfilled():
dependency.fulfill()
self.dependencies = self.__Resolver(self, resolvable)
[docs] def fulfill(self):
"""Fulfills this dependency.
**May** be implemented by inheriting classes, but defaults to calling
`self.run()`. In this case however, self.run() has to ensure
`_fulfill_dependencies()` is run.
Should the object only be run once, the following can be inserted at
the beginning of this method's implementation (or `self.run()`)::
if self.fulfilled():
return
"""
self.run()
[docs] def w_run(self):
if self.fulfilled():
return
self._fulfill_dependencies()
super(Dependency, self).w_run()
self._mark_fulfilled()
[docs]class Master(object):
def __init__(self):
self._registry = dict()
self._name_registry = dict()
self._func_name_registry = dict()
self._secondaries = dict()
[docs] def register(self, obj, func, secondary=None):
secondary = listify(secondary, none_empty=True)
self._registry[func] = obj
self._name_registry[func.__module__ + "." + func.__name__] = obj
self._func_name_registry[func.__name__] = obj
for s in secondary:
self._secondaries[s] = obj
try:
obj.registered_with(self)
except AttributeError:
pass
def __getitem__(self, key):
if isinstance(key, str):
try:
return self._name_registry[key]
except KeyError:
pass
try:
return self._func_name_registry[key]
except KeyError:
pass
else:
try:
return self._registry[key]
except KeyError:
pass
return self._secondaries[key]
master = Master()