Source code for pypersist.preprocessing

"""Code to produce a key from a list of arguments to a function.

When a function decorated with `@persist` is called, its `key` function is
called on the arguments to produce a key that corresponds to those arguments.
If the user does not specify a custom `key` function, then we fall back to a
default function that produces a tuple from the arguments; this tuple should be
in a standard form that ignores functionally irrelevant features such as the
ordering of keyword arguments.  The `arg_tuple` function in this module
produces this normalised tuple.

"""

from sys import version_info

PYTHON_VERSION = version_info[0]  # major version number

if PYTHON_VERSION >= 3:
    from inspect import getfullargspec
else:
    from inspect import getargspec as getfullargspec


[docs]def arg_tuple(func, *args, **kwargs): """Return a normalised tuple of arguments from args and kwargs This function checks that `func(*args, **kwargs)` is a valid function call, then converts all the non-keyword arguments to keyword arguments. It then discards any supplied arguments that are equal to their default values (since they are unnecessary) and finally it sorts the arguments into alphabetical order by name. The arguments are then retuend as a tuple of tuples, where each tuple is a pair containing the name of the argument followed by the value given. If `func` takes a variable number of arguments, any unnamed arguments will be included as a list with a name beginning with an asterisk. Parameters ---------- func : function Function such that `func(*args, **kwargs)` is a valid call. args : list List of non-keyword arguments to be passed to `func`. kwargs : dict Dictionary of keyword arguments to be passed to `func`. Examples -------- Tuple of arguments to built-in function `len`: >>> len("hello world") 11 >>> arg_tuple(len, "hello world") (('obj', 'hello world'),) Tuple of arguments to user-defined function, with default argument being discarded: >>> def sum_of_three(x, a, m=2): ... return x + a + m >>> sum_of_three(10, m=2, a=15) 27 >>> arg_tuple(sum_of_three, 10, m=2, a=15) (('a', 15), ('x', 10)) """ kwargs = kwargs.copy() spec = getfullargspec(func) # Check for too many arguments if len(args) > len(spec.args): if spec.varargs is None: func(*args, **kwargs) # throws TypeError with useful message else: kwargs["*" + spec.varargs] = args[len(spec.args) :] # add varargs # Convert args to kwargs kwargs.update(dict(zip(spec.args, args))) # Remove any default arguments if spec.defaults is not None: for (arg, val) in zip(spec.args[-len(spec.defaults) :], spec.defaults): if kwargs.get(arg) == val: kwargs.pop(arg) if hasattr(spec, "kwonlydefaults") and spec.kwonlydefaults is not None: for arg in spec.kwonlydefaults: if kwargs.get(arg) == spec.kwonlydefaults[arg]: kwargs.pop(arg) # Return as a tuple out = tuple(sorted(kwargs.items())) return out