Merge branch 'develop' into feature/io_pickle
This commit is contained in:
0
tests/__init__.py
Normal file
0
tests/__init__.py
Normal file
@ -2,7 +2,6 @@ import pytest
|
||||
|
||||
from bonobo.config.configurables import Configurable
|
||||
from bonobo.config.options import Option
|
||||
from bonobo.config.services import Container, Service, validate_service_name
|
||||
|
||||
|
||||
class MyConfigurable(Configurable):
|
||||
@ -25,28 +24,6 @@ class MyConfigurableUsingPositionalOptions(MyConfigurable):
|
||||
third = Option(str, required=False, positional=True)
|
||||
|
||||
|
||||
class PrinterInterface():
|
||||
def print(self, *args):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class ConcretePrinter(PrinterInterface):
|
||||
def __init__(self, prefix):
|
||||
self.prefix = prefix
|
||||
|
||||
def print(self, *args):
|
||||
return ';'.join((self.prefix, *args))
|
||||
|
||||
|
||||
class MyServiceDependantConfigurable(Configurable):
|
||||
printer = Service(
|
||||
PrinterInterface,
|
||||
)
|
||||
|
||||
def __call__(self, printer: PrinterInterface, *args):
|
||||
return printer.print(*args)
|
||||
|
||||
|
||||
def test_missing_required_option_error():
|
||||
with pytest.raises(TypeError) as exc:
|
||||
MyConfigurable()
|
||||
@ -107,39 +84,5 @@ def test_option_resolution_order():
|
||||
assert o.integer == None
|
||||
|
||||
|
||||
def test_service_name_validator():
|
||||
assert validate_service_name('foo') == 'foo'
|
||||
assert validate_service_name('foo.bar') == 'foo.bar'
|
||||
assert validate_service_name('Foo') == 'Foo'
|
||||
assert validate_service_name('Foo.Bar') == 'Foo.Bar'
|
||||
assert validate_service_name('Foo.a0') == 'Foo.a0'
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
validate_service_name('foo.0')
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
validate_service_name('0.foo')
|
||||
|
||||
|
||||
SERVICES = Container(
|
||||
printer0=ConcretePrinter(prefix='0'),
|
||||
printer1=ConcretePrinter(prefix='1'),
|
||||
)
|
||||
|
||||
|
||||
def test_service_dependency():
|
||||
o = MyServiceDependantConfigurable(printer='printer0')
|
||||
|
||||
assert o(SERVICES.get('printer0'), 'foo', 'bar') == '0;foo;bar'
|
||||
assert o(SERVICES.get('printer1'), 'bar', 'baz') == '1;bar;baz'
|
||||
assert o(*SERVICES.args_for(o), 'foo', 'bar') == '0;foo;bar'
|
||||
|
||||
|
||||
def test_service_dependency_unavailable():
|
||||
o = MyServiceDependantConfigurable(printer='printer2')
|
||||
with pytest.raises(KeyError):
|
||||
SERVICES.args_for(o)
|
||||
|
||||
|
||||
def test_option_positional():
|
||||
o = MyConfigurableUsingPositionalOptions('1', '2', '3', required_str='hello')
|
||||
@ -28,8 +28,6 @@ def test_define_with_decorator():
|
||||
def Concrete(self, *args, **kwargs):
|
||||
calls.append((args, kwargs, ))
|
||||
|
||||
print('handler', Concrete.handler)
|
||||
|
||||
assert callable(Concrete.handler)
|
||||
t = Concrete('foo', bar='baz')
|
||||
|
||||
96
tests/config/test_services.py
Normal file
96
tests/config/test_services.py
Normal file
@ -0,0 +1,96 @@
|
||||
import threading
|
||||
import time
|
||||
|
||||
import pytest
|
||||
|
||||
from bonobo.config import Configurable, Container, Exclusive, Service
|
||||
from bonobo.config.services import validate_service_name
|
||||
|
||||
|
||||
class PrinterInterface():
|
||||
def print(self, *args):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class ConcretePrinter(PrinterInterface):
|
||||
def __init__(self, prefix):
|
||||
self.prefix = prefix
|
||||
|
||||
def print(self, *args):
|
||||
return ';'.join((self.prefix, *args))
|
||||
|
||||
|
||||
SERVICES = Container(
|
||||
printer0=ConcretePrinter(prefix='0'),
|
||||
printer1=ConcretePrinter(prefix='1'),
|
||||
)
|
||||
|
||||
|
||||
class MyServiceDependantConfigurable(Configurable):
|
||||
printer = Service(
|
||||
PrinterInterface,
|
||||
)
|
||||
|
||||
def __call__(self, printer: PrinterInterface, *args):
|
||||
return printer.print(*args)
|
||||
|
||||
|
||||
def test_service_name_validator():
|
||||
assert validate_service_name('foo') == 'foo'
|
||||
assert validate_service_name('foo.bar') == 'foo.bar'
|
||||
assert validate_service_name('Foo') == 'Foo'
|
||||
assert validate_service_name('Foo.Bar') == 'Foo.Bar'
|
||||
assert validate_service_name('Foo.a0') == 'Foo.a0'
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
validate_service_name('foo.0')
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
validate_service_name('0.foo')
|
||||
|
||||
|
||||
def test_service_dependency():
|
||||
o = MyServiceDependantConfigurable(printer='printer0')
|
||||
|
||||
assert o(SERVICES.get('printer0'), 'foo', 'bar') == '0;foo;bar'
|
||||
assert o(SERVICES.get('printer1'), 'bar', 'baz') == '1;bar;baz'
|
||||
assert o(*SERVICES.args_for(o), 'foo', 'bar') == '0;foo;bar'
|
||||
|
||||
|
||||
def test_service_dependency_unavailable():
|
||||
o = MyServiceDependantConfigurable(printer='printer2')
|
||||
with pytest.raises(KeyError):
|
||||
SERVICES.args_for(o)
|
||||
|
||||
|
||||
class VCR:
|
||||
def __init__(self):
|
||||
self.tape = []
|
||||
|
||||
def append(self, x):
|
||||
return self.tape.append(x)
|
||||
|
||||
|
||||
def test_exclusive():
|
||||
vcr = VCR()
|
||||
vcr.append('hello')
|
||||
|
||||
def record(prefix, vcr=vcr):
|
||||
with Exclusive(vcr):
|
||||
for i in range(5):
|
||||
vcr.append(' '.join((prefix, str(i))))
|
||||
time.sleep(0.05)
|
||||
|
||||
threads = [threading.Thread(target=record, args=(str(i), )) for i in range(5)]
|
||||
|
||||
for thread in threads:
|
||||
thread.start()
|
||||
time.sleep(0.01) # this is not good practice, how to test this without sleeping ?? XXX
|
||||
|
||||
for thread in threads:
|
||||
thread.join()
|
||||
|
||||
assert vcr.tape == [
|
||||
'hello', '0 0', '0 1', '0 2', '0 3', '0 4', '1 0', '1 1', '1 2', '1 3', '1 4', '2 0', '2 1', '2 2', '2 3',
|
||||
'2 4', '3 0', '3 1', '3 2', '3 3', '3 4', '4 0', '4 1', '4 2', '4 3', '4 4'
|
||||
]
|
||||
@ -55,3 +55,38 @@ def test_read_csv_from_file(tmpdir):
|
||||
'b': 'b bar',
|
||||
'c': 'c bar',
|
||||
}
|
||||
|
||||
|
||||
def test_read_csv_kwargs_output_formater(tmpdir):
|
||||
fs, filename = open_fs(tmpdir), 'input.csv'
|
||||
fs.open(filename, 'w').write('a,b,c\na foo,b foo,c foo\na bar,b bar,c bar')
|
||||
|
||||
reader = CsvReader(path=filename, delimiter=',', output_format='kwargs')
|
||||
|
||||
context = CapturingNodeExecutionContext(reader, services={'fs': fs})
|
||||
|
||||
context.start()
|
||||
context.write(BEGIN, Bag(), END)
|
||||
context.step()
|
||||
context.stop()
|
||||
|
||||
assert len(context.send.mock_calls) == 2
|
||||
|
||||
args0, kwargs0 = context.send.call_args_list[0]
|
||||
assert len(args0) == 1 and not len(kwargs0)
|
||||
args1, kwargs1 = context.send.call_args_list[1]
|
||||
assert len(args1) == 1 and not len(kwargs1)
|
||||
|
||||
_args, _kwargs = args0[0].get()
|
||||
assert not len(_args) and _kwargs == {
|
||||
'a': 'a foo',
|
||||
'b': 'b foo',
|
||||
'c': 'c foo',
|
||||
}
|
||||
|
||||
_args, _kwargs = args1[0].get()
|
||||
assert not len(_args) and _kwargs == {
|
||||
'a': 'a bar',
|
||||
'b': 'b bar',
|
||||
'c': 'c bar',
|
||||
}
|
||||
|
||||
@ -1,10 +1,26 @@
|
||||
import runpy
|
||||
import sys
|
||||
from unittest.mock import patch
|
||||
|
||||
import pkg_resources
|
||||
import pytest
|
||||
|
||||
from bonobo import get_examples_path
|
||||
from bonobo import __main__, __version__, get_examples_path
|
||||
from bonobo.commands import entrypoint
|
||||
|
||||
|
||||
def runner_entrypoint(*args):
|
||||
return entrypoint(list(args))
|
||||
|
||||
|
||||
def runner_module(*args):
|
||||
with patch.object(sys, 'argv', ['bonobo', *args]):
|
||||
return runpy.run_path(__main__.__file__, run_name='__main__')
|
||||
|
||||
|
||||
all_runners = pytest.mark.parametrize('runner', [runner_entrypoint, runner_module])
|
||||
|
||||
|
||||
def test_entrypoint():
|
||||
commands = {}
|
||||
|
||||
@ -13,23 +29,51 @@ def test_entrypoint():
|
||||
|
||||
assert 'init' in commands
|
||||
assert 'run' in commands
|
||||
assert 'version' in commands
|
||||
|
||||
|
||||
def test_no_command(capsys):
|
||||
@all_runners
|
||||
def test_no_command(runner, capsys):
|
||||
with pytest.raises(SystemExit):
|
||||
entrypoint([])
|
||||
runner()
|
||||
_, err = capsys.readouterr()
|
||||
assert 'error: the following arguments are required: command' in err
|
||||
|
||||
|
||||
def test_init():
|
||||
pass # need ext dir
|
||||
|
||||
|
||||
def test_run(capsys):
|
||||
entrypoint(['run', '--quiet', get_examples_path('types/strings.py')])
|
||||
@all_runners
|
||||
def test_run(runner, capsys):
|
||||
runner('run', '--quiet', get_examples_path('types/strings.py'))
|
||||
out, err = capsys.readouterr()
|
||||
out = out.split('\n')
|
||||
assert out[0].startswith('Foo ')
|
||||
assert out[1].startswith('Bar ')
|
||||
assert out[2].startswith('Baz ')
|
||||
|
||||
|
||||
@all_runners
|
||||
def test_run_module(runner, capsys):
|
||||
runner('run', '--quiet', '-m', 'bonobo.examples.types.strings')
|
||||
out, err = capsys.readouterr()
|
||||
out = out.split('\n')
|
||||
assert out[0].startswith('Foo ')
|
||||
assert out[1].startswith('Bar ')
|
||||
assert out[2].startswith('Baz ')
|
||||
|
||||
|
||||
@all_runners
|
||||
def test_run_path(runner, capsys):
|
||||
runner('run', '--quiet', get_examples_path('types'))
|
||||
out, err = capsys.readouterr()
|
||||
out = out.split('\n')
|
||||
assert out[0].startswith('Foo ')
|
||||
assert out[1].startswith('Bar ')
|
||||
assert out[2].startswith('Baz ')
|
||||
|
||||
|
||||
@all_runners
|
||||
def test_version(runner, capsys):
|
||||
runner('version')
|
||||
out, err = capsys.readouterr()
|
||||
out = out.strip()
|
||||
assert out.startswith('bonobo ')
|
||||
assert out.endswith(__version__)
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import types
|
||||
import inspect
|
||||
|
||||
|
||||
def test_wildcard_import():
|
||||
@ -10,7 +10,7 @@ def test_wildcard_import():
|
||||
if name.startswith('_'):
|
||||
continue
|
||||
attr = getattr(bonobo, name)
|
||||
if isinstance(attr, types.ModuleType):
|
||||
if inspect.ismodule(attr):
|
||||
continue
|
||||
|
||||
assert name in bonobo.__all__
|
||||
|
||||
@ -1,4 +1,9 @@
|
||||
import operator
|
||||
|
||||
import pytest
|
||||
|
||||
from bonobo.util.objects import Wrapper, get_name, ValueHolder
|
||||
from bonobo.util.testing import optional_contextmanager
|
||||
|
||||
|
||||
class foo:
|
||||
@ -52,3 +57,56 @@ def test_valueholder():
|
||||
assert y == x
|
||||
assert y is not x
|
||||
assert repr(x) == repr(y) == repr(43)
|
||||
|
||||
|
||||
unsupported_operations = {
|
||||
int: {operator.matmul},
|
||||
str: {
|
||||
operator.sub, operator.mul, operator.matmul, operator.floordiv, operator.truediv, operator.mod, divmod,
|
||||
operator.pow, operator.lshift, operator.rshift, operator.and_, operator.xor, operator.or_
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize('x,y', [(5, 3), (0, 10), (0, 0), (1, 1), ('foo', 'bar'), ('', 'baz!')])
|
||||
@pytest.mark.parametrize(
|
||||
'operation,inplace_operation', [
|
||||
(operator.add, operator.iadd),
|
||||
(operator.sub, operator.isub),
|
||||
(operator.mul, operator.imul),
|
||||
(operator.matmul, operator.imatmul),
|
||||
(operator.truediv, operator.itruediv),
|
||||
(operator.floordiv, operator.ifloordiv),
|
||||
(operator.mod, operator.imod),
|
||||
(divmod, None),
|
||||
(operator.pow, operator.ipow),
|
||||
(operator.lshift, operator.ilshift),
|
||||
(operator.rshift, operator.irshift),
|
||||
(operator.and_, operator.iand),
|
||||
(operator.xor, operator.ixor),
|
||||
(operator.or_, operator.ior),
|
||||
]
|
||||
)
|
||||
def test_valueholder_integer_operations(x, y, operation, inplace_operation):
|
||||
v = ValueHolder(x)
|
||||
|
||||
is_supported = operation not in unsupported_operations.get(type(x), set())
|
||||
|
||||
isdiv = ('div' in operation.__name__) or ('mod' in operation.__name__)
|
||||
|
||||
# forward...
|
||||
with optional_contextmanager(pytest.raises(TypeError), ignore=is_supported):
|
||||
with optional_contextmanager(pytest.raises(ZeroDivisionError), ignore=y or not isdiv):
|
||||
assert operation(x, y) == operation(v, y)
|
||||
|
||||
# backward...
|
||||
with optional_contextmanager(pytest.raises(TypeError), ignore=is_supported):
|
||||
with optional_contextmanager(pytest.raises(ZeroDivisionError), ignore=x or not isdiv):
|
||||
assert operation(y, x) == operation(y, v)
|
||||
|
||||
# in place...
|
||||
if inplace_operation is not None:
|
||||
with optional_contextmanager(pytest.raises(TypeError), ignore=is_supported):
|
||||
with optional_contextmanager(pytest.raises(ZeroDivisionError), ignore=y or not isdiv):
|
||||
inplace_operation(v, y)
|
||||
assert v == operation(x, y)
|
||||
|
||||
Reference in New Issue
Block a user