feat, wip: refactoring and simplification of how casts are made.

This commit is contained in:
Romain Dorgueil
2018-07-29 11:59:47 +01:00
parent f5ebe1b1e7
commit 980a76399b
17 changed files with 251 additions and 65 deletions

View File

@ -0,0 +1,62 @@
from collections import namedtuple
import bonobo
from bonobo.config import use_raw_input
from bonobo.execution.contexts import GraphExecutionContext
from bonobo.util.bags import BagType
Extracted = namedtuple('Extracted', ['id', 'name', 'value'])
ExtractedBT = BagType('ExtractedBT', ['id', 'name', 'value'])
def extract_nt():
yield Extracted(id=1, name='Guido', value='.py')
yield Extracted(id=2, name='Larry', value='.pl')
yield Extracted(id=3, name='Dennis', value='.c')
yield Extracted(id=4, name='Yukihiro', value='.rb')
def extract_bt():
yield ExtractedBT(id=1, name='Guido', value='.py')
yield ExtractedBT(id=2, name='Larry', value='.pl')
yield ExtractedBT(id=3, name='Dennis', value='.c')
yield ExtractedBT(id=4, name='Yukihiro', value='.rb')
def transform_using_args(id, name, value):
yield Extracted(id=id * 2, name=name, value=name.lower() + value)
@use_raw_input
def transform_nt(row):
yield row._replace(name=row.name.upper())
def StoreInList(buffer: list):
def store_in_list(*args, buffer=buffer):
buffer.append(args)
return store_in_list
def test_execution():
graph = bonobo.Graph()
result_args = []
result_nt = []
result_bt = []
graph.add_chain(extract_nt, transform_using_args, StoreInList(result_args))
graph.add_chain(transform_nt, StoreInList(result_nt), _input=extract_nt)
graph.add_chain(extract_bt, transform_using_args, StoreInList(result_bt))
with GraphExecutionContext(graph) as context:
context.run_until_complete()
assert result_args == [(2, 'Guido', 'guido.py'), (4, 'Larry', 'larry.pl'), (6, 'Dennis', 'dennis.c'),
(8, 'Yukihiro', 'yukihiro.rb')]
assert result_nt == [(1, 'GUIDO', '.py'), (2, 'LARRY', '.pl'), (3, 'DENNIS', '.c'), (4, 'YUKIHIRO', '.rb')]
assert result_bt == [(2, 'Guido', 'guido.py'), (4, 'Larry', 'larry.pl'), (6, 'Dennis', 'dennis.c'),
(8, 'Yukihiro', 'yukihiro.rb')]

View File

@ -3,9 +3,10 @@ from unittest.mock import MagicMock
import pytest
from bonobo import Graph
from bonobo.constants import EMPTY, NOT_MODIFIED, INHERIT
from bonobo.constants import EMPTY
from bonobo.execution.contexts.node import NodeExecutionContext, split_token
from bonobo.execution.strategies import NaiveStrategy
from bonobo.util.envelopes import F_NOT_MODIFIED, F_INHERIT
from bonobo.util.testing import BufferingNodeExecutionContext, BufferingGraphExecutionContext
@ -227,32 +228,36 @@ def test_node_lifecycle_with_kill():
def test_split_token():
assert split_token(('foo', 'bar')) == (set(), ('foo', 'bar'))
assert split_token(()) == (set(), ())
assert split_token('') == (set(), ('', ))
with pytest.deprecated_call():
assert split_token(('foo', 'bar')) == (set(), ('foo', 'bar'))
assert split_token(()) == (set(), ())
assert split_token('') == (set(), ('', ))
def test_split_token_duplicate():
with pytest.raises(ValueError):
split_token((NOT_MODIFIED, NOT_MODIFIED))
with pytest.raises(ValueError):
split_token((INHERIT, INHERIT))
with pytest.raises(ValueError):
split_token((INHERIT, NOT_MODIFIED, INHERIT))
with pytest.deprecated_call():
with pytest.raises(ValueError):
split_token((F_NOT_MODIFIED, F_NOT_MODIFIED))
with pytest.raises(ValueError):
split_token((F_INHERIT, F_INHERIT))
with pytest.raises(ValueError):
split_token((F_INHERIT, F_NOT_MODIFIED, F_INHERIT))
def test_split_token_not_modified():
with pytest.raises(ValueError):
split_token((NOT_MODIFIED, 'foo', 'bar'))
with pytest.raises(ValueError):
split_token((NOT_MODIFIED, INHERIT))
with pytest.raises(ValueError):
split_token((INHERIT, NOT_MODIFIED))
assert split_token(NOT_MODIFIED) == ({NOT_MODIFIED}, ())
assert split_token((NOT_MODIFIED, )) == ({NOT_MODIFIED}, ())
with pytest.deprecated_call():
with pytest.raises(ValueError):
split_token((F_NOT_MODIFIED, 'foo', 'bar'))
with pytest.raises(ValueError):
split_token((F_NOT_MODIFIED, F_INHERIT))
with pytest.raises(ValueError):
split_token((F_INHERIT, F_NOT_MODIFIED))
assert split_token(F_NOT_MODIFIED) == ({F_NOT_MODIFIED}, ())
assert split_token((F_NOT_MODIFIED, )) == ({F_NOT_MODIFIED}, ())
def test_split_token_inherit():
assert split_token(INHERIT) == ({INHERIT}, ())
assert split_token((INHERIT, )) == ({INHERIT}, ())
assert split_token((INHERIT, 'foo', 'bar')) == ({INHERIT}, ('foo', 'bar'))
with pytest.deprecated_call():
assert split_token(F_INHERIT) == ({F_INHERIT}, ())
assert split_token((F_INHERIT, )) == ({F_INHERIT}, ())
assert split_token((F_INHERIT, 'foo', 'bar')) == ({F_INHERIT}, ('foo', 'bar'))

