Skip to content

pyutils

tuprolog.pyutils

Pure-Python helpers used throughout the tuprolog package.

They let factories accept their arguments in several shapes (e.g. theory(c1, c2) as well as theory([c1, c2])), and compose functions with post-processing steps. None of them needs the JVM.

register_single_value_type

register_single_value_type(cls: type) -> None

Makes iterable_or_varargs treat the instances of cls as single values.

Strings and bytes are single values out of the box, although they are iterable; packages register their own iterable value types, e.g. logic lists, which must not be split into their items when passed as the only argument of a factory.

Parameters:

Name Type Description Default
cls type

The type whose instances are single values.

required

iterable_or_varargs

iterable_or_varargs(
    args: Sequence[Any],
    dispatch: Callable[[Iterable[Any]], Any] = lambda x: (
        x
    ),
) -> Any

Accepts items given either as several arguments or as one iterable.

It lets a function with signature f(*items) be called both as f(a, b) and as f([a, b]).

Parameters:

Name Type Description Default
args Sequence[Any]

The positional arguments received, i.e. items in f(*items).

required
dispatch Callable[[Iterable[Any]], Any]

The function to call with the items (the identity, unless given).

lambda x: x

Returns:

Type Description
Any

What dispatch returns when given the items: the only argument, if it is an iterable but

Any

not a single value (see register_single_value_type); the only argument wrapped in a

Any

list, if it is not iterable; or all the arguments, otherwise.

Examples:

>>> iterable_or_varargs((1, 2, 3))
(1, 2, 3)
>>> iterable_or_varargs(([1, 2, 3],))
[1, 2, 3]
>>> iterable_or_varargs(("abc",), list)
['abc']

dict_or_keyword_args

dict_or_keyword_args(
    dictionary: Mapping[str, _T],
    kwargs: Mapping[str, _T],
    dispatch: Callable[
        [Mapping[str, _T]], Any
    ] = lambda x: x,
) -> Any

Accepts key-value pairs given as a mapping, as keyword arguments, or both.

It lets a function with signature f(dictionary={}, **kwargs) be called as f({"a": 1}), as f(a=1), or as f({"a": 1}, b=2).

Parameters:

Name Type Description Default
dictionary Mapping[str, _T]

The pairs given as a mapping.

required
kwargs Mapping[str, _T]

The pairs given as keyword arguments, overriding those in dictionary.

required
dispatch Callable[[Mapping[str, _T]], Any]

The function to call with the merged pairs (the identity, unless given).

lambda x: x

Returns:

Type Description
Any

What dispatch returns when given a new dictionary of all the pairs.

Examples:

>>> dict_or_keyword_args({"a": 1, "b": 2}, {"b": 3})
{'a': 1, 'b': 3}

and_then

and_then(
    continuation: Callable[[Any], Any],
) -> Callable[[Callable], Callable]

Creates a decorator post-processing the results of the decorated function.

Parameters:

Name Type Description Default
continuation Callable[[Any], Any]

The function the results are passed to.

required

Returns:

Type Description
Callable[[Callable], Callable]

The decorator: the decorated function returns continuation(result) instead of result.

Examples:

>>> @and_then(list)
... def numbers(n):
...     return range(n)
>>> numbers(3)
[0, 1, 2]

apply_to_result

apply_to_result(
    consumer: Callable[[Any], Any],
) -> Callable[[Callable], Callable]

Creates a decorator passing the results of the decorated function to a consumer, too.

Unlike and_then, the decorated function still returns its own results.

Parameters:

Name Type Description Default
consumer Callable[[Any], Any]

The function the results are passed to, whose own results are ignored.

required

Returns:

Type Description
Callable[[Callable], Callable]

The decorator.

Examples:

>>> log = []
>>> @apply_to_result(log.append)
... def double(x):
...     return 2 * x
>>> double(21), log
(42, [42])