attr_utils
Utilities to augment attrs.
Docs |
|
---|---|
Tests |
|
PyPI |
|
Anaconda |
|
Activity |
|
QA |
|
Other |
Installation
python3 -m pip install attr_utils --user
First add the required channels
conda config --add channels https://conda.anaconda.org/conda-forge
conda config --add channels https://conda.anaconda.org/domdfcoding
Then install
conda install attr_utils
python3 -m pip install git+https://github.com/domdfcoding/attr_utils@master --user
Attention
In v0.6.0 and above the pprinter
module requires the pprint
extra to be installed:
python -m pip install attr-utils[pprint]
Overview
attr_utils
provides both utility functions and two Sphinx extensions: attr_utils.annotations
and attr_utils.autoattrs
.
Enable the extensions by adding the following to the extensions
variable in your conf.py
:
extensions = [
...
'sphinx.ext.autodoc',
'sphinx_toolbox.more_autodoc.typehints',
'attr_utils.annotations',
'attr_utils.autoattrs',
]
For more information see https://www.sphinx-doc.org/en/master/usage/extensions#third-party-extensions .
Contents
Demo
This example shows the output from attr_utils.annotations
and attr_utils.autoattrs
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | """ This example is based on real code. """ # stdlib from typing import Any, Dict, List, Optional, Sequence, Tuple, Union, overload # 3rd party import attr from domdf_python_tools.utils import strtobool # this package from attr_utils.annotations import attrib from attr_utils.pprinter import pretty_repr from attr_utils.serialise import serde @pretty_repr @serde @attr.s(slots=True) class Device: """ Represents a device in an :class:`~.AcqMethod`. """ #: The ID of the device device_id: str = attr.ib(converter=str) #: The display name for the device. display_name: str = attr.ib(converter=str) rc_device: bool = attr.ib(converter=strtobool) """ Flag to indicate the device is an RC Device. If :py:obj:`False` the device is an SCIC. """ #: List of key: value mappings for configuration options. configuration: List[Dict[str, Any]] = attr.ib(converter=list, factory=list) #: Alternative form of ``configuration``. configuration2: Tuple[Dict[str, Any]] = attr.ib( converter=tuple, default=attr.Factory(tuple), ) #: Alternative form of ``configuration``. configuration3: List[Dict[str, Any]] = attr.ib( converter=list, default=attr.Factory(list), metadata={"annotation": Sequence[Dict[str, Any]]}, ) #: Alternative form of ``configuration``. configuration4: List[Dict[str, Any]] = attrib( converter=list, factory=list, annotation=Sequence[Dict[str, Any]], ) @overload def __getitem__(self, item: int) -> str: ... @overload def __getitem__(self, item: slice) -> List[str]: ... def __getitem__(self, item: Union[int, slice]) -> Union[str, List[str]]: """ Return the item with the given index. :param item: :rtype: .. versionadded:: 1.2.3 """ @attr.s(init=False) class Connector: """ Represents an electrical connector. :param name: The name of the connector. :param n_pins: The number if pins. For common connectors this is inferred from the name. :param right_angle: Whether this is a right angle connector. """ #: The name of the connector name: str = attr.ib(converter=str) #: The number of pins n_pins: int = attr.ib(converter=int) def __init__(self, name: str, n_pins: Optional[int] = None, right_angle: bool = False): if name == "DA-15": n_pins = 15 elif name == "DB-25": n_pins = 25 elif name == "DE-15": n_pins = 15 self.__attrs_init__(name, n_pins) |
.. autoattrs:: demo.Device
:autosummary:
-
class
Device
(device_id, display_name, rc_device, configuration=[], configuration2=(), configuration3=[], configuration4=[])[source] Bases:
object
Represents a device in an
AcqMethod
.- Parameters
device_id (
str
) – The ID of the devicedisplay_name (
str
) – The display name for the device.rc_device (
Union
[str
,int
]) – Flag to indicate the device is an RC Device. IfFalse
the device is an SCIC.configuration (
List
[Dict
[str
,Any
]]) – List of key: value mappings for configuration options. Default[]
.configuration2 (
Tuple
[Dict
[str
,Any
]]) – Alternative form ofconfiguration
. Default()
.configuration3 (
Sequence
[Dict
[str
,Any
]]) – Alternative form ofconfiguration
. Default[]
.configuration4 (
Sequence
[Dict
[str
,Any
]]) – Alternative form ofconfiguration
. Default[]
.
Methods:
__eq__
(other)Return
self == other
.__ge__
(other)Return
self >= other
.__getitem__
(item)Return the item with the given index.
__getstate__
()Used for pickling.
__gt__
(other)Return
self > other
.__le__
(other)Return
self <= other
.__lt__
(other)Return
self < other
.__ne__
(other)Return
self != other
.__repr__
()Return a string representation of the
Device
.__setstate__
(state)Used for pickling.
from_dict
(d)Construct an instance of
Device
from a dictionary.to_dict
([convert_values])Returns a dictionary containing the contents of the
Device
object.Attributes:
List of key: value mappings for configuration options.
Alternative form of
configuration
.Alternative form of
configuration
.Alternative form of
configuration
.The ID of the device
The display name for the device.
Flag to indicate the device is an RC Device.
-
__getitem__
(item)[source] Return the item with the given index.
- Parameters
- Return type
- Overloads
__getitem__
(item:int
) ->str
__getitem__
(item:slice
) ->List
[str
]
New in version 1.2.3.
attr_utils.annotations
Add type annotations to the __init__
of an attrs class.
Since python-attrs/attrs#363python-attrs/attrs#363 attrs has
populated the __init__.__annotations__
based on the types of attributes.
However, annotations were deliberately omitted when converter functions were used.
This module attempts to generate the annotations for use in Sphinx documentation,
even when converter functions are used, based on the following assumptions:
If the converter function is a Python
type
, such asstr
,int
, orlist
, the type annotation will be that type. If the converter and the type annotation refer to the same type (e.g.list
andtyping.List
) the type annotation will be used.If the converter function has an annotation for its first argument, that annotation is used.
If the converter function is not annotated, the type of the attribute will be used.
The annotation can also be provided via the 'annotation'
key in the
metadata dict.
If you prefer you can instead provide this as a keyword argument to attrib()
which will construct the metadata dict and call attr.ib()
for you.
Changed in version 0.2.0: Improved support for container types.
Attention
Due to changes in the typing
module annotations
is only officially supported on Python 3.7 and above.
Examples
Library Usage:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | def my_converter(arg: List[Dict[str, Any]]): return arg def untyped_converter(arg): return arg @attr.s class SomeClass: a_string: str = attr.ib(converter=str) custom_converter: Any = attr.ib(converter=my_converter) untyped: Tuple[str, int, float] = attr.ib(converter=untyped_converter) annotated: List[str] = attr.ib( converter=list, metadata={"annotation": Sequence[str]}, ) add_attrs_annotations(SomeClass) print(SomeClass.__init__.__annotations__) # { # 'return': None, # 'a_string': <class 'str'>, # 'custom_converter': typing.List[typing.Dict[str, typing.Any]], # 'untyped': typing.Tuple[str, int, float], # } |
Sphinx documentation:
@attr.s
class AttrsClass:
"""
Example of using :func:`~.add_init_annotations` for attrs_ classes with Sphinx documentation.
.. _attrs: https://www.attrs.org/en/stable/
:param name: The name of the person.
:param age: The age of the person.
:param occupations: The occupation(s) of the person.
"""
name: str = attr.ib(converter=str)
age: int = attr.ib(converter=int)
occupations: List[str] = attr.ib(converter=parse_occupations)
The parse_occupations
function looks like:
def parse_occupations(occupations: Iterable[str]) -> Iterable[str]: # pragma: no cover
if isinstance(occupations, str):
return [x.strip() for x in occupations.split(',')]
else:
return [str(x) for x in occupations]
The Sphinx output looks like:
API Reference
Functions:
|
Wrapper around |
|
Add type annotations to the |
|
Hook for |
|
Sphinx extension to populate |
Data:
Invariant |
|
Invariant |
-
attrib
(default=NOTHING, validator=None, repr=True, hash=None, init=True, metadata=None, annotation=NOTHING, converter=None, factory=None, kw_only=False, eq=None, order=None, **kwargs)[source] Wrapper around
attr.ib()
which supports theannotation
keyword argument for use byadd_init_annotations()
.New in version 0.2.0.
- Parameters
default – Default
NOTHING
.validator – Default
None
.hash – Default
None
.init – Default
True
.metadata – Default
None
.annotation (
Union
[Type
,object
]) – The type to add to__init__.__annotations__
, if different to that the type taken as input to the converter function or the type hint of the attribute. DefaultNOTHING
.converter – Default
None
.factory – Default
None
.eq – Default
None
.order – Default
None
.
See the documentation for
attr.ib()
for descriptions of the other arguments.
-
_A
= TypeVar(_A, bound=typing.Any) Type:
TypeVar
Invariant
TypeVar
bound totyping.Any
.
-
_C
= TypeVar(_C, bound=typing.Callable) Type:
TypeVar
Invariant
TypeVar
bound totyping.Callable
.
-
add_init_annotations
(obj)[source] Add type annotations to the
__init__
method of an attrs class.- Return type
-
attr_docstring_hook
(obj)[source] Hook for
sphinx_toolbox.more_autodoc.typehints
to add annotations to the__init__
method of attrs classes.
attr_utils.autoattrs
Sphinx directive for documenting attrs classes.
New in version 0.1.0.
Attention
Due to changes in the typing
module autoattrs
is only officially supported on Python 3.7 and above.
Attention
This module has the following additional requirements:
sphinx<7,>=3.2.0 sphinx-toolbox>=3.3.0
These can be installed as follows:
python -m pip install attr-utils[sphinx]
-
.. autoattrs::
Autodoc directive to document an attrs class.
It behaves much like
autoclass
. It can be used directly or as part ofautomodule
.Docstrings for parameters in
__init__
can be given in the class docstring or alongside each attribute (seeautoattribute
for the syntax). The second option is recommended as it interacts better with other parts of autodoc. However, the class docstring can be used to override the description for a given parameter.-
:no-init-attribs:
(flag) Excludes attributes taken as arguments in
__init__
from the output, even if they are documented.This may be useful for simple classes where converter functions aren’t used.
This option cannot be used as part of
automodule
.
-
API Reference
Classes:
|
Sphinx autodoc |
Functions:
|
Setup |
-
class
AttrsDocumenter
(*args)[source] Bases:
PatchedAutoSummClassDocumenter
Sphinx autodoc
Documenter
for documenting attrs classes.Changed in version 0.3.0:Parameters for
__init__
can be documented either in the class docstring or alongside the attribute. The class docstring has priority.Added support for autodocsumm.
Methods:
can_document_member
(member, membername, …)Called to see if a member can be documented by this documenter.
add_content
(more_content[, no_docstring])Add extra content (from docstrings, attribute docs etc.), but not the class docstring.
import_object
([raiseerror])Import the object given by
self.modname
andself.objpath
and set it asself.object
.sort_members
(documenters, order)Sort the given member list and add attribute docstrings to the class docstring.
filter_members
(members, want_all)Filter the list of members to always include init attributes unless the
:no-init-attribs:
flag was given.generate
([more_content, real_modname, …])Generate reST for the object given by
self.name
, and possibly for its members.-
classmethod
can_document_member
(member, membername, isattr, parent)[source] Called to see if a member can be documented by this documenter.
-
add_content
(more_content, no_docstring=False)[source] Add extra content (from docstrings, attribute docs etc.), but not the class docstring.
-
import_object
(raiseerror=False)[source] Import the object given by
self.modname
andself.objpath
and set it asself.object
.If the object is an attrs class
attr_utils.docstrings.add_attrs_doc()
will be called.
-
sort_members
(documenters, order)[source] Sort the given member list and add attribute docstrings to the class docstring.
-
filter_members
(members, want_all)[source] Filter the list of members to always include init attributes unless the
:no-init-attribs:
flag was given.
-
generate
(more_content=None, real_modname=None, check_module=False, all_members=False)[source] Generate reST for the object given by
self.name
, and possibly for its members.- Parameters
more_content (
Optional
[Any
]) – Additional content to include in the reST output. DefaultNone
.real_modname (
Optional
[str
]) – Module name to use to find attribute documentation. DefaultNone
.check_module (
bool
) – IfTrue
, only generate if the object is defined in the module name it is imported from. DefaultFalse
.all_members (
bool
) – IfTrue
, document all members. DefaultFalse
.
-
setup
(app)[source] Setup
attr_utils.autoattrs
.- Parameters
app (
Sphinx
)- Return type
attr_utils.docstrings
Add better docstrings to attrs generated functions.
Data:
Invariant |
Functions:
|
Add better docstrings to attrs generated functions. |
-
_T
= TypeVar(_T, bound=typing.Type) Type:
TypeVar
Invariant
TypeVar
bound totyping.Type
.
attr_utils.mypy_plugin
Plugin for mypy which adds support for attr_utils.
New in version 0.4.0.
To use this plugin, add the following to your mypy configuration file:
[mypy] plugins=attr_utils.mypy_plugin
See https://mypy.readthedocs.io/en/stable/extending_mypy.html#configuring-mypy-to-use-plugins for more information.
Classes:
Plugin for mypy which adds support for |
Functions:
|
Adds a new classmethod to a class definition. |
|
Handles |
|
Entry point to |
-
add_classmethod_to_class
(api, cls, name, args, return_type, cls_type=None, tvar_def=None)[source] Adds a new classmethod to a class definition.
-
attr_utils_serialise_serde
(cls_def_ctx)[source] Handles
attr_utils.serialise.serde()
.- Parameters
cls_def_ctx (
ClassDefContext
)
-
plugin
(version)[source] Entry point to
attr_utils.mypy_plugin
.- Parameters
version (
str
) – The current mypy version.
attr_utils.pprinter
Pretty printing functions.
This module monkeypatches prettyprinter to disable a potentially undesirable behaviour of its singledispatch feature, where deferred types took precedence over resoled types.
It also changes the pretty print output for an enum.Enum
to be the same as the
Enum
's __repr__
.
Attention
This module has the following additional requirement:
prettyprinter==0.18.0
This can be installed as follows:
python -m pip install attr-utils[pprint]
Classes:
|
Data:
Invariant |
Functions:
|
Add a pretty-printing |
|
Returns a decorator that registers the decorated function as the pretty printer for instances of |
-
protocol
PrettyFormatter
[source] Bases:
Protocol
typing.Protocol
representing the pretty formatting functions decorated byregister_pretty()
.New in version 0.6.0.
This protocol is runtime checkable.
Classes that implement this protocol must have the following methods / attributes:
-
_PF
= TypeVar(_PF, bound=PrettyFormatter) Type:
TypeVar
Invariant
TypeVar
bound toattr_utils.pprinter.PrettyFormatter
.
-
pretty_repr
(obj)[source] Add a pretty-printing
__repr__
function to the decorated attrs class.>>> import attr >>> from attr_utils.pprinter import pretty_repr >>> @pretty_repr ... @attr.s ... class Person(object): ... name = attr.ib() >>> repr(Person(name="Bob")) Person(name='Bob')
- Parameters
obj (
Type
)
-
register_pretty
(type=None, predicate=None)[source] Returns a decorator that registers the decorated function as the pretty printer for instances of
type
.- Parameters
type (
Union
[Type
,str
,None
]) – The type to register the pretty printer for, or astr
to indicate the module and name, e.g.'collections.Counter'
. DefaultNone
.predicate (
Optional
[Callable
[[Any
],bool
]]) – A predicate function that takes one argument and returns a boolean indicating if the value should be handled by the registered pretty printer. DefaultNone
.
Only one of
type
andpredicate
may be supplied, and thereforepredicate
will only be called for unregistered types.Here’s an example of the pretty printer for
collections.OrderedDict
:from collections import OrderedDict from attr_utils.pprinter import register_pretty from prettyprinter import pretty_call @register_pretty(OrderedDict) def pretty_orderreddict(value, ctx): return pretty_call(ctx, OrderedDict, list(value.items()))
attr_utils.serialise
Add serialisation and deserialisation capability to attrs classes.
Based on attrs-serde.
Example usage
>>> import attr
>>> from attr_utils.serialise import serde
>>> person_dict = {"contact": {"personal": {"name": "John"}, "phone": "555-112233"}}
>>> name_path = ["contact", "personal", "name"]
>>> phone_path = ["contact", "phone"]
>>> @serde
... @attr.s
... class Person(object):
... name = attr.ib(metadata={"to": name_path, "from": name_path})
... phone = attr.ib(metadata={"to": phone_path, "from": phone_path})
>>> p = Person.from_dict(person_dict)
Person(name=John phone=555-112233)
>>> p.to_dict
{"contact": {"personal": {"name": "John"}, "phone": "555-112233"}}
API Reference
-
serde
(cls=None, from_key='from', to_key='to')[source] Decorator to add serialisation and deserialisation capabilities to attrs classes.
The keys used in the dictionary output, and used when creating the class from a dictionary, can be controlled using the
metadata
argument inattr.ib()
:from attr_utils.serialize import serde import attr @serde @attr.s class Person(object): name = attr.ib(metadata={"to": name_path, "from": name_path}) phone = attr.ib(metadata={"to": phone_path, "from": phone_path})
The names of the keys given in the
metadata
argument can be controlled with thefrom_key
andto_key
arguments:from attr_utils.serialize import serde import attr @serde(from_key="get", to_key="set") @attr.s class Person(object): name = attr.ib(metadata={"get": name_path, "set": name_path}) phone = attr.ib(metadata={"get": phone_path, "set": phone_path})
This may be required when using other extensions to attrs.
- Parameters
- Return type
Union
[Type
[AttrsClass
],Callable
[[Type
[AttrsClass
]],Type
[AttrsClass
]]]- Overloads
Classes decorated with
@serde
will have two new methods added:-
classmethod
from_dict
(d) Construct an instance of the class from a dictionary.
-
to_dict(convert_values=False):
Returns a dictionary containing the contents of the class.
- Parameters
convert_values (
bool
) – Recurse into other attrs classes, and convert tuples, sets etc. into lists. This may be required to later construct a new class from the dictionary if the class uses complex converter functions.- Return type
Changed in version 0.5.0: By default values are left unchanged. In version 0.4.0 these were converted to basic Python types, which may be undesirable. The original behaviour can be restored using the
convert_values
parameter.
Contributing
attr_utils
uses tox to automate testing and packaging,
and pre-commit to maintain code quality.
Install pre-commit
with pip
and install the git hook:
python -m pip install pre-commit
pre-commit install
Coding style
formate is used for code formatting.
It can be run manually via pre-commit
:
pre-commit run formate -a
Or, to run the complete autoformatting suite:
pre-commit run -a
Automated tests
Tests are run with tox
and pytest
.
To run tests for a specific Python version, such as Python 3.6:
tox -e py36
To run tests for all Python versions, simply run:
tox
Build documentation locally
The documentation is powered by Sphinx. A local copy of the documentation can be built with tox
:
tox -e docs
Downloading source code
The attr_utils
source code is available on GitHub,
and can be accessed from the following URL: https://github.com/domdfcoding/attr_utils
If you have git
installed, you can clone the repository with the following command:
git clone https://github.com/domdfcoding/attr_utils
Cloning into 'attr_utils'...
remote: Enumerating objects: 47, done.
remote: Counting objects: 100% (47/47), done.
remote: Compressing objects: 100% (41/41), done.
remote: Total 173 (delta 16), reused 17 (delta 6), pack-reused 126
Receiving objects: 100% (173/173), 126.56 KiB | 678.00 KiB/s, done.
Resolving deltas: 100% (66/66), done.

Downloading a ‘zip’ file of the source code
Building from source
The recommended way to build attr_utils
is to use tox:
tox -e build
The source and wheel distributions will be in the directory dist
.
If you wish, you may also use pep517.build or another PEP 517-compatible build tool.
License
attr_utils
is licensed under the MIT License
A short and simple permissive license with conditions only requiring preservation of copyright and license notices. Licensed works, modifications, and larger works may be distributed under different terms and without source code.
Permissions | Conditions | Limitations |
---|---|---|
|
|
Copyright (c) 2020 Dominic Davis-Foster
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
OR OTHER DEALINGS IN THE SOFTWARE.
View the Function Index or browse the Source Code.