testing bags
This commit is contained in:
@ -20,6 +20,7 @@ enable_features = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
install_requires = [
|
install_requires = [
|
||||||
|
'blessings >=1.6,<1.7',
|
||||||
'psutil >=5.0,<5.1',
|
'psutil >=5.0,<5.1',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
from .bags import Bag, Inherit
|
from .bags import Bag
|
||||||
from .graphs import Graph
|
from .graphs import Graph
|
||||||
from .services import inject, service
|
from .services import inject, service
|
||||||
from .strategies.executor import ThreadPoolExecutorStrategy, ProcessPoolExecutorStrategy
|
from .strategies.executor import ThreadPoolExecutorStrategy, ProcessPoolExecutorStrategy
|
||||||
@ -7,7 +7,6 @@ from .strategies.naive import NaiveStrategy
|
|||||||
__all__ = [
|
__all__ = [
|
||||||
'Bag',
|
'Bag',
|
||||||
'Graph',
|
'Graph',
|
||||||
'Inherit',
|
|
||||||
'NaiveStrategy',
|
'NaiveStrategy',
|
||||||
'ProcessPoolExecutorStrategy',
|
'ProcessPoolExecutorStrategy',
|
||||||
'ThreadPoolExecutorStrategy',
|
'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:
|
class Bag:
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, _flags=None, _parent=None, **kwargs):
|
||||||
self.args = args
|
self._flags = _flags or ()
|
||||||
self.kwargs = kwargs
|
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):
|
def apply(self, f, *args, **kwargs):
|
||||||
return f(*args, *self.args, **kwargs, **self.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):
|
def __repr__(self):
|
||||||
return '<{} *{} **{}>'.format(type(self).__name__, self.args, self.kwargs)
|
return '<{} ({})>'.format(
|
||||||
|
type(self).__name__, ', '.join(
|
||||||
|
itertools.chain(
|
||||||
class Inherit(Bag):
|
map(repr, self.args),
|
||||||
def override(self, input):
|
('{}={}'.format(k, repr(v)) for k, v in self.kwargs.items()), )))
|
||||||
self.args = input.args + self.args
|
|
||||||
kwargs = dict(input.kwargs)
|
|
||||||
kwargs.update(self.kwargs)
|
|
||||||
self.kwargs = kwargs
|
|
||||||
return self
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@ from functools import partial
|
|||||||
from queue import Empty
|
from queue import Empty
|
||||||
from time import sleep
|
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.errors import InactiveReadableError
|
||||||
from bonobo.core.inputs import Input
|
from bonobo.core.inputs import Input
|
||||||
from bonobo.core.stats import WithStatistics
|
from bonobo.core.stats import WithStatistics
|
||||||
@ -139,7 +139,6 @@ class ComponentExecutionContext(WithStatistics):
|
|||||||
|
|
||||||
def _call(self, bag_or_arg):
|
def _call(self, bag_or_arg):
|
||||||
# todo add timer
|
# 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):
|
if getattr(self.component, '_with_context', False):
|
||||||
return bag.apply(self.component, self)
|
return bag.apply(self.component, self)
|
||||||
return bag.apply(self.component)
|
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
|
"""Runs a transformation callable with given args/kwargs and flush the result into the right
|
||||||
output channel."""
|
output channel."""
|
||||||
|
|
||||||
input_row = self.get()
|
input_bag = self.get()
|
||||||
|
|
||||||
def _resolve(result):
|
def _resolve(output):
|
||||||
nonlocal input_row
|
nonlocal input_bag
|
||||||
if result is NotModified:
|
|
||||||
return input_row
|
|
||||||
if hasattr(result, 'override'):
|
|
||||||
return result.override(input_row)
|
|
||||||
return result
|
|
||||||
|
|
||||||
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
|
# self._exec_time += timer.duration
|
||||||
# Put data onto output channels
|
# Put data onto output channels
|
||||||
|
|||||||
5
setup.py
5
setup.py
@ -21,7 +21,10 @@ setup(
|
|||||||
name='bonobo',
|
name='bonobo',
|
||||||
description='Bonobo',
|
description='Bonobo',
|
||||||
license='Apache License, Version 2.0',
|
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,
|
version=version,
|
||||||
long_description=read('README.rst'),
|
long_description=read('README.rst'),
|
||||||
classifiers=read('classifiers.txt', tolines),
|
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