Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

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=True on 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") becomes port=9000 because the hint says int. 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.
  • A required field can follow one with a default, so a subclass can add one to a base whose fields all have defaults. See Field annotations.
  • 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__; a test such as HideIfNone() applies to every field
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; also "classvar", "keep", or any of those with +narrow (and "narrow" = "pin+narrow") to narrow its type and reject other values; a field's own Pin[T, mode] wins over it
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.3.dev1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for bagof-magic 0.3.dev1
File Size Uploaded
bagof_magic-0.3.dev1.tar.gz 206.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for bagof-magic 0.3.dev1
File Interpreter ABI Platform
bagof_magic-0.3.dev1-py3-none-any.whl Python 3 none any Details

Total release size: 323.4 kB

Release files / bagof_magic-0.3.dev1.tar.gz

Download URL bagof_magic-0.3.dev1.tar.gz
Size 206.4 kB
Tags Source
SHA-256 checksum
How to use checksums
dd5ba40ee1db85a915d32b6ffdf1dd0a62cb356e606a7c4c3547da3555fe5760
BLAKE2b-256 checksum
How to use checksums
21cf36c289aa3011aace4591511f56d0b9e34f693ca17a50678f6ece815c36e1
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.3.dev1-py3-none-any.whl

Download URL bagof_magic-0.3.dev1-py3-none-any.whl
Size 116.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3e60b0006e757424afd7af7aa36947659ac3e4733daf663d56541c0fdb833721
BLAKE2b-256 checksum
How to use checksums
0af6d77da0a54f0bf84fd20af5b809378c8e15033a84d0ccc71b2c8671bef5cb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page