示例#1
0
def breadth_first(start, expand):
    """Performs a breadth-first search of a graph-like structure.

    :param start: Node to start the search from
    :param expand: Function taking a node as an argument and returning iterable
                   of its child nodes

    :return: Iterable of nodes in the BFS order

    Example::

        tree = json.loads(some_data)
        for item in breadth_first(tree, key_func('children', default=())):
            do_something_with(item)
    """
    ensure_callable(expand)

    def generator():
        queue = deque([start])
        while queue:
            node = queue.popleft()
            yield node
            queue.extend(expand(node))

    return generator()
示例#2
0
def method_decorator(decor):
    """Decorator for function decorators (sic), written either
    as classes or functions.

    In either case, the decorator ``decor`` must be "doubly-callable":

        * for classes, this means implementing ``__call__`` method
          in addition to possible ``__init__``
        * for functions, this means returning a function that acts
          as an actual decorator, i.e. taking a function and returning
          its decorated version

    Although it works for any decorator, it's useful mainly for those
    that should take optional arguments. If the decorator is adorned
    with ``@method_decorator``, it's possible to use it without the pair of
    empty parentheses::

        class Foo(object):
            @enhanced  # rather than @enhanced()
            def foo(self):
                pass

    when we don't want to pass any arguments to it.

    .. note::

        :func:`function_decorator` makes decorator applicable
        only to methods inside a class. Use :func:`decorator`,
        :func:`function_decorator` or :func:`class_decorator` for decorators
        that should be applicable to other language constructs.

    .. versionadded:: 0.0.3
    """
    ensure_callable(decor)
    return _wrap_decorator(decor, "methods", is_method)
示例#3
0
def decorator(decor):
    """Decorator for decorators (sic), written either as classes or functions.

    In either case, the decorator ``decor`` must be "doubly-callable":

        * for classes, this means implementing ``__call__`` method
          in addition to possible ``__init__``
        * for functions, this means returning a function that acts
          as an actual decorator, i.e. taking a function and returning
          its decorated version

    Although it works for any decorator, it's useful mainly for those
    that should take optional arguments. If the decorator is adorned
    with ``@decorator``, it's possible to use it without the pair of
    empty parentheses::

        @enhanced  # rather than @enhanced()
        def foo():
            pass

    when we don't want to pass any arguments to it.

    .. note::

        :func:`decorator` makes decorator appicable for both
        functions and classes. If you want to restrict the type of
        decorator targets, use :func:`function_decorator`,
        :func:`method_decorator` or :func:`class_decorator`.
    """
    ensure_callable(decor)
    return _wrap_decorator(decor, "functions or classes",
                           or_(inspect.isfunction, inspect.isclass))
示例#4
0
def flip(f):
    """Flip the order of positonal arguments of given function."""
    ensure_callable(f)

    result = lambda *args, **kwargs: f(*reversed(args), **kwargs)
    functools.update_wrapper(result, f, ('__name__', '__module__'))
    return result
示例#5
0
文件: fluency.py 项目: Xion/taipan
def terminator(method):
    """Mark a public method of @\ :class:`fluent` class as *terminator*,
    i.e. a method that ends a chain of consecutive calls and returns a result.
    """
    ensure_callable(method)
    method.__fluent_terminator = True
    return method
示例#6
0
def terminator(method):
    """Mark a public method of @\ :class:`fluent` class as *terminator*,
    i.e. a method that ends a chain of consecutive calls and returns a result.
    """
    ensure_callable(method)
    method.__fluent_terminator = True
    return method
示例#7
0
def uncurry(f):
    """Convert a curried function into a function on tuples
    (of positional arguments) and dictionaries (of keyword arguments).
    """
    ensure_callable(f)

    result = lambda args=(), kwargs=None: f(*args, **(kwargs or {}))
    functools.update_wrapper(result, f, ('__name__', '__module__'))
    return result
示例#8
0
def not_(f):
    """Creates a function that returns a Boolean negative of provided function.

    :param f: Function to create a Boolean negative of

    :return: Function ``g`` such that ``g(<args>) == not f(<args>)``
             for any ``<args>``
    """
    ensure_callable(f)
    return lambda *args, **kwargs: not f(*args, **kwargs)
