Create instances of Python dataclasses with the builder pattern.
Documentation for PyRADS can be found at https://dataclass-builder.readthedocs.io/en/latest/ or in PDF and Epub formats.
- Python 3.6 or greater
- dataclasses if using Python 3.6
dataclass-builder is on PyPI so the easiest way to install it is:
$ pip install dataclass-builder
There are two ways to use dataclass-builder. Via a builder instance or by creating a dedicated builder. The latter is recommended when repeated building of a given dataclass is desired or when docstrings and type checking are important.
Using specialized builders allows for better documentation than the DataclassBuilder wrapper.
from dataclasses import dataclass
from dataclass_builder import (dataclass_builder, build, fields, update
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)
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'
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']
If the underlying dataclass has a field named fields this method will not be generated and instead the fields function should be used instead.
An already built dataclass can be updated with a partially completed builder using the update
function.
>>> point = Point(x=5.8, y=8.1, w=100)
>>> update(point, PointBuilder(y=1.1))
>>> point
Point(x=5.8, y=1.1, w=100)
Dataclass builders can also be updated, but frozen dataclasses cannot.
Using a builder instance is the fastest way to get started with the dataclass-builder package.
from dataclasses import dataclass
from dataclass_builder import (DataclassBuilder, build, fields,
REQUIRED, OPTIONAL)
@dataclass
class Point:
x: float
y: float
w: float = 1.0
Now we can build a point.
>>> builder = DataclassBuilder(Point)
>>> builder.x = 5.8
>>> builder.y = 8.1
>>> builder.w = 2.0
>>> build(builder)
Point(x=5.8, y=8.1, w=2.0)
Field values can also be provided in the constructor.
>>> builder = DataclassBuilder(Point, x=5.8, w=100)
>>> builder.y = 8.1
>>> build(builder)
Point(x=5.8, y=8.1, w=100)
Note
Positional arguments are not allowed, except for the dataclass itself.
Fields with default values in the dataclass are optional in the builder.
>>> builder = DataclassBuilder(Point)
>>> builder.x = 5.8
>>> builder.y = 8.1
>>> build(builder)
Point(x=5.8, y=8.1, w=1.0)
Fields that don't have default values in the dataclass are not optional.
>>> builder = DataclassBuilder(Point)
>>> builder.y = 8.1
>>> build(builder)
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 = DataclassBuilder(Point)
>>> builder.x
REQUIRED
>>> builder.w
OPTIONAL
The fields function 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(fields(builder).keys())
['x', 'y', 'w']
>>> [f.type.__name__ for f in fields(builder).values()]
['float', 'float', 'float']
A subset of the fields can be also be retrieved, for instance, to only get required fields:
>>> list(fields(builder, optional=False).keys())
['x', 'y']
or only the optional fields.
>>> list(fields(builder, required=False).keys())
['w']