dependency.py
111 lines
| 3.2 KiB
| text/x-python
|
PythonLexer
MinRK
|
r3546 | """Dependency utilities""" | ||
from IPython.external.decorator import decorator | ||||
MinRK
|
r3631 | |||
MinRK
|
r3642 | from .asyncresult import AsyncResult | ||
from .error import UnmetDependency | ||||
MinRK
|
r3546 | |||
MinRK
|
r3571 | |||
MinRK
|
r3546 | class depend(object): | ||
"""Dependency decorator, for use with tasks.""" | ||||
def __init__(self, f, *args, **kwargs): | ||||
self.f = f | ||||
self.args = args | ||||
self.kwargs = kwargs | ||||
def __call__(self, f): | ||||
return dependent(f, self.f, *self.args, **self.kwargs) | ||||
class dependent(object): | ||||
"""A function that depends on another function. | ||||
This is an object to prevent the closure used | ||||
in traditional decorators, which are not picklable. | ||||
""" | ||||
def __init__(self, f, df, *dargs, **dkwargs): | ||||
self.f = f | ||||
MinRK
|
r3607 | self.func_name = getattr(f, '__name__', 'f') | ||
MinRK
|
r3546 | self.df = df | ||
self.dargs = dargs | ||||
self.dkwargs = dkwargs | ||||
def __call__(self, *args, **kwargs): | ||||
if self.df(*self.dargs, **self.dkwargs) is False: | ||||
raise UnmetDependency() | ||||
return self.f(*args, **kwargs) | ||||
MinRK
|
r3607 | |||
@property | ||||
def __name__(self): | ||||
return self.func_name | ||||
MinRK
|
r3546 | |||
MinRK
|
r3548 | def _require(*names): | ||
for name in names: | ||||
try: | ||||
__import__(name) | ||||
except ImportError: | ||||
return False | ||||
return True | ||||
MinRK
|
r3546 | |||
MinRK
|
r3548 | def require(*names): | ||
return depend(_require, *names) | ||||
class Dependency(set): | ||||
MinRK
|
r3611 | """An object for representing a set of msg_id dependencies. | ||
MinRK
|
r3548 | |||
Subclassed from set().""" | ||||
MinRK
|
r3624 | all=True | ||
MinRK
|
r3607 | success_only=True | ||
MinRK
|
r3548 | |||
MinRK
|
r3624 | def __init__(self, dependencies=[], all=True, success_only=True): | ||
MinRK
|
r3548 | if isinstance(dependencies, dict): | ||
# load from dict | ||||
MinRK
|
r3624 | all = dependencies.get('all', True) | ||
MinRK
|
r3607 | success_only = dependencies.get('success_only', success_only) | ||
dependencies = dependencies.get('dependencies', []) | ||||
MinRK
|
r3624 | ids = [] | ||
if isinstance(dependencies, AsyncResult): | ||||
ids.extend(AsyncResult.msg_ids) | ||||
else: | ||||
for d in dependencies: | ||||
if isinstance(d, basestring): | ||||
ids.append(d) | ||||
elif isinstance(d, AsyncResult): | ||||
ids.extend(d.msg_ids) | ||||
else: | ||||
raise TypeError("invalid dependency type: %r"%type(d)) | ||||
set.__init__(self, ids) | ||||
self.all = all | ||||
MinRK
|
r3607 | self.success_only=success_only | ||
MinRK
|
r3548 | |||
MinRK
|
r3607 | def check(self, completed, failed=None): | ||
if failed is not None and not self.success_only: | ||||
completed = completed.union(failed) | ||||
MinRK
|
r3548 | if len(self) == 0: | ||
return True | ||||
MinRK
|
r3624 | if self.all: | ||
MinRK
|
r3565 | return self.issubset(completed) | ||
else: | ||||
MinRK
|
r3624 | return not self.isdisjoint(completed) | ||
MinRK
|
r3548 | |||
MinRK
|
r3607 | def unreachable(self, failed): | ||
if len(self) == 0 or len(failed) == 0 or not self.success_only: | ||||
return False | ||||
MinRK
|
r3624 | # print self, self.success_only, self.all, failed | ||
if self.all: | ||||
MinRK
|
r3607 | return not self.isdisjoint(failed) | ||
else: | ||||
MinRK
|
r3624 | return self.issubset(failed) | ||
MinRK
|
r3607 | |||
MinRK
|
r3548 | def as_dict(self): | ||
"""Represent this dependency as a dict. For json compatibility.""" | ||||
return dict( | ||||
dependencies=list(self), | ||||
MinRK
|
r3624 | all=self.all, | ||
MinRK
|
r3607 | success_only=self.success_only, | ||
MinRK
|
r3548 | ) | ||
MinRK
|
r3624 | __all__ = ['depend', 'require', 'dependent', 'Dependency'] | ||
MinRK
|
r3546 | |||