Making config/util/structs apis available at level 2 import (x.y), implements the roots for loopbacks (recursive transformations). This still needs work, as its hard not to close an input queue as soon as the last item was read.

This commit is contained in:
Romain Dorgueil
2017-10-02 08:38:31 +02:00
parent d858b246ad
commit c09c101074
8 changed files with 96 additions and 32 deletions

View File

@ -1,6 +1,6 @@
import logging import logging
from bonobo.structs import Bag, Graph, Token from bonobo.structs import Bag, ErrorBag, Graph, Token
from bonobo.nodes import CsvReader, CsvWriter, FileReader, FileWriter, Filter, JsonReader, JsonWriter, Limit, \ from bonobo.nodes import CsvReader, CsvWriter, FileReader, FileWriter, Filter, JsonReader, JsonWriter, Limit, \
PickleReader, PickleWriter, PrettyPrinter, RateLimited, Tee, arg0_to_kwargs, count, identity, kwargs_to_arg0, noop PickleReader, PickleWriter, PrettyPrinter, RateLimited, Tee, arg0_to_kwargs, count, identity, kwargs_to_arg0, noop
from bonobo.strategies import create_strategy from bonobo.strategies import create_strategy
@ -70,7 +70,7 @@ def run(graph, strategy=None, plugins=None, services=None):
# bonobo.structs # bonobo.structs
register_api_group(Bag, Graph, Token) register_api_group(Bag, ErrorBag, Graph, Token)
# bonobo.strategies # bonobo.strategies
register_api(create_strategy) register_api(create_strategy)

View File

@ -3,6 +3,7 @@ from bonobo.structs.tokens import Token
BEGIN = Token('Begin') BEGIN = Token('Begin')
END = Token('End') END = Token('End')
INHERIT_INPUT = Token('InheritInput') INHERIT_INPUT = Token('InheritInput')
LOOPBACK = Token('Loopback')
NOT_MODIFIED = Token('NotModified') NOT_MODIFIED = Token('NotModified')
DEFAULT_SERVICES_FILENAME = '_services.py' DEFAULT_SERVICES_FILENAME = '_services.py'
DEFAULT_SERVICES_ATTR = 'get_services' DEFAULT_SERVICES_ATTR = 'get_services'

View File

@ -2,13 +2,13 @@ import traceback
from queue import Empty from queue import Empty
from time import sleep from time import sleep
from bonobo.constants import INHERIT_INPUT, NOT_MODIFIED from bonobo.constants import INHERIT_INPUT, NOT_MODIFIED, BEGIN, END
from bonobo.errors import InactiveReadableError, UnrecoverableError from bonobo.errors import InactiveReadableError, UnrecoverableError
from bonobo.execution.base import LoopingExecutionContext from bonobo.execution.base import LoopingExecutionContext
from bonobo.structs.bags import Bag from bonobo.structs.bags import Bag
from bonobo.structs.inputs import Input from bonobo.structs.inputs import Input
from bonobo.util.compat import deprecated_alias from bonobo.util.compat import deprecated_alias
from bonobo.util.errors import is_error from bonobo.util.inspect import iserrorbag, isloopbackbag
from bonobo.util.iterators import iter_if_not_sequence from bonobo.util.iterators import iter_if_not_sequence
from bonobo.util.objects import get_name from bonobo.util.objects import get_name
from bonobo.util.statistics import WithStatistics from bonobo.util.statistics import WithStatistics
@ -65,8 +65,10 @@ class NodeExecutionContext(WithStatistics, LoopingExecutionContext):
if not _control: if not _control:
self.increment('out') self.increment('out')
if is_error(value): if iserrorbag(value):
value.apply(self.handle_error) value.apply(self.handle_error)
elif isloopbackbag(value):
self.input.put(value)
else: else:
for output in self.outputs: for output in self.outputs:
output.put(value) output.put(value)
@ -137,7 +139,7 @@ def _resolve(input_bag, output):
if output is NOT_MODIFIED: if output is NOT_MODIFIED:
return input_bag return input_bag
if is_error(output): if iserrorbag(output):
return output return output
# If it does not look like a bag, let's create one for easier manipulation # If it does not look like a bag, let's create one for easier manipulation

View File

@ -1,5 +1,11 @@
from bonobo.structs.bags import Bag from bonobo.structs.bags import Bag, ErrorBag, LoopbackBag
from bonobo.structs.graphs import Graph from bonobo.structs.graphs import Graph
from bonobo.structs.tokens import Token from bonobo.structs.tokens import Token
__all__ = ['Bag', 'Graph', 'Token'] __all__ = [
'Bag',
'ErrorBag',
'Graph',
'LoopbackBag',
'Token',
]

View File

