testing bags

This commit is contained in:
Romain Dorgueil
2016-12-25 14:25:10 +01:00
parent a3adb044bf
commit 7b34b43b08
9 changed files with 153 additions and 27 deletions

View File

@ -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',
] ]

View File

@ -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',

View File

@ -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

View File

@ -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

View File

@ -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
View 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)>"

View File