bagof-magic
Classes that build themselves from your type hints.
Write your fields as annotations. Magic generates __init__, __repr__,
__eq__, and everything else.
from bagof.magic import Magic
class Point(Magic, frozen=True):
x: float
y: float
>>> Point(1.0, 2.0)
Point(x=1.0, y=2.0)
>>> Point(1.0, 2.0) == Point(1.0, 2.0)
True
>>> Point(1.0, 2.0).x = 3.0
Traceback (most recent call last):
AttributeError: Cannot set frozen field 'x'
If you prefer a decorator:
=== "Base class"
```python
from bagof.magic import Magic
class Point(Magic, frozen=True):
x: float
y: float
```
=== "Decorator"
```python
from bagof.magic import magic
@magic(frozen=True)
class Point:
x: float
y: float
```
What sets it apart
- Settings are class keyword arguments, and subclasses inherit them. Set
frozen=Trueon a base once; every subclass keeps it, and can override just the settings it needs to change. See Settings. - Per-field behaviour lives in the annotation, not in a
field()call:tags: Factory[list],token: NoRepr[str] = "". See Field annotations. - Conversion and validation come from the type hint, opt in per class or
per field.
Config("localhost", "9000")becomesport=9000because the hint saysint. See Conversion and validation. - A class can build one of its own subclasses, chosen from the arguments it's called with. See Building the right subclass.
- A field can accept several input names, and expose forwarding properties under other names. See Input aliases and forwarding properties.
- Also included: dict-like instances,
replace/asdict/astuple, mutable defaults that aren't shared, hooks around construction, generic classes, and docstrings generated from the fields. See Extras.
How it compares
Close to attrs in spirit, with pydantic's habit of doing real work from your type hints, and inheritance where the others use decorators.
| dataclasses | attrs | pydantic | magic | |
|---|---|---|---|---|
| settings inherited by subclasses | no | no | yes | yes |
| per-field behaviour in the annotation | no | no | partly | yes |
| conversion from the type hint | no | partly | yes | yes |
| validation from the type hint | no | partly | yes | yes |
| dict-like instances | no | no | partly | yes |
| no methods added unless asked | yes | yes | no | yes |
There is a fuller side-by-side in the comparison page.
Settings
class Thing(Magic, frozen=True, kw_only=True, slots=True):
...
| Setting | Default | What it does |
|---|---|---|
init |
True |
generate __init__ |
repr |
True |
generate __repr__ |
eq |
True |
generate __eq__ |
order |
False |
generate the comparisons |
hash |
None |
generate __hash__; decides for itself by default |
unsafe_hash |
False |
generate one even when the class is mutable |
frozen |
False |
refuse assignment after construction |
match_args |
False |
support structural pattern matching |
kw_only |
False |
every field must be passed by name |
positional_only |
False |
every field must be passed by position |
slots |
False |
use __slots__, and drop __dict__ |
weakref_slot |
False |
allow weak references under slots |
convert |
False |
convert every field from its type |
validate |
False |
check every field against its type |
convert_defaults |
True |
convert a value that came from a default, too |
validate_defaults |
True |
check a value that came from a default, too |
unresolved_hints |
"warn" |
what to do when a type hint still names something undefined the first time a field needs it; or "raise", or "ignore" |
factory |
False |
build every missing default from its type |
mutable_default |
"factory" |
give each instance its own copy of x: list = []; or "raise", or "allow" |
alias |
default public name | input names; True includes enabled property names, False keeps underscores |
property |
False |
forwarding attributes; True or "readonly" exposes the public name, "all" every input alias |
mapping |
False |
behave like a dictionary; a subclass inherits the methods and cannot turn them off |
override |
False |
apply this class's settings to inherited fields too |
polymorphic |
False |
build one of this class's subclasses, chosen from the arguments; or "strict", which refuses to build this class when none of them matches |
pin_discriminant |
"pin" |
what a subclass does with the field it matches on; or "classvar", or "keep" |
reverse |
False |
list a subclass's own fields before inherited ones |
doc |
True |
add the field table to the class docstring |
Most of them also accept a string instead of True, which binds the
generated method under that name. This is useful when you want to call the
generated method from your own.
See Settings for how they're inherited and how to override them.
Install
pip install git+https://github.com/bagofseeds/bagof-magic.git
Python 3.8 and later.
Status
Early. The API is settling, and things may still move. Issues and ideas are welcome at bagofseeds/bagof-magic.
Metadata
Release files for bagof-magic 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| bagof_magic-0.2.1.tar.gz | 167.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| bagof_magic-0.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 267.1 kB
Release files / bagof_magic-0.2.1.tar.gz
| Download URL | bagof_magic-0.2.1.tar.gz |
|---|---|
| Size | 167.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
13cda551293afbf6b02169e80a9f677becd4d83b4667695a0465477856801545
|
|
BLAKE2b-256 checksum How to use checksums |
abd87ce9f94e6b7aa3ee82fb69622f5027fba61a35d391869a3ca0c71de3c189
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / bagof_magic-0.2.1-py3-none-any.whl
| Download URL | bagof_magic-0.2.1-py3-none-any.whl |
|---|---|
| Size | 99.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b3d5f7f0615dbd9e462f615b4dbacb48523871e97b248e9bd5e5633b69057fe1
|
|
BLAKE2b-256 checksum How to use checksums |
7eb4025d70e382287264cd79c8e4fb0cae545b7b94d27d6f3fef0fdac832b8be
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|