@ -1,6 +1,6 @@
import itertools import itertools
from bonobo.constants import INHERIT_INPUT from bonobo.constants import INHERIT_INPUT, LOOPBACK
__all__ = [ __all__ = [
'Bag', 'Bag',
@ -33,8 +33,10 @@ class Bag:
""" """
default_flags = ()
def __init__(self, *args, _flags=None, _parent=None, **kwargs): def __init__(self, *args, _flags=None, _parent=None, **kwargs):
self._flags = _flags or () self._flags = type(self).default_flags + (_flags or ())
self._parent = _parent self._parent = _parent
self._args = args self._args = args
self._kwargs = kwargs self._kwargs = kwargs
@ -43,7 +45,7 @@ class Bag:
def args(self): def args(self):
if self._parent is None: if self._parent is None:
return self._args return self._args
return (*self._parent.args, *self._args, ) return (*self._parent.args, *self._args,)
@property @property
def kwargs(self): def kwargs(self):
@ -91,7 +93,7 @@ class Bag:
@classmethod @classmethod
def inherit(cls, *args, **kwargs): def inherit(cls, *args, **kwargs):
return cls(*args, _flags=(INHERIT_INPUT, ), **kwargs) return cls(*args, _flags=(INHERIT_INPUT,), **kwargs)
def __eq__(self, other): def __eq__(self, other):
return isinstance(other, Bag) and other.args == self.args and other.kwargs == self.kwargs return isinstance(other, Bag) and other.args == self.args and other.kwargs == self.kwargs
@ -99,12 +101,16 @@ class Bag:
def __repr__(self): def __repr__(self):
return '<{} ({})>'.format( return '<{} ({})>'.format(
type(self).__name__, ', '. type(self).__name__, ', '.
join(itertools.chain( join(itertools.chain(
map(repr, self.args), map(repr, self.args),
('{}={}'.format(k, repr(v)) for k, v in self.kwargs.items()), ('{}={}'.format(k, repr(v)) for k, v in self.kwargs.items()),
)) ))
) )
class LoopbackBag(Bag):
default_flags = (LOOPBACK,)
class ErrorBag(Bag): class ErrorBag(Bag):
pass pass

View File

@ -1,6 +1,28 @@
from bonobo.util.inspect import (
inspect_node,
isbag,
isconfigurable,
isconfigurabletype,
iscontextprocessor,
iserrorbag,
isloopbackbag,
ismethod,
isoption,
istype,
)
from bonobo.util.python import require from bonobo.util.python import require
# Bonobo's util API # Bonobo's util API
__all__ = [ __all__ = [
'require' 'require',
'inspect_node',
'isbag',
'isconfigurable',
'isconfigurabletype',
'iscontextprocessor',
'iserrorbag',
'isloopbackbag',
'ismethod',
'isoption',
'istype',
] ]

View File

@ -1,13 +1,6 @@
import sys import sys
from textwrap import indent from textwrap import indent
from bonobo import settings
from bonobo.structs.bags import ErrorBag
def is_error(bag):
return isinstance(bag, ErrorBag)
def _get_error_message(exc): def _get_error_message(exc):
if hasattr(exc, '__str__'): if hasattr(exc, '__str__'):

View File

@ -1,5 +1,18 @@
from collections import namedtuple from collections import namedtuple
from bonobo.constants import LOOPBACK
def isconfigurable(mixed):
"""
Check if the given argument is an instance of :class:`bonobo.config.Configurable`.
:param mixed:
:return: bool
"""
from bonobo.config.configurables import Configurable
return isinstance(mixed, Configurable)
def isconfigurabletype(mixed): def isconfigurabletype(mixed):
""" """
@ -13,17 +26,6 @@ def isconfigurabletype(mixed):
return isinstance(mixed, ConfigurableMeta) return isinstance(mixed, ConfigurableMeta)
def isconfigurable(mixed):
"""
Check if the given argument is an instance of :class:`bonobo.config.Configurable`.
:param mixed:
:return: bool
"""
from bonobo.config.configurables import Configurable
return isinstance(mixed, Configurable)
def isoption(mixed): def isoption(mixed):
""" """
Check if the given argument is an instance of :class:`bonobo.config.Option`. Check if the given argument is an instance of :class:`bonobo.config.Option`.
@ -68,6 +70,38 @@ def istype(mixed):
return isinstance(mixed, type) return isinstance(mixed, type)
def isbag(mixed):
"""
Check if the given argument is an instance of a :class:`bonobo.Bag`.
:param mixed:
:return: bool
"""
from bonobo.structs.bags import Bag
return isinstance(mixed, Bag)
def iserrorbag(mixed):
"""
Check if the given argument is an instance of an :class:`bonobo.ErrorBag`.
:param mixed:
:return: bool
"""
from bonobo.structs.bags import ErrorBag
return isinstance(mixed, ErrorBag)
def isloopbackbag(mixed):
"""
Check if the given argument is an instance of a :class:`bonobo.Bag`, marked for loopback behaviour.
:param mixed:
:return: bool
"""
return isbag(mixed) and LOOPBACK in mixed.flags
ConfigurableInspection = namedtuple( ConfigurableInspection = namedtuple(
'ConfigurableInspection', [ 'ConfigurableInspection', [
'type', 'type',