bagof.magic._fields
Attributes
REQUIRED
module-attribute
REQUIRED = REQUIRED
A default that says the field has none.
Written as the default of a field that inherits, as in x: ... = REQUIRED,
it removes the default the field inherited, so the field has to be passed.
PIN
module-attribute
PIN: Literal['pin'] = 'pin'
Give the field the value the subclass stands for, as its default.
CLASSVAR
module-attribute
CLASSVAR: Literal['classvar'] = 'classvar'
Make the field a class attribute that holds the value.
An argument for the field is still accepted, and dropped.
PIN_NARROW
module-attribute
PIN_NARROW: Literal['pin+narrow'] = 'pin+narrow'
Like PIN, and also refuse any other value for the field.
CLASSVAR_NARROW
module-attribute
CLASSVAR_NARROW: Literal['classvar+narrow'] = 'classvar+narrow'
Like CLASSVAR, and also refuse any other value for the field.
KEEP_NARROW
module-attribute
KEEP_NARROW: Literal['keep+narrow'] = 'keep+narrow'
Like KEEP, and also refuse any other value for the field.
Classes
Field
Bases: SlotsBase
A single field in a Magic class.
Every annotation in a Magic class body becomes a Field. A Field
is rarely created directly: the annotation family, such as
Factory, KwOnly and ConvertTo, and the field()
function are the usual ways to declare one.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
The field's name in the class body. |
required |
type
|
type or type hint
|
The field's type, from which the converter, the validator and the default factory are worked out when those are turned on. |
required |
default
|
any
|
The default value. |
required |
factory
|
bool or Callable[[], any]
|
How a fresh default is built for each instance, instead of
one value being shared between instances. |
`Options().factory`
|
init
|
bool
|
Whether the field is a parameter of |
required |
repr
|
bool or Callable[[any], any]
|
Whether the field is shown in the generated |
True
|
hash
|
bool
|
Whether the field counts towards the generated |
None (follows `eq`)
|
eq
|
bool or Callable[[any, any], bool]
|
Whether the field counts towards the generated |
True
|
order
|
bool
|
Whether the field counts towards the generated ordering
methods. A field left out of |
follows `eq`
|
metadata
|
dict
|
Arbitrary user-defined metadata. |
required |
kw
|
bool
|
Whether the field may be passed by keyword. Together with
|
`not Options().positional_only`
|
positional
|
bool
|
Whether the field may be passed by position. Together with
|
`not Options().kw_only`
|
frozen
|
bool
|
Forbid assignment after construction. |
`Options().frozen`
|
converter
|
bool or Callable[[any], any]
|
How an incoming value is converted. |
`Options().convert`
|
validator
|
bool or Callable[[any], any]
|
How an incoming value is validated, in the same three forms
as |
`Options().validate`
|
var
|
bool
|
False
|
|
doc
|
str
|
The field's documentation, which can also be given with the
|
required |
key
|
bool | str | ShowIf | tuple
|
Whether the field is a key of the dict-like interface. A
string is used as the key name. A test such as
|
`Options().mapping`
|
alias
|
str | sequence[str] | bool
|
The input name, or the input names in order of preference.
The first name is used in the signature, in the repr and as
the mapping key. By default the field is known by its own
name without any leading underscore. |
required |
property
|
str | sequence[str] | mapping | bool
|
Forwarding attributes. A name or a sequence of names creates
properties that can be read and written. A mapping chooses
|
False
|
pin
|
str or bool
|
What a subclass that matches on this field does with it.
When it is left out, each such subclass uses its own
|
required |
inherit
|
bool or str
|
How the field relates to a field the class inherits. |
required |
position
|
bool
|
Read only when the field inherits, that is when |
True
|
Other Parameters:
| Name | Type | Description |
|---|---|---|
compare |
bool
|
A shorthand that sets both |
kw_only |
bool
|
The |
default_factory |
Callable[[], any]
|
The |
Raises:
| Type | Description |
|---|---|
TypeError
|
If a keyword that is not listed here is given, or if both
|
Attributes
init
property
writable
init: bool
Whether the generated __init__ takes this field.
The property is computed from kw and positional. It is
True when the field can be passed by keyword, by position or
both, and False when it can be passed neither way.
Assigning True or False to field.init sets both kw and
positional to that value. Field(init=False), like NoInit,
forbids both ways, while Field(init=True), like Init, changes
nothing, since a field is a parameter by default.
convert
property
convert: bool
Whether an incoming value is converted.
The property reads converter. It is True for a converter
worked out from the type and for a callable given directly, and
False when conversion is off. Conversion is set through
converter, or through the convert= keyword when the field is
built.
validate
property
validate: bool
Whether an incoming value is validated.
The property reads validator, in the same way that convert
reads converter.
build
property
build: bool
Whether a fresh default is built for this field for each instance.
The property reads factory, in the same way that convert
reads converter.
aliases
property
aliases: tuple[str, ...]
The accepted input names, with the preferred public name first.
properties
property
A copy of the forwarding attribute names and their access modes.
public_key
property
public_key: str | None
The key of this field in the generated dict-like interface.
Methods:
Alias
Bases: AnnotatedField
Accept one or more input names for a field, in order of preference.
Alias[str, ("label", "name")] accepts either keyword, and label
is preferred. Alias[str] adds the names of the field's enabled
properties.
Property
Bases: AnnotatedField
Expose forwarding attributes for a stored field.
Property[str, "label"] makes label an attribute that reads and
writes the field, and Property[str, {"label": "readonly"}] makes
it read-only. A sequence of names gives every name read and write
access. Without names, the preferred public name is exposed, and
Property[str, "all"] exposes every input alias that the field
accepts.
ReadOnlyProperty
Bases: Property
Expose read-only forwarding attributes for a stored field.
ReadOnlyProperty is the read-only counterpart of Property:
ReadOnlyProperty[str, names] exposes the same attributes as
Property[str, names], but forbids assignment through them.
ReadOnlyProperty[str, "label"] reads the field through label.
Without names, the preferred public name is exposed, and
ReadOnlyProperty[str, "all"] exposes every input alias.
Default
Factory
Bases: AnnotatedField
Build a field's default by calling a factory, once for each instance.
A factory suits any mutable default, because every instance receives its own object. Without an argument, the factory is worked out from the field's type.
How it lowers
In a class
ConvertTo
Bases: AnnotatedField
Convert whatever is passed in to the field's type.
Without an argument, the converter is worked out from the type. A callable given as the argument is used as the converter instead.
How it lowers
In a class
Validate
Bases: AnnotatedField
Reject a value that does not match the field's type.
Without an argument, the check is worked out from the type. A
callable given as the argument is used as the validator instead.
Unlike ConvertTo, Validate leaves the value exactly as it was
given.
How it lowers
In a class
Init
Bases: BoolAnnotatedField
Include a field in the generated __init__, or leave it out.
NoInit lets a field be passed neither by name nor by position. The
field still exists and takes its default or factory value, but it
cannot be passed to the constructor.
Init says the opposite, which is already true of every field
unless something says otherwise. It therefore changes nothing, and
it serves to state the intent explicitly. How the field may be
passed is still decided by the class, or by Kw and
Positional.
How it lowers
NoInit
Kw
Bases: BoolAnnotatedField
Allow a field to be passed by keyword, or forbid it.
Together with Positional, Kw says exactly how a field may be
passed. KwOnly and PositionalOnly are the two useful
combinations, ready-made, and forbidding both ways is NoInit.
How it lowers
NotKw
Positional
Bases: BoolAnnotatedField
Allow a field to be passed by position, or forbid it.
Together with Kw, Positional says exactly how a field may be
passed. PositionalOnly and KwOnly are the two useful
combinations, ready-made.
How it lowers
NotPositional
Bases: Positional, InversedBoolAnnotatedField
Forbid passing a field by position.
x: NotPositional[int] can still be passed by keyword, unless
something forbids that too. It is the opposite of Positional.
KwOnly
Bases: Kw, NotPositional
Make a field keyword-only.
x: KwOnly[int] can be passed by name but not by position, as with
field(kw_only=True). It combines Kw with
NotPositional.
NotKwOnly
Bases: Positional
Let a field be passed by position as well as by keyword.
x: NotKwOnly[int] undoes a keyword-only setting, such as
kw_only=True on the class, and leaves passing by keyword as it
was. It is the same as Positional.
PositionalOnly
Bases: Positional, NotKw
Make a field positional-only.
x: PositionalOnly[int] can be passed by position but not by name.
It combines Positional with NotKw.
NotPositionalOnly
Frozen
Bases: BoolAnnotatedField
Forbid assignment to a field after the object is built.
Frozen freezes part of an otherwise mutable class.
How it lowers
In a class
NotFrozen
Var
Bases: BoolAnnotatedField
Declare a pseudo-field, which is not stored on each instance.
An InitVar is passed to __init__ and used, but not kept. It
reaches __pre_init__ and __post_init__ like any other argument.
A ClassVar is a plain class attribute, shared by every
instance and absent from __init__.
How it lowers
In a class
InitVar
ClassVar
Repr
Bases: BoolAnnotatedField
Show a field in the generated __repr__, hide it, or choose how.
Besides True and False, a field's repr setting can be a function
of the value, and the function's result decides what is shown:
- a string is shown as the value's text, in place of
repr(value); NoneorFalsehides the field;True, or anything else that is true, showsrepr(value);- anything else that is false hides the field.
A function can therefore either format the value or decide whether
the field is shown. ShowIf, HideIf, HideIfNone and
HideIfDefault are ready-made functions of the second kind.
How it lowers
In a class
Formatting the value
NoRepr
ShowIf
Bases: Repr
Show a field in __repr__ only while a test of its value passes.
ShowIf(test) calls test(value) and shows the field when the
result is true. On a dict-like class it also works as a key setting,
as in Key(ShowIf(test)), where it leaves the key out while the test
fails.
After the test, ShowIf takes the same keywords as field(), so it
can be written as a field's value: notes: str = ShowIf(bool,
default=""). A test given such keywords also declares the field,
and so it cannot be used as a repr or key setting on its own.
How it lowers
In a class
HideIf
HideIfNone
HideIfNone(**kwargs: Any)
Bases: HideIf
Hide a field from __repr__ while it holds None.
The class can be written wherever an instance can, so
Field(repr=HideIfNone) is the same as Field(repr=HideIfNone()).
Given as a class setting, as in class C(Magic, repr=HideIfNone()),
it applies to every field.
It takes the keywords of field(), so it can be written as a
field's value: nickname: Optional[str] = HideIfNone(default=None).
In a class
HideIfDefault
HideIfDefault(**kwargs: Any)
Bases: HideIf
Hide a field from __repr__ while it holds its default.
A value counts as the default when it is the default object or compares equal to it, and a value that cannot be compared with the default is shown. The field needs a plain default to compare with, so a default built by a factory is refused, because each instance has its own.
Given as a class setting, as in
class C(Magic, repr=HideIfDefault()), it applies to every field
that has a plain default, and the other fields are always shown.
It takes the keywords of field(), so it can be written as a
field's value together with the default it compares with:
method: str = HideIfDefault(default="GET").
In a class
Eq
Bases: BoolAnnotatedField
Compare a field in the generated __eq__, ignore it, or choose how.
A field that is ignored takes no part in equality, so two objects that differ only in that field compare equal.
Besides True and False, a field's eq setting can be a function
of two values, which is called with the field's value on each of the
two objects. The objects can be equal only when its answer is true.
A function suits a value whose == does not answer with a single
True or False: numpy.array_equal compares two arrays as wholes,
where == compares them element by element. A field compared with a
function is left out of the hash, since two values that the function
calls equal can still hash differently, and it is left out of the
ordering unless the field says order=True.
How it lowers
In a class
Comparing with a function
NoEq
Order
Bases: BoolAnnotatedField
Compare a field in the generated ordering, or ignore it.
The ordering methods are generated only when the class asks for
them with order=True.
How it lowers
NoOrder
Compare
NoCompare
Hash
Bases: BoolAnnotatedField
Include a field in the generated __hash__, or leave it out.
A field left out of the comparison is left out of the hash too, so
Hash is rarely needed on its own.
How it lowers
NoHash
Key
Bases: BoolAnnotatedField
Include a field in the dict-like interface, or leave it out.
Key matters only on a class built with mapping=True. A string
given as the argument is used as the key in place of the field's
name.
How it lowers
In a class
A test such as ShowIf(bool) or HideIfNone() keeps the key only
while the test passes. A name given before the test renames the key
as well.
With a test
NotKey
Doc
Bases: AnnotatedField, Doc
Document a field.
The text appears in the class docstring and in the documentation of the
generated __init__. After the text, Doc takes the same keywords as
field(), so it can be written as a field's value with a default:
retries: int = Doc("how many times to retry", default=3).
How it lowers
Pin
Bases: AnnotatedField
Decide what a subclass that matches on this field does with it.
A subclass written with on={"mode": "minor"} gives mode that
value. Pin decides how the value is given to this field, whatever
the subclass's pin_discriminant setting says. It takes the same
values as that setting, which are "pin" (the default), "classvar",
"keep", "narrow", "pin+narrow", "classvar+narrow" and "keep+narrow",
and also True for "pin" and False for "keep". Narrow[T] is
Pin[T, "narrow"], and NoPin[T] is Pin[T, False].
Each mode is also available as a constant: PIN, CLASSVAR,
KEEP, NARROW, PIN_NARROW, CLASSVAR_NARROW and
KEEP_NARROW. A linter reads a constant as a name that it
knows, whereas it reads "classvar" inside the brackets as an
undefined type.
The field keeps its Pin in every subclass, so every class that
matches on the field treats it in the same way.
How it lowers
>>> Pin()
Pin(pin='pin')
>>> Pin[str]
typing.Annotated[str, Pin(pin='pin')]
>>> Pin[str, "classvar"]
typing.Annotated[str, Pin(pin='classvar')]
>>> Pin[str, CLASSVAR]
typing.Annotated[str, Pin(pin='classvar')]
>>> Narrow[str]
typing.Annotated[str, Narrow(pin='narrow')]
>>> NoPin[str]
typing.Annotated[str, NoPin(pin=False)]
In a class
Narrow
NoPin
Forget
Bases: AnnotatedField
Remove a field the class inherits.
Forget is written on its own as the annotation, as in y: Forget.
The field is gone from this class and from every class that
inherits from it: the constructor no longer takes it, and the repr,
the comparisons and the dict-like view leave it out. Its public name
is free again, so another field may take it. A subclass further
down that declares the field again creates a new field.
A value written beside Forget becomes an ordinary class attribute.
When no value is written, the name is looked up as on any class, so
reading it can still find what a base class holds under that name,
such as the field's old default.
A field by which a base class chooses its subclasses can be forgotten too. Passing that field to the class is then an error that names the class that forgot it, and a base class that is choosing a subclass passes over the forgetting class whenever the call passes that field.
In a class
Inherit
Bases: AnnotatedField
Build a field from a field the class inherits.
A field that a subclass declares again normally replaces the
inherited field completely, so the default, the aliases and every
other setting written in the base class are lost. Inherit keeps
them instead. Written as the value of a field whose type is ...,
as in x: ... = Inherit(frozen=True), it starts the field from what
the base class declared and changes only the settings it is given.
Inherit accepts every keyword that Field accepts. A plain value
after ..., as in x: ... = 5, changes nothing but the default, and
a default of REQUIRED removes the inherited default.
Given the name of another inherited field, as in
_x: ... = Inherit("x"), Inherit takes that field over. The
inherited field leaves the class, and the new field starts from the
inherited field's declaration, its public name and its place in the
constructor. The class also receives a property under the public
name that reads and assigns the new field, unless the class body
defines something under that name itself. The public name can be
changed with alias=, in which case no property is made, and
position=False places the field where it is written in the class
body rather than where the inherited field was.
Inherit can also be written in the brackets of an annotation, where
the first argument is the type, as for every annotation in the
family. x: Inherit[float] keeps the inherited field but gives it a
new type, and a converter, validator or factory that was worked out
from the old type is worked out again from the new one.
Inherit["Node"] is read as a forward reference to a class named
Node. Inherit[..., "x"] keeps the inherited type and takes over
x. Linters such as Ruff and Pyflakes read the string "x" in that
annotation as a forward reference and report it as an undefined name
(F821), so code that a linter checks either adds # noqa: F821 to the
line or writes Inherit as the value instead.
Every other annotation in the family accepts ... as its type in the
same way, so x: Frozen[...] is another spelling of
x: ... = Inherit(frozen=True). These spellings work on every
supported version of Python, whereas Annotated[..., Frozen()]
written by hand works only from Python 3.12, because older versions
of Annotated refuse ... as a type.
How it lowers
Changing an inherited field
Taking a field over
Functions:
field
Describe one field, for use as its default value.
class Task(Magic):
name: str
tags: list = field(factory=list)
token: str = field(default="", repr=False)
retries: int = field(default=0, kw_only=True)
field() takes the same arguments as Field and returns the
same object, and it refuses a keyword that it does not recognise.
The two differ only for type checkers: field(...) declares its
return type as the annotated type, so a checker accepts
tags: list = field(...). Field(...) in that position also works
when the program runs.