Files
bonobo/bonobo/structs/bags.py

117 lines
2.8 KiB
Python

import itertools
from bonobo.constants import INHERIT_INPUT, LOOPBACK
__all__ = [
'Bag',
'ErrorBag',
]
class Bag:
"""
Bags are simple datastructures that holds arguments and keyword arguments together, that may be applied to a
callable.
Example:
>>> from bonobo import Bag
>>> def myfunc(foo, *, bar):
... print(foo, bar)
...
>>> bag = Bag('foo', bar='baz')
>>> bag.apply(myfunc)
foo baz
A bag can inherit another bag, allowing to override only a few arguments without touching the parent.
Example:
>>> bag2 = Bag(bar='notbaz', _parent=bag)
>>> bag2.apply(myfunc)
foo notbaz
"""
default_flags = ()
def __init__(self, *args, _flags=None, _parent=None, **kwargs):
self._flags = type(self).default_flags + (_flags or ())
self._parent = _parent
self._args = args
self._kwargs = kwargs
@property
def args(self):
if self._parent is None:
return self._args
return (*self._parent.args, *self._args, )
@property
def kwargs(self):
if self._parent is None:
return self._kwargs
return {
**self._parent.kwargs,
**self._kwargs,
}
@property
def flags(self):
return self._flags
def apply(self, func_or_iter, *args, **kwargs):
if callable(func_or_iter):
return func_or_iter(*args, *self.args, **kwargs, **self.kwargs)
if len(args) == 0 and len(kwargs) == 0:
try:
iter(func_or_iter)
def generator():
yield from func_or_iter
return generator()
except TypeError as exc:
raise TypeError('Could not apply bag to {}.'.format(func_or_iter)) from exc
raise TypeError('Could not apply bag to {}.'.format(func_or_iter))
def get(self):
"""
Get a 2 element tuple of this bag's args and kwargs.
:return: tuple
"""
return self.args, self.kwargs
def extend(self, *args, **kwargs):
return type(self)(*args, _parent=self, **kwargs)
def set_parent(self, parent):
self._parent = parent
@classmethod
def inherit(cls, *args, **kwargs):
return cls(*args, _flags=(INHERIT_INPUT, ), **kwargs)
def __eq__(self, other):
return isinstance(other, Bag) and other.args == self.args and other.kwargs == self.kwargs
def __repr__(self):
return '<{} ({})>'.format(
type(self).__name__, ', '.
join(itertools.chain(
map(repr, self.args),
('{}={}'.format(k, repr(v)) for k, v in self.kwargs.items()),
))
)
class LoopbackBag(Bag):
default_flags = (LOOPBACK, )
class ErrorBag(Bag):
pass