dataclass_builder.factory module

Create dataclasses.dataclass() builders for specific dataclasses.

This module uses a factory to build builder classes that build a specific dataclass. These builder classes implement the builder pattern and allow constructing dataclasses over a period of time instead of all at once.

Examples

Using specialized builders allows for better documentation than the DataclassBuilder wrapper and allows for type checking because annotations are dynamically generated.

from dataclasses import dataclass
from dataclass_builder import (dataclass_builder, build, fields,
                               REQUIRED, OPTIONAL)

@dataclass
class Point:
    x: float
    y: float
    w: float = 1.0

PointBuilder = dataclass_builder(Point)

Now we can build a point.

>>> builder = PointBuilder()
>>> builder.x = 5.8
>>> builder.y = 8.1
>>> builder.w = 2.0
>>> build(builder)
Point(x=5.8, y=8.1, w=2.0)

As long as the dataclass the builder was constructed for does not have a build field then a build method will be generated as well.

>>> builder.build()
Point(x=5.8, y=8.1, w=2.0)

Field values can also be provided in the constructor.

>>> builder = PointBuilder(x=5.8, w=100)
>>> builder.y = 8.1
>>> builder.build()
Point(x=5.8, y=8.1, w=100)

Note

Positional arguments are not allowed.

Fields with default values in the dataclass are optional in the builder.

>>> builder = PointBuilder()
>>> builder.x = 5.8
>>> builder.y = 8.1
>>> builder.build()
Point(x=5.8, y=8.1, w=1.0)

Fields that don’t have default values in the dataclass are not optional.

>>> builder = PointBuilder()
>>> builder.y = 8.1
>>> builder.build()
Traceback (most recent call last):
...
MissingFieldError: field 'x' of dataclass 'Point' is not optional

Fields not defined in the dataclass cannot be set in the builder.

>>> builder.z = 3.0
Traceback (most recent call last):
...
UndefinedFieldError: dataclass 'Point' does not define field 'z'

Note

No exception will be raised for fields beginning with an underscore as they are reserved for use by subclasses.

Accessing a field of the builder before it is set gives either the REQUIRED or OPTIONAL constant

>>> builder = PointBuilder()
>>> builder.x
REQUIRED
>>> builder.w
OPTIONAL

The fields method can be used to retrieve a dictionary of settable fields for the builder. This is a mapping of field names to dataclasses.Field objects from which extra data can be retrieved such as the type of the data stored in the field.

>>> list(builder.fields().keys())
['x', 'y', 'w']
>>> [f.type.__name__ for f in builder.fields().values()]
['float', 'float', 'float']

A subset of the fields can be also be retrieved, for instance, to only get required fields:

>>> list(builder.fields(optional=False).keys())
['x', 'y']

or only the optional fields.

>>> list(builder.fields(required=False).keys())
['w']

Note

If the underlying dataclass has a field named fields this method will not be generated and instead the fields() function should be used instead.

dataclass_builder.factory.dataclass_builder(dataclass: Type[Any], *, name: Optional[str] = None) → Type[Any][source]

Create a new builder class specialized to a given dataclass.

Parameters
  • dataclass – The dataclasses.dataclass() to create the builder for.

  • name – Override the name of the builder, by default it will be ‘<dataclass>Builder’ where <dataclass> is replaced by the name of the dataclass.

Return object

A new dataclass builder class that is specialized to the given dataclass. If the given dataclasses.dataclass() does not contain the fields build or fields these will be exposed as public methods with the same signature as the dataclass_builder.utility.build() and dataclass_builder.utility.fields() functions respectively.

Raises

TypeError – If dataclass is not a dataclasses.dataclass(). This is decided via dataclasses.is_dataclass().