示例#9
0
    def transform(self, func):
        """Transform the value stored in this variable
        by applying a specified function to it.

        :param func: Unary transformation function

        :raise ValueAbsentError: When the variable has no value
        :raise TypeError: When ``func`` is not a callable

        .. versionadded:: 0.0.2
        """
        self._ensure_has_value()
        ensure_callable(func)
        self.value = func(self.value)
示例#10
0
文件: constructs.py 项目: Xion/taipan
    def transform(self, func):
        """Transform the value stored in this variable
        by applying a specified function to it.

        :param func: Unary transformation function

        :raise ValueAbsentError: When the variable has no value
        :raise TypeError: When ``func`` is not a callable

        .. versionadded:: 0.0.2
        """
        self._ensure_has_value()
        ensure_callable(func)
        self.value = func(self.value)
示例#11
0
def filterkeys(predicate, dict_):
    """Return a new dictionary comprising of keys
    for which ``predicate`` returns True, and their corresponding values.

    :param predicate: Predicate taking a dictionary key, or None
    """
    predicate = bool if predicate is None else ensure_callable(predicate)
    ensure_mapping(dict_)
    return dict_.__class__((k, v) for k, v in iteritems(dict_) if predicate(k))
示例#12
0
def starfilteritems(predicate, dict_):
    """Return a new dictionary comprising of keys and values
    for which ``predicate`` returns True.

    :param predicate: Predicate taking key and value, or None

    .. versionchanged:: 0.0.2
       Renamed ``starfilteritems`` for consistency with :func:`starmapitems`.
    """
    ensure_mapping(dict_)

    if predicate is None:
        predicate = lambda k, v: all((k, v))
    else:
        ensure_callable(predicate)

    return dict_.__class__(
        (k, v) for k, v in iteritems(dict_) if predicate(k, v))
示例#13
0
def filtervalues(predicate, dict_):
    """Returns a new dictionary comprising of values
    for which ``predicate`` return True, and keys that corresponded to them.

    :param predicate: Predicate taking a dictionary value, or None
    """
    predicate = bool if predicate is None else ensure_callable(predicate)
    ensure_mapping(dict_)
    return dict_.__class__((k, v) for k, v in iteritems(dict_) if predicate(v))
示例#14
0
文件: constructs.py 项目: Xion/taipan
def with_(contextmanager, do):
    """Emulate a `with`` statement, performing an operation within context.

    :param contextmanager: Context manager to use for ``with`` statement
    :param do: Operation to perform: callable that receives the ``as`` value

    :return: Result of the operation

    Example::

        # read all lines from given list of ``files``
        all_lines = sum((with_(open(filename), do=dotcall('readlines'))
                         for filename in files), [])
    """
    ensure_contextmanager(contextmanager)
    ensure_callable(do)

    with contextmanager as value:
        return do(value)
示例#15
0
def with_(contextmanager, do):
    """Emulate a `with`` statement, performing an operation within context.

    :param contextmanager: Context manager to use for ``with`` statement
    :param do: Operation to perform: callable that receives the ``as`` value

    :return: Result of the operation

    Example::

        # read all lines from given list of ``files``
        all_lines = sum((with_(open(filename), do=dotcall('readlines'))
                         for filename in files), [])
    """
    ensure_contextmanager(contextmanager)
    ensure_callable(do)

    with contextmanager as value:
        return do(value)
示例#16
0
def mapvalues(function, dict_):
    """Return a new dictionary where the values come from applying ``function``
    to the values of given dictionary.

    :param function: Function taking a dictionary value,
                     or None (corresponding to identity function)

    .. versionadded:: 0.0.2
    """
    ensure_mapping(dict_)
    function = identity() if function is None else ensure_callable(function)
    return dict_.__class__((k, function(v)) for k, v in iteritems(dict_))
