"""Contain functions."""
from contextlib import contextmanager
from functools import partial, reduce
from operator import (
lt, le, eq, ne, ge, gt,
add, sub, truediv, floordiv, mul, matmul, mod, pow, neg, pos,
contains, concat,
and_, or_, xor, not_, truth,
invert, lshift, rshift,
is_, is_not,
setitem, getitem, delitem,
iadd,
) # noqa: F401
[docs]def vartial(func, *args, **keywords):
"""
Prepare a function with args and kwargs except for the first arg.
Functions like `functools.partial` except that the resulting
preprepared function expects the first positional argument.
Example
-------
>>> pow2 = vartial(math.pow, 2)
>>> pow2(3)
9
>>> pow2(4)
16
This is different from:
>>> pow_base_3 = partial(math.pow, 3)
>>> pow_base_3(2)
9
>>> pow_base_3(4)
81
"""
def newfunc(value, *fargs, **fkeywords):
# newkeywords = {**keywords, **fkeywords}
newkeywords = keywords.copy()
newkeywords.update(fkeywords)
return func(value, *args, *fargs, **newkeywords)
newfunc.func = func
newfunc.args = args
newfunc.keywords = keywords
return newfunc
[docs]def give(value):
"""
Preare a function to return a value when called.
Ignore `*args` and `**kwargs`.
Example
-------
>>> true = give(True)
>>> true()
True
>>> five = give(5)
>>> five(4, 6, 7, 8, some_args='some string')
5
"""
def newfunc(*ignore, **everything):
return value
newfunc.value = value
return newfunc
# predefined set ups
true = give(True)
false = give(False)
none = give(None)
[docs]def pass_(value):
"""
Do nothing, just pass the value.
Example
-------
>>> pass_(1)
1
"""
return value
[docs]def f1f2(f1, f2, *a, **k):
"""
Apply one function after the other.
Call `f1` on the return value of `f2`.
Args and kwargs apply to `f2`.
Example
-------
>>> f1f2(str, int, 2)
"2"
"""
return f1(f2(*a, **k))
[docs]def f2f1(f1, f2, *a, **k):
"""
Apply the second function after the first.
Call `f2` on the return value of `f1`.
Args and kwargs apply to `f1`.
Example
-------
>>> f2f1(str, int, 2)
2
"""
return f2(f1(*a, **k))
[docs]def ternary_operator(iflogic, assertion, elselogic):
"""
Apply ternary operator logic executing functions.
Functions should be preconfigured and accept no arguments.
Better if you see the code:
`return iflogic() if assertion() else elselogic()`
"""
return iflogic() if assertion() else elselogic()
[docs]def ternary_operator_v(x, iflogic, assertion, elselogic):
"""
Apply ternary operator logic executing functions.
Functions should receive a single value: `x`.
Better if you see the code:
`return iflogic(x) if assertion(x) else elselogic(x)`
Parameters
----------
x
The value to pass to each function.
"""
return iflogic(x) if assertion(x) else elselogic(x)
[docs]def make_iterable(value):
"""
Transform into an iterable.
Transforms a given `value` into an iterable if it is not.
Else, return the value itself.
Example
-------
>>> make_iterable(1)
[1]
>>> make_iterable([1])
[1]
"""
try:
iter(value)
except TypeError:
return [value]
else:
return value
[docs]def reduce_helper(value, f, *a, **k):
"""
Help in `reduce`.
Helper function when applying `reduce` to a list of functions.
Parameters
----------
value : anything
f : callable
The function to call. This function receives `value` as first
positional argument.
*a, **k
Args and kwargs passed to `f`.
"""
return f(value, *a, **k)
[docs]def chainf(init, *funcs):
"""
Run functions in sequence starting from an initial value.
Example
-------
>>> chainf(2, [str, int, float])
2.0
"""
return reduce(reduce_helper, funcs, init)
[docs]def chainfs(*funcs):
"""
Store functions be executed on a value.
Example
-------
>>> do = chainfs(str, int, float)
>>> do(2)
2.0
"""
def execute(value):
return chainf(value, *funcs)
return execute
[docs]def if_elif_else(value, condition_function_pair):
"""
Apply logic if condition is True.
Parameters
----------
value : anything
The initial value
condition_function_pair : tuple
First element is the assertion function, second element is the
logic function to execute if assertion is true.
Returns
-------
The result of the first function for which assertion is true.
"""
for condition, func in condition_function_pair:
if condition(value):
return func(value)
[docs]def whileloop(cond, func, do_stopiteration=none, do_exhaust=none):
"""
Execute while loop.
All function accept no arguments. If state needs to be evaluated,
`cond` and `func` need to be synchronized.
Parameters
----------
cond : callable
The `while` loop condition.
func : callable
The function to call on each while loop iteration.
do_stopiteration : callable
The function to execute when `func` raises StopIteration error.
do_exhaust : callable
The function to execute when while loop exhausts.
Return
------
None
"""
while cond():
try:
func()
except StopIteration:
do_stopiteration()
return
do_exhaust()
return
[docs]def consume(gen):
"""
Consume generator in a single statement.
Example
-------
>>> consume(generator)
"""
for _ in gen:
pass
[docs]def mapc(f, *iterables):
"""
Consume map function.
Like `map()` but it is not a generator; `map` is consumed
immediately.
"""
return consume(map(f, *iterables))
[docs]def flatlist(list_):
"""
Flat a list recursively.
This is a generator.
"""
# escape strings which would yield infinite recursion
if isinstance(list_, str):
yield list_
else:
try:
for sublist in list_:
yield from flatlist(sublist)
except TypeError: # sublist is not iterable
yield sublist
[docs]def raise_(exception, *ignore, **everything):
"""Raise exception."""
raise exception
[docs]@contextmanager
def context_engine(
func,
exceptions,
doerror,
doelse,
dofinally,
*args,
**kwargs):
"""Make a context engine."""
try:
result = func(*args, **kwargs)
except (exceptions) as err:
doerror(err, *args, **kwargs)
else:
yield result
doelse(result, *args, **kwargs)
finally:
dofinally(*args, **kwargs)
# If Then Else
ite = ternary_operator
itev = ternary_operator_v
# conditionals
is_none = partial(is_, None)
is_not_none = partial(is_not, None)
# To deprecate in version 1
ITE = ternary_operator
ITEX = ternary_operator_v
ternary_operator_x = ternary_operator_v
# chainfs, can be replaced with vartial(chainf, f1, f2, f3)