From 464d08a4a2053c610f70fc883bf962eae1319e5f Mon Sep 17 00:00:00 2001 From: Romain Dorgueil Date: Wed, 27 Dec 2017 14:21:50 +0100 Subject: [PATCH] Generalize tuplize decorator to cast(...) decorator. --- bonobo/util/__init__.py | 3 ++- bonobo/util/api.py | 4 ++- bonobo/util/collections.py | 47 +++++++++++++++++++--------------- bonobo/util/resolvers.py | 4 +-- tests/util/test_collections.py | 11 +++++--- 5 files changed, 40 insertions(+), 29 deletions(-) diff --git a/bonobo/util/__init__.py b/bonobo/util/__init__.py index d07b0b4..b03c0a9 100644 --- a/bonobo/util/__init__.py +++ b/bonobo/util/__init__.py @@ -1,4 +1,4 @@ -from bonobo.util.collections import ensure_tuple, sortedlist, tuplize +from bonobo.util.collections import cast, ensure_tuple, sortedlist, tuplize from bonobo.util.compat import deprecated, deprecated_alias from bonobo.util.inspect import ( inspect_node, @@ -16,6 +16,7 @@ from bonobo.util.objects import (get_name, get_attribute_or_create, ValueHolder) # Bonobo's util API __all__ = [ 'ValueHolder', + 'cast', 'deprecated', 'deprecated_alias', 'ensure_tuple', diff --git a/bonobo/util/api.py b/bonobo/util/api.py index 1acf5c8..1561207 100644 --- a/bonobo/util/api.py +++ b/bonobo/util/api.py @@ -2,6 +2,7 @@ from bonobo.util import get_name class ApiHelper: + # TODO __all__ kwarg only def __init__(self, __all__): self.__all__ = __all__ @@ -13,7 +14,8 @@ class ApiHelper: from inspect import signature parameters = list(signature(x).parameters) required_parameters = {'plugins', 'services', 'strategy'} - assert parameters[0] == 'graph', 'First parameter of a graph api function must be "graph".' + assert len(parameters) > 0 and parameters[ + 0] == 'graph', 'First parameter of a graph api function must be "graph".' assert required_parameters.intersection( parameters ) == required_parameters, 'Graph api functions must define the following parameters: ' + ', '.join( diff --git a/bonobo/util/collections.py b/bonobo/util/collections.py index 745c3b9..de706f4 100644 --- a/bonobo/util/collections.py +++ b/bonobo/util/collections.py @@ -26,31 +26,36 @@ def ensure_tuple(tuple_or_mixed, *, cls=tuple): if isinstance(tuple_or_mixed, tuple): return tuple.__new__(cls, tuple_or_mixed) - return tuple.__new__(cls, (tuple_or_mixed, )) + return tuple.__new__(cls, (tuple_or_mixed,)) -def tuplize(generator): - """ - Decorates a generator and make it a tuple-returning function. As a side effect, it can also decorate any - iterator-returning function to force return value to be a tuple. +def cast(type_): + def _wrap_cast(f): + @functools.wraps(f) + def _wrapped_cast(*args, **kwargs): + nonlocal f, type_ + return type_(f(*args, **kwargs)) - >>> tuplized_lambda = tuplize(lambda: [1, 2, 3]) - >>> tuplized_lambda() - (1, 2, 3) + return _wrapped_cast - >>> @tuplize - ... def my_generator(): - ... yield 1 - ... yield 2 - ... yield 3 - ... - >>> my_generator() - (1, 2, 3) + return _wrap_cast - """ - @functools.wraps(generator) - def tuplized(*args, **kwargs): - return tuple(generator(*args, **kwargs)) +tuplize = cast(tuple) +tuplize.__doc__ = """ +Decorates a generator and make it a tuple-returning function. As a side effect, it can also decorate any +iterator-returning function to force return value to be a tuple. - return tuplized +>>> tuplized_lambda = tuplize(lambda: [1, 2, 3]) +>>> tuplized_lambda() +(1, 2, 3) + +>>> @tuplize +... def my_generator(): +... yield 1 +... yield 2 +... yield 3 +... +>>> my_generator() +(1, 2, 3) +""" diff --git a/bonobo/util/resolvers.py b/bonobo/util/resolvers.py index 60934d8..5cf2738 100644 --- a/bonobo/util/resolvers.py +++ b/bonobo/util/resolvers.py @@ -8,7 +8,7 @@ import os import runpy import bonobo -from bonobo.util.collections import tuplize +from bonobo.util import cast class _RequiredModule: @@ -61,7 +61,7 @@ def _resolve_options(options=None): return dict() -@tuplize +@cast(tuple) def _resolve_transformations(transformations): """ Resolve a collection of strings into the matching python objects, defaulting to bonobo namespace if no package is provided. diff --git a/tests/util/test_collections.py b/tests/util/test_collections.py index 3a1e517..f502afd 100644 --- a/tests/util/test_collections.py +++ b/tests/util/test_collections.py @@ -1,5 +1,7 @@ +import pytest + from bonobo.util import sortedlist, ensure_tuple -from bonobo.util.collections import tuplize +from bonobo.util.collections import tuplize, cast def test_sortedlist(): @@ -12,12 +14,13 @@ def test_sortedlist(): def test_ensure_tuple(): - assert ensure_tuple('a') == ('a', ) - assert ensure_tuple(('a', )) == ('a', ) + assert ensure_tuple('a') == ('a',) + assert ensure_tuple(('a',)) == ('a',) assert ensure_tuple(()) is () -def test_tuplize(): +@pytest.mark.parametrize('tuplize', [tuplize, cast(tuple)]) +def test_tuplize(tuplize): tuplized_lambda = tuplize(lambda: [1, 2, 3]) assert tuplized_lambda() == (1, 2, 3)