Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env python
- import functools
- class Dependent:
- """A class to help manage dependencies within my filters.
- Classes that inherit from it are automatically created using the
- decorator :func:`make_dependent`. No instances of this class are
- usually created. Instead, calling it is equivalent to calling it's
- object.
- """
- _object = None
- _dependencies = []
- def __new__(cls, *args, **kwargs):
- return cls._object(*args, **kwargs)
- def __init__(self, _object=None, _dependencies=None):
- if _dependencies is not None:
- self._dependencies = check_type_strictly(_dependencies, list)
- if _object is not None:
- self._object = _object
- @classmethod
- def resolve_dependencies(cls, resolved=None, seen=None):
- """Calles the function :func:`resolve_dependencies` and returns
- its return value.
- :param resolved: list of :class:`Dependent` who's dependencies have
- alredy been resolved.
- :type resolved: `list` | `None`
- :param seen: list or :class:`Dependent` that already appeared while
- resolving its dependencies. Helps avoid circular
- dependencies.
- :type seen: `list` | `None`
- """
- return resolve_dependencies(cls, resolved, seen)
- @classmethod
- def __repr__(cls):
- if hasattr(cls._object, '__name__'):
- return cls._object.__name__
- else:
- return repr(cls._object)
- @classmethod
- def add_dependency(cls, dependency):
- cls._dependencies.append(dependency)
- @classmethod
- def add_dependencies(cls, *dependencies):
- for dependency in dependencies:
- cls.add_dependency(dependency)
- @classmethod
- def to_function(cls):
- actions, _ = cls.resolve_dependencies()
- def run_functions(*args):
- for a in actions:
- a._object(*args)
- return run_functions
- def resolve_dependencies(dependent, resolved=None, seen=None):
- """Resolve all the dependencies of a Class or Instance of a Class that
- inherited from :class:`Dependent`
- :param resolved: list of :class:`Dependent` who's dependencies have
- alredy been resolved.
- :type resolved: `list` | `None`
- :param seen: list or :class:`Dependent` that already appeared while
- resolving its dependencies. Helps avoid circular
- dependencies.
- :type seen: `list` | `None`
- :returns: a `tuple` of containing the list of resolved and seen
- :class:`Dependent` objects.
- """
- if resolved is None:
- resolved = []
- if seen is None:
- seen = []
- if isinstance(dependent, list):
- for d in dependent:
- resolve_dependencies(d, resolved, seen)
- else:
- if dependent not in resolved:
- seen.append(dependent)
- for dependency in dependent._dependencies:
- if dependency not in resolved:
- if dependency in seen:
- raise Exception('Circular dependency')
- resolve_dependencies(dependency, resolved, seen)
- resolved.append(dependent)
- return resolved, seen
- def make_dependent(*dependencies):
- """A decorator to make a function into a Class that inherits from
- :class:`Dependent`.
- :param *dependencies: What other functions this one is dependent on.
- :type dependencies: :class:`Dependent` sequence
- .. code-block:: python
- @make_dependent()
- def a_func(name):
- print(name)
- @make_dependent(a_func)
- def b_func(name):
- print(name)
- Now `b_func` is dependent on `a_func`. A list of dependent functions can
- then be created doing this:
- .. code-block:: python
- b_func.resolve_dependencies()
- """
- def function_wrapper(func):
- inner_dependencies = dependencies
- class Wrapped(Dependent):
- _object = func
- _dependencies = inner_dependencies
- # Make the wrapped class have the original functions attributed
- for attr in functools.WRAPPER_ASSIGNMENTS:
- setattr(Wrapped, attr, getattr(func, attr))
- doc = getattr(func, '__doc__', '')
- doc = '' if doc is None else doc
- signature = str(inspect.signature(func))
- name = getattr(func, '__name__')
- doc = f'{name}{signature}\n' + doc
- setattr(Wrapped, '__doc__', doc)
- return Wrapped
- return function_wrapper
- def reduce_dependencies(*list_):
- """Tries to resolve all the dependencies passed as parameters.
- :param *list_: The dependencies that sould be resolved
- :type *list: `tuple` of `Dependent`
- :returns: A list of functions, hopefully in the order of their
- depencency.
- """
- return [i._object
- for i in functools.reduce(
- reduce_dependencies_helper,
- [None] + list(list_),
- )[0]]
- def reduce_dependencies_helper(returned_value, dependent):
- """Just a helper function for :func:`reduce_dependencies`.
- :param returned_value: The tuple returned by
- :func:`Dependent.resolve_dependencies`
- :type returned_value: `tuple` of two `list`
- :param dependent:
- """
- if returned_value is None:
- returned_value = ([], [])
- return_value = dependent.resolve_dependencies(*returned_value)
- return return_value
- def check_type_strictly(input, type_):
- if isinstance(input, type_):
- return input
- else:
- raise TypeError('Expected input to be of type {}, was {}.'.format(
- type_,
- type(input),
- ))
Add Comment
Please, Sign In to add comment