The Essentials

starstar.divide(kw: dict, *funcs: Callable | Iterable[Callable], mode='strict', varkw: bool = True)[source]

Divide **kwargs between multiple functions based on their signatures.

Parameters:
  • *funcs (callable) – The functions you want to divide arguments amongst.

  • mode (str) –

    How to handle extra keyword arguments.

    • 'separate': Add them as an extra dictionary at the end.

    • 'strict': If there are extra keyword arguments, raise a TypeError. This will only raise if no function with a variable keyword is found or varkw == False.

  • varkw (bool | 'first') – Do we want to pass extra arguments as **kwargs to any function that accepts them? By default (True), they will go to all functions with variable keyword arguments. If 'first' they will only go to the first matching function. If False, no function will get variable keyword args.

Returns:

A dict for each function provided, plus one more for unused kwargs if mode == 'separate'.

Raises:

TypeError – if mode='strict' (default) and it receives arguments that don’t appear in any function’s signature. Does not apply if any function takes **kw.

Pass arguments to multiple functions!

def func_a(a=None, b=None, c=None):
    return a, b, c

def func_b(d=None, e=None, f=None):
    return d, e, f

def main(**kw):
    kw_a, kw_b = starstar.divide(kw, func_a, func_b)
    func_a(**kw_a)
    func_b(**kw_b)

# and it even works for nested functions !

def func_c(**kw):
    kw_a, kw_b = starstar.divide(kw, func_a, func_b)
    func_a(**kw_a)
    func_b(**kw_b)

def func_d(g=None, h=None, i=None):
    return g, h, i

def main(**kw):
    kw_c, kw_d = starstar.divide(kw, (func_a, func_b), func_d)
    func_c(**kw_c)
    func_d(**kw_d)

Decide how you want to handle extra keyword args.

main(a=1, x=2)  # extra argument "x"
# divide raises TypeError

def main(**kw):
    kw_a, kw_b, kw_extra = starstar.divide(kw, func_a, func_b, mode='separate')

main(a=1, x=2)  # extra argument "x"
# gets put in ``kw_extra``
starstar.traceto(*funcs: Callable, keep_varkw=None, filter_hidden=True, doc=False) Callable[source]

Tell a function where its **kwargs are going!

This is similar to functools.wraps, except that it merges the signatures of multiple functions and only deals with arguments that can be passed as keyword arguments.

Parameters:
  • *funcs (callable) – The functions where the keyword arguments go.

  • keep_varkw (bool) – Whether we should keep **kw in the signature. If not set, this will be True if any of the passed arguments take variable kwargs.

  • filter_hidden (bool) – Whether we should filter out arguments starting with an underscore. Default True. This is often used for private arguments for example in the case of recursive functions that pass objects internally.

  • doc (bool) – Whether to merge the docstrings. Defaults to False.

By having func_c trace its **kwargs signature, main can say that it’s passing its arguments to func_c and it will be able to see the parameters of func_a & func_b.

@starstar.traceto(func_a, func_b)
def func_c(**kw):
    kw_a, kw_b = starstar.divide(kw, func_a, func_b)
    func_a(**kw_a)
    func_b(**kw_b)

@starstar.traceto(func_c, func_d)
def main(**kw):
    kw_c, kw_d = starstar.divide(kw, func_c, func_d)
    func_c(**kw_c)
    func_d(**kw_d)
starstar.wraps(func: Callable, skip_args=(), skip_n=0) Callable[source]

functools.wraps, except that it merges the signature.

Note

functools.wraps doesn’t do any function introspection. This means that if the wrapper function adds any arguments to the function signature, these arguments won’t be documented.

If you’re not familiar with functools.wraps, it is a decorator that renames a wrapper function and its signature to look like the function that it’s wrapping.

# without wrapping

def print_output(func):
    def inner(*a, print_output=True, **kw):
        output = func(*a, **kw)
        if print_output:
            print(output)
        return output
    return inner

@print_output
def something(a, b):
    return a+b

assert something.__name__ == 'inner'

# with wrapping

def print_output(func):
    @starstar.wraps(func)
    def inner(*a, print_output=True, **kw):
        output = func(*a, **kw)
        if print_output:
            print(output)
        return output
    return inner

@print_output
def something(a, b):
    return a+b

assert something.__name__ == 'something'

Argument Filtering

starstar.filtered(func)[source]

A decorator that filters out any extra kwargs passed to a function. See starstar.filter for more information.

@starstar.filtered
def func_a(a, b, c): pass

func_a(1, 2, c=3, x=1, y=2)  # just gonna ignore x and y

# using the decorator is equivalent to
func_a(*a, **starstar.filter_kw(func_a, kw))
starstar.filter_kw(func, kw, skip_n=0, pop=False, inverse=False, unmatched=False, include_varkw=True)[source]

Filter **kwargs down to only those that appear in the function signature.

Parameters:
  • func (callable) – The function to filter using.

  • kw – keyword arguments that you’d like to filter.

  • pop (bool) – Remove matched keys from kw.

  • inverse (bool) – Return keys not in function signature.

  • include_varkw (bool) – if a function takes **kw, should it swallow all arguments? default True.

Returns:

the filtered kwargs

Return type:

(dict)

def func_a(a, b, c):
    pass

args = {'b': 2, 'c': 3, 'x': 1, 'y': 2}
assert starstar.filter_kw(func_a, args) == {'b': 2, 'c': 3}