示例#17
0
def filteritems(predicate, dict_):
    """Return a new dictionary comprising of items
    for which ``predicate`` returns True.

    :param predicate: Predicate taking a key-value pair, or None

    .. versionchanged: 0.0.2
       ``predicate`` is now taking a key-value pair as a single argument.
    """
    predicate = all if predicate is None else ensure_callable(predicate)
    ensure_mapping(dict_)
    return dict_.__class__(ifilter(predicate, iteritems(dict_)))
示例#18
0
def depth_first(start, descend):
    """Performs a depth-first search of a graph-like structure.

    :param start: Node to start the search from
    :param expand: Function taking a node as an argument and returning iterable
                   of its child nodes

    :return: Iterable of nodes in the DFS order

    Example::

        for node in depth_first(graph, attr_func('adjacent')):
            visit(node)
    """
    ensure_callable(descend)

    def generator():
        stack = [start]
        while stack:
            node = stack.pop()
            yield node
            stack.extend(descend(node))

    return generator()
示例#19
0
def starmapitems(function, dict_):
    """Return a new dictionary where the keys and values come from applying
    ``function`` to the keys and values of given dictionary.

    .. warning::

        If ``function`` returns a key-value pair with the same key
        more than once, it is undefined which value will be chosen
        for that key in the resulting dictionary.

    :param function: Function taking key and value as two arguments
                     and returning a new key-value pair, or None
                     (corresponding to identity function)

    .. versionadded:: 0.0.2
    """
    ensure_mapping(dict_)

    if function is None:
        function = lambda k, v: (k, v)
    else:
        ensure_callable(function)

    return dict_.__class__(starmap(function, iteritems(dict_)))
示例#20
0
def _index(*args, **kwargs):
    """Implementation of list searching.

    :param of: Element to search for
    :param where: Predicate to search for
    :param in_: List to search in
    :param start: Start index for the lookup
    :param step: Counter step (i.e. in/decrement) for each iteration

    :return: Pair of ``(list, index)``,
             where ``list`` is the list we searched in
             and ``index`` is the index of the first element found, or -1
    """
    start = kwargs.pop('start', 0)
    step = kwargs.pop('step', 1)

    if len(args) == 2:
        elem, list_ = args
        ensure_sequence(list_)
        predicate = lambda item: item == elem
    else:
        ensure_keyword_args(kwargs,
                            mandatory=('in_',), optional=('of', 'where'))
        if 'of' in kwargs and 'where' in kwargs:
            raise TypeError(
                "either an item or predicate must be supplied, not both")
        if not ('of' in kwargs or 'where' in kwargs):
            raise TypeError("an item or predicate must be supplied")

        list_ = ensure_sequence(kwargs['in_'])
        if 'where' in kwargs:
            predicate = ensure_callable(kwargs['where'])
        else:
            elem = kwargs['of']
            predicate = lambda item: item == elem

    len_ = len(list_)
    start = max(0, min(len_ - 1, start))

    i = start
    while 0 <= i < len_:
        if predicate(list_[i]):
            return list_, i
        i += step
    else:
        return list_, -1
示例#21
0
def mapkeys(function, dict_):
    """Return a new dictionary where the keys come from applying ``function``
    to the keys of given dictionary.

    .. warning::

        If ``function`` returns the same value for more than one key,
        it is undefined which key will be chosen for the resulting dictionary.

    :param function: Function taking a dictionary key,
                     or None (corresponding to identity function)

    .. versionadded:: 0.0.2
    """
    ensure_mapping(dict_)
    function = identity() if function is None else ensure_callable(function)
    return dict_.__class__((function(k), v) for k, v in iteritems(dict_))
示例#22
0
def mapitems(function, dict_):
    """Return a new dictionary where the keys and values come from applying
    ``function`` to key-value pairs from given dictionary.

    .. warning::

        If ``function`` returns a key-value pair with the same key
        more than once, it is undefined which value will be chosen
        for that key in the resulting dictionary.

    :param function: Function taking a key-value pair as a single argument,
                     and returning a new key-value pair; or None
                     (corresponding to identity function)

    .. versionadded:: 0.0.2
    """
    ensure_mapping(dict_)
    function = identity() if function is None else ensure_callable(function)
    return dict_.__class__(imap(function, iteritems(dict_)))
