Declarively apply converter functions to class attributes.
Project description
Exert
Declaratively apply converter functions to class attributes.
Installation
Install via pip:
pip install exert
Usage
Use this to declaratively apply arbitrary converter functions to the attributes of a class. For example:
from __future__ import annotations
from typing import Annotated
from exert import exert
@exert
class Foo:
a: Annotated[int, lambda x: x**2]
b: Annotated[float, lambda x: x / 2]
def __init__(self, a: int, b: float) -> None:
self.a = a
self.b = b
foo = Foo(2, 42.0)
print(foo.a) # prints 4
print(foo.b) # prints 21.0
Here, the lambda function inside the Annotated
tag is the converter.
Using with dataclasses
Dataclasses can also be used to avoid writing the initializer by hand. For example:
...
from dataclasses import dataclass
@exert
@datclasses
class Foo:
a: Annotated[int, lambda x: x**2]
b: Annotated[float, lambda x: x / 2]
foo = Foo(2, 42.0)
print(foo.a) # prints 4
print(foo.b) # prints 21.0
Apply multiple converters sequentially
Multiple converters are allowed. For example:
...
@exert
@dataclass
class Foo:
a: Annotated[int, lambda x: x**2, lambda x: x**3]
b: Annotated[float, lambda x: x / 2, lambda x: x / 3]
foo = Foo(2, 42.0)
print(foo.a) # prints 64 [2**2=4, 4**3=64]
print(foo.b) # prints 7.0 [42.0/2=21.0, 21.0/3=7.0]
Excluding tagged fields
If you want to exclude a field that's tagged with Annotated
, you can do so using the tagged_exclude
parameter:
...
@exert(tagged_exclude=("b",))
@dataclass
class Foo:
a: Annotated[int, lambda x: x**2, lambda x: x**3]
b: Annotated[float, lambda x: x / 2, lambda x: x / 3]
foo = Foo(2, 42.0)
print(foo.a) # prints 64 [2**2=4, 4**3=64]
print(foo.b) # prints 42.0 [This field was ignored]
Including untagged fields
By default, exert
will ignore fields that aren't tagged with Annotated
. But you can
still apply converters to those fields. You'll need to use converters
and untagged_include
together:
...
@exert(converters=(lambda x: x**2, lambda x: x**3), untagged_include=("b",))
@dataclass
class Foo:
a: int
b: float
foo = Foo(2, 42.0)
print(foo.a) # prints 2 [This field remains untouched]
print(foo.b) # prints 5489031744.0 [42.0**2=1764, 1764**3=5489031744.0]
Apply common converters without repetition
Common converters can be applied to multiple fields without introducing any repetition. The the previous section already shows how to do it:
...
@exert(converters=(lambda x: x**2, ), untagged_include=("a", "b"))
@dataclass
class Foo:
a: int
b: float
foo = Foo(2, 42.0)
print(foo.a) # prints 2 [This field remains untouched]
print(foo.b) # prints 1764.0 [42.0**2=1764.0]
Apply common and tagged converters together
You can apply a sequence of common converters and tagged converters together. By default, the common converters are applied first and then the tagged converters are applied sequentially:
...
@exert(converters=(lambda x: x**2, lambda x: x**3), untagged_include=("b",))
@dataclass
class Foo:
a: Annotated[int, lambda x: x / 100]
b: float
foo = Foo(2, 42.0)
print(foo.a) # prints 0.64 [2**2=4, 4**3=64, 64/100=0.64]
print(foo.b) # prints 5489031744.0 [42.0**2=1764, 1764**3=5489031744.0]
You can also, choose to apply the common converters after the tagged ones. For this,
you'll need to set the apply_last
parameter to True
:
...
@exert(
converters=(lambda x: x**2, lambda x: x**3),
untagged_include=("b",),
apply_last=True,
)
@dataclass
class Foo:
a: Annotated[int, lambda x: x / 100]
b: float
foo = Foo(2, 42.0)
print(foo.a) # prints 6.401e-11 [2/100=0.02, 0.02**2=0.004, 0.0004**3=6.401e-11]
print(foo.b) # prints 5489031744.0 [42.0**2=1764, 1764**3=5489031744.0]
Include all untagged fields
To apply converters to all the untagged fields, use untagged_include="__all__"
:
...
@exert(
converters=(lambda x: x**2, lambda x: x**3),
untagged_include="__all__",
)
@dataclass
class Foo:
a: int
b: float
foo = Foo(2, 42.0)
print(foo.a) # prints 64 [2**2=4, 4**4=64]
print(foo.b) # prints 5489031744.0 [42.0**2=1764, 1764**3=5489031744.0]
Exclude all tagged fields
To ignore all the fields tagged with Annotated
, use tagged_exclude="__all__"
:
...
@exert(
converters=(lambda x: x**2, lambda x: x**3),
tagged_exclude="__all__",
)
@dataclass
class Foo:
a: Annotated[int, lambda x: x**2]
b: Annotated[float, lambda x: x**3]
foo = Foo(2, 42.0)
print(foo.a) # prints 2 [Untouched]
print(foo.b) # prints 42.0 [Untouched]
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file exert-0.2.1.tar.gz
.
File metadata
- Download URL: exert-0.2.1.tar.gz
- Upload date:
- Size: 4.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.0 CPython/3.10.4
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | fc0ab0f413deb8a896424954fb745252cd46fb295159b9ab8f0f09b5b929033e |
|
MD5 | 25a13c74f1b3c8837080cb4aa7989d25 |
|
BLAKE2b-256 | 9579c9d53fba996044d1af56abb500c13547af1ee97af12809f1c81bed8e28f7 |
File details
Details for the file exert-0.2.1-py3-none-any.whl
.
File metadata
- Download URL: exert-0.2.1-py3-none-any.whl
- Upload date:
- Size: 4.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.0 CPython/3.10.4
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 366fc7bde7fddef99051e73e766afda91d9434ba1b789c7cc5d8ce2165a2be84 |
|
MD5 | 4e8ac161a5ddd97d319185bf66e61dc0 |
|
BLAKE2b-256 | 08f170a7afde334c66725963d44db86405209d8326fdeb84eb6de03bde9ae713 |