testing bags
This commit is contained in:
@ -20,6 +20,7 @@ enable_features = {
|
||||
}
|
||||
|
||||
install_requires = [
|
||||
'blessings >=1.6,<1.7',
|
||||
'psutil >=5.0,<5.1',
|
||||
]
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
from .bags import Bag, Inherit
|
||||
from .bags import Bag
|
||||
from .graphs import Graph
|
||||
from .services import inject, service
|
||||
from .strategies.executor import ThreadPoolExecutorStrategy, ProcessPoolExecutorStrategy
|
||||
@ -7,7 +7,6 @@ from .strategies.naive import NaiveStrategy
|
||||
__all__ = [
|
||||
'Bag',
|
||||
'Graph',
|
||||
'Inherit',
|
||||
'NaiveStrategy',
|
||||
'ProcessPoolExecutorStrategy',
|
||||
'ThreadPoolExecutorStrategy',
|
||||
|
||||
@ -1,19 +1,58 @@
|
||||
from operator import attrgetter
|
||||
|
||||
import itertools
|
||||
|
||||
from bonobo.util.tokens import Token
|
||||
|
||||
_get_args = attrgetter('args')
|
||||
|
||||
InheritInputFlag = Token('InheritInputFlag')
|
||||
|
||||
|
||||
class Bag:
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
||||
def __init__(self, *args, _flags=None, _parent=None, **kwargs):
|
||||
self._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, f, *args, **kwargs):
|
||||
return f(*args, *self.args, **kwargs, **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=(InheritInputFlag, ), **kwargs)
|
||||
|
||||
def __repr__(self):
|
||||
return '<{} *{} **{}>'.format(type(self).__name__, self.args, self.kwargs)
|
||||
|
||||
|
||||
class Inherit(Bag):
|
||||
def override(self, input):
|
||||
self.args = input.args + self.args
|
||||
kwargs = dict(input.kwargs)
|
||||
kwargs.update(self.kwargs)
|
||||
self.kwargs = kwargs
|
||||
return self
|
||||
return '<{} ({})>'.format(
|
||||
type(self).__name__, ', '.join(
|
||||
itertools.chain(
|
||||
map(repr, self.args),
|
||||
('{}={}'.format(k, repr(v)) for k, v in self.kwargs.items()), )))
|
||||
|
||||
@ -3,7 +3,7 @@ from functools import partial
|
||||
from queue import Empty
|
||||
from time import sleep
|
||||
|
||||
from bonobo.core.bags import Bag
|
||||
from bonobo.core.bags import Bag, InheritInputFlag
|
||||
from bonobo.core.errors import InactiveReadableError
|
||||
from bonobo.core.inputs import Input
|
||||
from bonobo.core.stats import WithStatistics
|
||||
@ -139,7 +139,6 @@ class ComponentExecutionContext(WithStatistics):
|
||||
|
||||
def _call(self, bag_or_arg):
|
||||
# todo add timer
|
||||
bag = bag_or_arg if hasattr(bag_or_arg, 'apply') else Bag(bag_or_arg)
|
||||
if getattr(self.component, '_with_context', False):
|
||||
return bag.apply(self.component, self)
|
||||
return bag.apply(self.component)
|
||||
@ -149,17 +148,27 @@ class ComponentExecutionContext(WithStatistics):
|
||||
"""Runs a transformation callable with given args/kwargs and flush the result into the right
|
||||
output channel."""
|
||||
|
||||
input_row = self.get()
|
||||
input_bag = self.get()
|
||||
|
||||
def _resolve(result):
|
||||
nonlocal input_row
|
||||
if result is NotModified:
|
||||
return input_row
|
||||
if hasattr(result, 'override'):
|
||||
return result.override(input_row)
|
||||
return result
|
||||
def _resolve(output):
|
||||
nonlocal input_bag
|
||||
|
||||
results = self._call(input_row)
|
||||
# NotModified means to send the input unmodified to output.
|
||||
if output is NotModified:
|
||||
return input_bag
|
||||
|
||||
# If it does not look like a bag, let's create one for easier manipulation
|
||||
if hasattr(output, 'apply'):
|
||||
# Already a bag? Check if we need to set parent.
|
||||
if InheritInputFlag in output.flags:
|
||||
output.set_parent(input_bag)
|
||||
else:
|
||||
# Not a bag? Let's encapsulate it.
|
||||
output = Bag(result)
|
||||
|
||||
return output
|
||||
|
||||
results = self._call(input_bag)
|
||||
|
||||
# self._exec_time += timer.duration
|
||||
# Put data onto output channels
|
||||
|
||||
5
setup.py
5
setup.py
@ -21,7 +21,10 @@ setup(
|
||||
name='bonobo',
|
||||
description='Bonobo',
|
||||
license='Apache License, Version 2.0',
|
||||
install_requires=['psutil >=5.0,<5.1', ],
|
||||
install_requires=[
|
||||
'psutil >=5.0,<5.1',
|
||||
'blessings >=1.6,<1.7',
|
||||
],
|
||||
version=version,
|
||||
long_description=read('README.rst'),
|
||||
classifiers=read('classifiers.txt', tolines),
|
||||
|
||||
75
tests/core/test_bags.py
Normal file
75
tests/core/test_bags.py
Normal file
@ -0,0 +1,75 @@
|
||||
from mock import Mock
|
||||
|
||||
from bonobo import Bag
|
||||
from bonobo.core.bags import InheritInputFlag
|
||||
|
||||
args = (
|
||||
'foo',
|
||||
'bar', )
|
||||
kwargs = dict(acme='corp')
|
||||
|
||||
|
||||
def test_basic():
|
||||
my_callable1 = Mock()
|
||||
my_callable2 = Mock()
|
||||
bag = Bag(*args, **kwargs)
|
||||
|
||||
assert not my_callable1.called
|
||||
result1 = bag.apply(my_callable1)
|
||||
assert my_callable1.called and result1 is my_callable1.return_value
|
||||
|
||||
assert not my_callable2.called
|
||||
result2 = bag.apply(my_callable2)
|
||||
assert my_callable2.called and result2 is my_callable2.return_value
|
||||
|
||||
assert result1 is not result2
|
||||
|
||||
my_callable1.assert_called_once_with(*args, **kwargs)
|
||||
my_callable2.assert_called_once_with(*args, **kwargs)
|
||||
|
||||
|
||||
def test_inherit():
|
||||
bag = Bag('a', a=1)
|
||||
bag2 = Bag.inherit('b', b=2, _parent=bag)
|
||||
bag3 = bag.extend('c', c=3)
|
||||
bag4 = Bag('d', d=4)
|
||||
|
||||
assert bag.args == ('a', )
|
||||
assert bag.kwargs == {'a': 1}
|
||||
assert bag.flags is ()
|
||||
|
||||
assert bag2.args == (
|
||||
'a',
|
||||
'b', )
|
||||
assert bag2.kwargs == {'a': 1, 'b': 2}
|
||||
assert InheritInputFlag in bag2.flags
|
||||
|
||||
assert bag3.args == (
|
||||
'a',
|
||||
'c', )
|
||||
assert bag3.kwargs == {'a': 1, 'c': 3}
|
||||
assert bag3.flags is ()
|
||||
|
||||
assert bag4.args == ('d', )
|
||||
assert bag4.kwargs == {'d': 4}
|
||||
assert bag4.flags is ()
|
||||
|
||||
bag4.set_parent(bag)
|
||||
assert bag4.args == (
|
||||
'a',
|
||||
'd', )
|
||||
assert bag4.kwargs == {'a': 1, 'd': 4}
|
||||
assert bag4.flags is ()
|
||||
|
||||
bag4.set_parent(bag3)
|
||||
assert bag4.args == (
|
||||
'a',
|
||||
'c',
|
||||
'd', )
|
||||
assert bag4.kwargs == {'a': 1, 'c': 3, 'd': 4}
|
||||
assert bag4.flags is ()
|
||||
|
||||
|
||||
def test_repr():
|
||||
bag = Bag('a', a=1)
|
||||
assert repr(bag) == "<Bag ('a', a=1)>"
|
||||
0
tests/core/test_contexts.py
Normal file
0
tests/core/test_contexts.py
Normal file
Reference in New Issue
Block a user