示例#23
0
def unique(iterable, key=None):
    """Removes duplicates from given iterable, using given key as criterion.

    :param key: Key function which returns a hashable,
                uniquely identifying an object.

    :return: Iterable with duplicates removed
    """
    ensure_iterable(iterable)
    key = hash if key is None else ensure_callable(key)

    def generator():
        seen = set()
        for elem in iterable:
            k = key(elem)
            if k not in seen:
                seen.add(k)
                yield elem

    return generator()
示例#24
0
 def test_lambda(self):
     func = lambda : self.fail("lambda must not be actually called")
     __unit__.ensure_callable(func)
示例#25
0
 def test_few_builtins(self):
     __unit__.ensure_callable(open)
     __unit__.ensure_callable(min)
     __unit__.ensure_callable(sum)
     __unit__.ensure_callable(str.__add__)
示例#26
0
 def __init__(self, getter):
     ensure_callable(getter)
     self.getter = getter
示例#27
0
def try_(block, except_=None, else_=None, finally_=None):
    """Emulate a ``try`` block.

    :param block: Function to be executed within the ``try`` statement
    :param except_: Function to execute when an :class:`Exception` occurs.
                    It receives a single argument: the exception object.
                    Alternatively, a list of key-value pairs can be passed,
                    mapping exception types to their handler functions.
    :param else_: Function to execute when ``block`` completes successfully.
                  Note that it requires ``except_`` to be provided as well
    :param finally_: Function to execute at the end,
                     regardless of whether an exception occurred or not

    :return:  If no exception was raised while executing ``block``,
              the result of ``else_`` (if provided) or ``block`` is returned.
              Otherwise, the result of ``except_`` is returned.

    Note that :func:`try_` can _still_ raise an exception if it occurs
    while evaluating ``except_``, ``else_`` or ``finally_`` functions.
    """
    ensure_callable(block)
    if not (except_ or else_ or finally_):
        raise TypeError("at least one of `except_`, `else_` or `finally_` "
                        "functions must be provided")
    if else_ and not except_:
        raise TypeError("`else_` can only be provided along with `except_`")

    if except_:
        if callable(except_):
            except_ = [(Exception, except_)]
        else:
            ensure_iterable(except_)
            if is_mapping(except_):
                ensure_ordered_mapping(except_)
                except_ = except_.items()

        def handle_exception():
            """Dispatch current exception to proper handler in ``except_``."""
            exc_type, exc_object = sys.exc_info()[:2]
            for t, handler in except_:
                if issubclass(exc_type, t):
                    return handler(exc_object)
            raise

        if else_:
            ensure_callable(else_)
            if finally_:
                ensure_callable(finally_)
                try:
                    block()
                except:
                    return handle_exception()
                else:
                    return else_()
                finally:
                    finally_()
            else:
                try:
                    block()
                except:
                    return handle_exception()
                else:
                    return else_()
        else:
            if finally_:
                ensure_callable(finally_)
                try:
                    return block()
                except:
                    return handle_exception()
                finally:
                    finally_()
            else:
                try:
                    return block()
                except:
                    return handle_exception()
    elif finally_:
        ensure_callable(finally_)
        try:
            return block()
        finally:
            finally_()
示例#28
0
 def test_some_object(self):
     with self.assertRaises(TypeError):
         __unit__.ensure_callable(object())
