funcutils - functools fixes

Python’s built-in functools module builds several useful utilities on top of Python’s first-class function support. funcutils generally stays in the same vein, adding to and correcting Python’s standard metaprogramming facilities.

Decoration

Decorators are among Python’s most elegant and succinct language features, and boltons adds one special function to make them even more powerful.

boltons.funcutils.wraps(func, injected=None, **kw)[source]

Modeled after the built-in functools.wraps(), this function is used to make your decorator’s wrapper functions reflect the wrapped function’s:

  • Name
  • Documentation
  • Module
  • Signature

The built-in functools.wraps() copies the first three, but does not copy the signature. This version of wraps can copy the inner function’s signature exactly, allowing seamless usage and introspection. Usage is identical to the built-in version:

>>> from boltons.funcutils import wraps
>>>
>>> def print_return(func):
...     @wraps(func)
...     def wrapper(*args, **kwargs):
...         ret = func(*args, **kwargs)
...         print(ret)
...         return ret
...     return wrapper
...
>>> @print_return
... def example():
...     '''docstring'''
...     return 'example return value'
>>>
>>> val = example()
example return value
>>> example.__name__
'example'
>>> example.__doc__
'docstring'

In addition, the boltons version of wraps supports modifying the outer signature based on the inner signature. By passing a list of injected argument names, those arguments will be removed from the outer wrapper’s signature, allowing your decorator to provide arguments that aren’t passed in.

Parameters:
  • func (function) – The callable whose attributes are to be copied.
  • injected (list) – An optional list of argument names which should not appear in the new wrapper’s signature.
  • update_dict (bool) – Whether to copy other, non-standard attributes of func over to the wrapper. Defaults to True.
  • inject_to_varkw (bool) – Ignore missing arguments when a **kwargs-type catch-all is present. Defaults to True.

For more in-depth wrapping of functions, see the FunctionBuilder type, on which wraps was built.

Function construction

Functions are so key to programming in Python that there will even arise times where Python functions must be constructed in Python. Thankfully, Python is a dynamic enough to make this possible. Boltons makes it easy.

class boltons.funcutils.FunctionBuilder(name, **kw)[source]

The FunctionBuilder type provides an interface for programmatically creating new functions, either based on existing functions or from scratch.

Values are passed in at construction or set as attributes on the instance. For creating a new function based of an existing one, see the from_func() classmethod. At any point, get_func() can be called to get a newly compiled function, based on the values configured.

>>> fb = FunctionBuilder('return_five', doc='returns the integer 5',
...                      body='return 5')
>>> f = fb.get_func()
>>> f()
5
>>> fb.varkw = 'kw'
>>> f_kw = fb.get_func()
>>> f_kw(ignored_arg='ignored_val')
5

Note that function signatures themselves changed quite a bit in Python 3, so several arguments are only applicable to FunctionBuilder in Python 3. Except for name, all arguments to the constructor are keyword arguments.

Parameters:
  • name (str) – Name of the function.
  • doc (str) – Docstring for the function, defaults to empty.
  • module (str) – Name of the module from which this function was imported. Defaults to None.
  • body (str) – String version of the code representing the body of the function. Defaults to 'pass', which will result in a function which does nothing and returns None.
  • args (list) – List of argument names, defaults to empty list, denoting no arguments.
  • varargs (str) – Name of the catch-all variable for positional arguments. E.g., “args” if the resultant function is to have *args in the signature. Defaults to None.
  • varkw (str) – Name of the catch-all variable for keyword arguments. E.g., “kwargs” if the resultant function is to have **kwargs in the signature. Defaults to None.
  • defaults (dict) – A mapping of argument names to default values.
  • kwonlyargs (list) – Argument names which are only valid as keyword arguments. Python 3 only.
  • kwonlydefaults (dict) – A mapping, same as normal defaults, but only for the kwonlyargs. Python 3 only.
  • annotations (dict) – Mapping of type hints and so forth. Python 3 only.
  • filename (str) – The filename that will appear in tracebacks. Defaults to “boltons.funcutils.FunctionBuilder”.
  • indent (int) – Number of spaces with which to indent the function body. Values less than 1 will result in an error.
  • dict (dict) – Any other attributes which should be added to the functions compiled with this FunctionBuilder.

All of these arguments are also made available as attributes which can be mutated as necessary.

classmethod from_func(func)[source]

Create a new FunctionBuilder instance based on an existing function. The original function will not be stored or modified.

get_defaults_dict()[source]

Get a dictionary of function arguments with defaults and the respective values.

get_func(execdict=None, add_source=True, with_dict=True)[source]

Compile and return a new function based on the current values of the FunctionBuilder.

Parameters:
  • execdict (dict) – The dictionary representing the scope in which the compilation should take place. Defaults to an empty dict.
  • add_source (bool) – Whether to add the source used to a special __source__ attribute on the resulting function. Defaults to True.
  • with_dict (bool) – Add any custom attributes, if applicable. Defaults to True.

To see an example of usage, see the implementation of wraps().

remove_arg(arg_name)[source]

Remove an argument from this FunctionBuilder’s argument list. The resulting function will have one less argument per call to this function.

Parameters:arg_name (str) – The name of the argument to remove.

Raises a ValueError if the argument is not present.

Improved partial

boltons.funcutils.partial

alias of CachedInstancePartial

class boltons.funcutils.InstancePartial[source]

functools.partial is a huge convenience for anyone working with Python’s great first-class functions. It allows developers to curry arguments and incrementally create simpler callables for a variety of use cases.

Unfortunately there’s one big gap in its usefulness: methods. Partials just don’t get bound as methods and automatically handed a reference to self. The InstancePartial type remedies this by inheriting from functools.partial and implementing the necessary descriptor protocol. There are no other differences in implementation or usage. CachedInstancePartial, below, has the same ability, but is slightly more efficient.

class boltons.funcutils.CachedInstancePartial[source]

The CachedInstancePartial is virtually the same as InstancePartial, adding support for method-usage to functools.partial, except that upon first access, it caches the bound method on the associated object, speeding it up for future accesses, and bringing the method call overhead to about the same as non-partial methods.

See the InstancePartial docstring for more details.

Miscellaneous metaprogramming

boltons.funcutils.copy_function(orig, copy_dict=True)[source]

Returns a shallow copy of the function, including code object, globals, closure, etc.

>>> func = lambda: func
>>> func() is func
True
>>> func_copy = copy_function(func)
>>> func_copy() is func
True
>>> func_copy is not func
True
Parameters:
  • orig (function) – The function to be copied. Must be a function, not just any method or callable.
  • copy_dict (bool) – Also copy any attributes set on the function instance. Defaults to True.
boltons.funcutils.dir_dict(obj, raise_exc=False)[source]

Return a dictionary of attribute names to values for a given object. Unlike obj.__dict__, this function returns all attributes on the object, including ones on parent classes.

boltons.funcutils.mro_items(type_obj)[source]

Takes a type and returns an iterator over all class variables throughout the type hierarchy (respecting the MRO).

>>> sorted(set([k for k, v in mro_items(int) if not k.startswith('__') and 'bytes' not in k and not callable(v)]))
['denominator', 'imag', 'numerator', 'real']