View File

@ -1,4 +1,4 @@
from bonobo.constants import INHERIT
from bonobo.util.envelopes import AppendingEnvelope
from bonobo.util.testing import BufferingNodeExecutionContext
messages = [
@ -8,7 +8,7 @@ messages = [
def append(*args):
return INHERIT, '!'
return AppendingEnvelope('!')
def test_inherit():

View File

@ -15,4 +15,6 @@ def test_not_modified():
with BufferingNodeExecutionContext(useless) as context:
context.write_sync(*input_messages)
assert context.get_buffer() == input_messages
result = context.get_buffer()
print(result)
assert result == input_messages

65
tests/nodes/test_casts.py Normal file
View File

@ -0,0 +1,65 @@
from collections import namedtuple
from typing import Callable
import pytest
from bonobo.constants import EMPTY
from bonobo.util.bags import BagType
from bonobo.util.envelopes import Envelope
from bonobo.util.testing import BufferingNodeExecutionContext
MyTuple = namedtuple('MyTuple', ['a', 'b', 'c'])
MyBag = BagType('MyBag', ['a', 'b', 'c'])
class MyCustomType():
def __init__(self, *args):
self.args = args
def as_tuple(self):
return MyBag(*self.args)
@pytest.mark.parametrize(['factory', 'expected', 'expected_item0'], [
[lambda: (1, 2, 3), tuple, int],
[lambda: Envelope((1, 2, 3)), tuple, int],
[lambda: MyTuple(1, 2, 3), MyTuple, int],
[lambda: Envelope(MyTuple(1, 2, 3)), MyTuple, int],
[lambda: MyBag(1, 2, 3), MyBag, int],
[lambda: Envelope(MyBag(1, 2, 3)), MyBag, int],
[lambda: MyCustomType(1, 2, 3), tuple, MyCustomType],
[lambda: Envelope(MyCustomType(1, 2, 3)), tuple, MyCustomType],
])
def test_casts_after_output(factory: Callable, expected, expected_item0):
def transform():
yield factory()
yield factory()
with BufferingNodeExecutionContext(transform) as context:
context.write_sync(EMPTY)
result = context.get_buffer()
assert expected == type(result[0])
assert expected_item0 == type(result[0][0])
assert expected == type(result[1])
assert expected_item0 == type(result[1][0])
def test_cast_after_returning_custom_type():
def transform():
yield MyCustomType(1, 2, 3)
yield MyCustomType(4, 5, 6)
with BufferingNodeExecutionContext(transform) as context:
context.write_sync(EMPTY)
result = context.get_buffer()
assert tuple == type(result[0])
assert tuple == type(result[1])
assert MyCustomType == type(result[0][0])
assert MyCustomType == type(result[1][0])
with BufferingNodeExecutionContext(MyCustomType.as_tuple) as context:
context.write_sync(*result)
result = context.get_buffer()
assert MyBag == type(result[0])
assert MyBag == type(result[1])

View File

@ -3,7 +3,7 @@ import pytest
from unittest.mock import sentinel
from bonobo.constants import BEGIN
from bonobo.structs import Graph
from bonobo.structs.graphs import Graph
identity = lambda x: x

View File

@ -1,4 +1,4 @@
from bonobo.constants import Token
from bonobo.structs.tokens import Token
def test_token_repr():

View File

@ -2,7 +2,7 @@ from bonobo.config.processors import use_context_processor
from bonobo.constants import BEGIN, END
from bonobo.execution.contexts.graph import GraphExecutionContext
from bonobo.execution.strategies import NaiveStrategy
from bonobo.structs import Graph
from bonobo.structs.graphs import Graph
def generate_integers():