示例#29
0
文件: algorithms.py 项目: Xion/taipan
def topological_order(nodes, incoming):
    """Performs topological sort of a DAG-like structure
    (directed acyclic graph).

    :param nodes: Collection of nodes
    :param incoming: Function taking node as an argument and returning iterable
                     of nodes with edges pointing _towards_ given one

    :return: Iterable of nodes in the topological order

    .. note::

        ``incoming`` function works in _reverse_ to the typical adjacency
        relation in graphs: if ``A in incoming(B)``, it implies that ``A->B``
        is among the graph edges (**not** ``B->A``!).

        This reversal is useful in practice when dealing with graphs
        representing dependencies, module imports, header includes, and so on.

    Example::

        for package in topological_order(packages, attr_func('dependencies')):
            install(package)

    .. versionadded:: 0.0.4
    """
    ensure_iterable(nodes) ; ensure_countable(nodes)
    ensure_callable(incoming)

    # data structure for tracking node's visit state
    NOT_VISITED, VISITING, VISITED = range(3)
    visit_states = {}
    visit_state = lambda node: visit_states.get(id(node), NOT_VISITED)

    def visit(node):
        """Topological sort visitor function."""
        if visit_state(node) == VISITING:
            raise ValueError("cycle found on node %r" % (node,))
        if visit_state(node) == NOT_VISITED:
            visit_states[id(node)] = VISITING
            for neighbor in incoming(node):
                for n in visit(neighbor):
                    yield n
            visit_states[id(node)] = VISITED
            yield node

    def generator():
        """Main generator function that loops through the nodes
        until we've visited them all.
        """
        visited_count = 0
        while visited_count < len(nodes):
            visited_count = 0
            for node in nodes:
                if visit_state(node) == VISITED:
                    visited_count += 1
                else:
                    for n in visit(node):
                        yield n

    return generator()
示例#30
0
 def test_string(self):
     with self.assertRaises(TypeError):
         __unit__.ensure_callable("foo")
示例#31
0
文件: constructs.py 项目: Xion/taipan
def try_(block, except_=None, else_=None, finally_=None):
    """Emulate a ``try`` block.

    :param block: Function to be executed within the ``try`` statement
    :param except_: Function to execute when an :class:`Exception` occurs.
                    It receives a single argument: the exception object.
                    Alternatively, a list of key-value pairs can be passed,
                    mapping exception types to their handler functions.
    :param else_: Function to execute when ``block`` completes successfully.
                  Note that it requires ``except_`` to be provided as well
    :param finally_: Function to execute at the end,
                     regardless of whether an exception occurred or not

    :return:  If no exception was raised while executing ``block``,
              the result of ``else_`` (if provided) or ``block`` is returned.
              Otherwise, the result of ``except_`` is returned.

    Note that :func:`try_` can _still_ raise an exception if it occurs
    while evaluating ``except_``, ``else_`` or ``finally_`` functions.
    """
    ensure_callable(block)
    if not (except_ or else_ or finally_):
        raise TypeError("at least one of `except_`, `else_` or `finally_` "
                        "functions must be provided")
    if else_ and not except_:
        raise TypeError("`else_` can only be provided along with `except_`")

    if except_:
        if callable(except_):
            except_ = [(Exception, except_)]
        else:
            ensure_iterable(except_)
            if is_mapping(except_):
                ensure_ordered_mapping(except_)
                except_ = except_.items()

        def handle_exception():
            """Dispatch current exception to proper handler in ``except_``."""
            exc_type, exc_object = sys.exc_info()[:2]
            for t, handler in except_:
                if issubclass(exc_type, t):
                    return handler(exc_object)
            raise

        if else_:
            ensure_callable(else_)
            if finally_:
                ensure_callable(finally_)
                try:
                    block()
                except:
                    return handle_exception()
                else:
                    return else_()
                finally:
                    finally_()
            else:
                try:
                    block()
                except:
                    return handle_exception()
                else:
                    return else_()
        else:
            if finally_:
                ensure_callable(finally_)
                try:
                    return block()
                except:
                    return handle_exception()
                finally:
                    finally_()
            else:
                try:
                    return block()
                except:
                    return handle_exception()
    elif finally_:
        ensure_callable(finally_)
        try:
            return block()
        finally:
            finally_()
示例#32
0
 def test_lambda(self):
     func = lambda: self.fail("lambda must not be actually called")
     __unit__.ensure_callable(func)
示例#33
0
 def test_few_builtins(self):
     __unit__.ensure_callable(open)
     __unit__.ensure_callable(min)
     __unit__.ensure_callable(sum)
     __unit__.ensure_callable(str.__add__)
示例#34
0
    def test_function(self):
        def func():
            self.fail("function must not be actually called")

        __unit__.ensure_callable(func)
示例#35
0
    def test_class(self):
        class Foo(object):
            def __init__(self_):
                self.fail("class must not be actually instantiated")

        __unit__.ensure_callable(Foo)
示例#36
0
    def test_callable_object(self):
        class Foo(object):
            def __call__(self_):
                self.fail("object must not be actually called")

        __unit__.ensure_callable(Foo())
示例#37
0
 def test_string(self):
     with self.assertRaises(TypeError):
         __unit__.ensure_callable("foo")
示例#38
0
 def test_number(self):
     with self.assertRaises(TypeError):
         __unit__.ensure_callable(42)
示例#39
0
 def test_number(self):
     with self.assertRaises(TypeError):
         __unit__.ensure_callable(42)
示例#40
0
 def test_callable_object(self):
     class Foo(object):
         def __call__(self_):
             self.fail("object must not be actually called")
     __unit__.ensure_callable(Foo())
示例#41
0
文件: functions.py 项目: Xion/taipan
 def call(obj):
     member_func = ensure_callable(get_member_func(obj))
     return member_func(*args, **kwargs)
示例#42
0
 def test_class(self):
     class Foo(object):
         def __init__(self_):
             self.fail("class must not be actually instantiated")
     __unit__.ensure_callable(Foo)
示例#43
0
 def test_none(self):
     with self.assertRaises(TypeError):
         __unit__.ensure_callable(None)
示例#44
0
 def test_function(self):
     def func():
         self.fail("function must not be actually called")
     __unit__.ensure_callable(func)
示例#45
0
def merge(arg, *rest, **kwargs):
    """Merge a collection, with functions as items, into a single function
    that takes a collection and maps its items through corresponding functions.

    :param arg: A collection of functions, such as list, tuple, or dictionary
    :param default: Optional default function to use for items
                    within merged function's arguments that do not have
                    corresponding functions in ``arg``

    Example with two-element tuple::

        >> dict_ = {'Alice': -5, 'Bob': 4}
        >> func = merge((str.upper, abs))
        >> dict(map(func, dict_.items()))
        {'ALICE': 5, 'BOB': 4}

    Example with a dictionary::

        >> func = merge({'id': int, 'name': str.split})
        >> data = [
            {'id': '1', 'name': "John Doe"},
            {'id': '2', 'name': "Anne Arbor"},
        ]
        >> list(map(func, data))
        [{'id': 1, 'name': ['John', 'Doe']},
         {'id': 2, 'name': ['Anne', 'Arbor']}]

    :return: Merged function

    .. versionadded:: 0.0.2
    """
    ensure_keyword_args(kwargs, optional=('default', ))

    has_default = 'default' in kwargs
    if has_default:
        default = ensure_callable(kwargs['default'])

    # if more than one argument was given, they must all be functions;
    # result will be a function that takes multiple arguments (rather than
    # a single collection) and returns a tuple
    unary_result = True
    if rest:
        fs = (ensure_callable(arg), ) + tuple(imap(ensure_callable, rest))
        unary_result = False
    else:
        fs = arg

    if is_mapping(fs):
        if has_default:
            return lambda arg_: fs.__class__(
                (k, fs.get(k, default)(arg_[k])) for k in arg_)
        else:
            return lambda arg_: fs.__class__((k, fs[k](arg_[k])) for k in arg_)
    else:
        ensure_sequence(fs)
        if has_default:
            # we cannot use ``izip_longest(fs, arg_, fillvalue=default)``,
            # because we want to terminate the generator
            # only when ``arg_`` is exhausted (not when just ``fs`` is)
            func = lambda arg_: fs.__class__((fs[i]
                                              if i < len(fs) else default)(x)
                                             for i, x in enumerate(arg_))
        else:
            # we cannot use ``izip(fs, arg_)`` because it would short-circuit
            # if ``arg_`` is longer than ``fs``, rather than raising
            # the required ``IndexError``
            func = lambda arg_: fs.__class__(fs[i](x)
                                             for i, x in enumerate(arg_))
        return func if unary_result else lambda *args: func(args)
示例#46
0
文件: properties.py 项目: Xion/taipan
 def __init__(self, getter):
     ensure_callable(getter)
     self.getter = getter