Skip to main content

Record Classes

Project description

Test records codecov

Records

Records is a python library that makes powerful structure classes easy.

Simplest Example

A feature of Records is that, by default, it does nothing more than a namedtuple or dataclass would.

from records import RecordBase

class Point(RecordBase):
    x: float
    y: float
    z: float = 0.0

p0 = Point(x=0, y=0)
print(p0)  # Point(x=0, y=0)
print(p0.x)  # 0
# note that no type checking or coercion is performed
print(type(p0.y))  # int
# by default, the type hints are not even run
p1 = Point(x="hello", y="world", z="1.0")
print(p1.y)  # world
print(type(p1.z))  # str

Checking, Coercion, and Validation

Sometimes we'd like to perform some additional processing to arguments before they are entered into the struct. For that we have three steps: type-checking, coercion, and validation

  • type-checking is the first and simplest step, it simply checks that the argument is of the type we expect. If it isn't, then we perform coercion.
  • type coercion only occurs if typechecking has failed, it will attempt to convert the into the type we expect. As one may expect, there is a large number of potential coercers, so they must be added each individually.
  • validation occurs after either type checking or type coercion have succeeded. By this point we are certain that the input is of the correct type and we want to ensure/manipulate its value.

These methods are described per-field with the Annotation type hint (Annotation is new in python 3.9, but has been backported by records for older versions to use)

These three steps are expanded upon in the documentation, for now we will show some brief examples:

from typing import List
from records import RecordBase, Annotated, check, check_strict, Loose, Within, Eval

class Person(RecordBase):
    first_name: str  # no coercion or checking here, this is what we call a "hollow" field
    last_name: Annotated[str, check]  # now we will raise a TypeError if anyone tries to enter a non-string last_name  
    year_of_birth: Annotated[int, check_strict]  # we will raise a TypeError if year_of_birth isn't exactly an int (so passing True will throw an error)
    lucky_number: Annotated[int, check, Loose]  # the "Loose" built-in coerser will simply call the destination type with the input as an argument, so that using `lucky_number="7"` would be equivalent to `lucky_number=int("7")`
    number_of_children: Annotated[int, check, Within(ge=0)]  # the Within built-in validator ensures the value is within stated bounds (in this case, at least zero)
    # field tokens can even be more complex in case of nested field types
    names_of_children: Annotated[List[Annotated[int, check, Eval]], check]  # the list will be checked to be a list, and each item individually will be checked or coerced to be an int using the built-in Eval coercer.
    
    # validators can also be added after declaration with pre_bind
    @classmethod
    def pre_bind(cls):
        @cls.last_name.add_validator
        def no_bad_words(last_name):
            # we want to remove some words from the last name
            return last_name.replace('richard', '*******')

    # we can also add some more pre-processing on an entire instance with "post_new"
    def post_new(self):
        if len(self.names_of_children) != self.number_of_children:
            raise ValueError("children mismatch")

Parsing

Records can also be parsed from various python primitives. Including parsing from dicts, jsons, and even generic namepaces.

from types import SimpleNamespace
from records import RecordBase, check

class User(RecordBase, default_type_check=check):
    name: str
    password: str
    age: int = 18
    

print(User.from_mapping({"name": "richard", "password": "swordfish"}))
print(User.from_json('{"name": "richard", "password": "swordfish"})'))
n = SimpleNamespace(user="rich", password="ard", age= 7)
print(User.from_instance(n))

# parsing can even be done if you expect misnamed fields!
from_upper_dict = User.from_mapping.select(keys_to_rename=[('user','name')], keys_to_remove=['favorite_color'])
print(from_upper_dict({'user':'richard', 'password': 'pw', 'favorite_color': 'red'}))

You can also define your own parsers and even use them in construction!

from math import sqrt
from records import RecordBase, check, SelectableFactory, parser

class Point(RecordBase, default_type_check=check):
    x: float
    y: float
    z: float = 0
    
    @parser
    @SelectableConstructor
    @classmethod
    def from_tuple(cls, v):
        return {'x':v[0], 'y':v[1], 'z':v[2] if len(v) > 2 else 0}

    @property
    def norm(self):
        return sqrt(self.x**2 + self.y**2 + self.z**2)

p = Point([2,3,6])
print(p.norm)  # 7

Exporting

Records can also be exporting to various formats (same as parsing).

from records import RecordBase, check

class Point(RecordBase, default_type_check=check):
    x: float
    y: float
    z: float

p = Point(x=2, y=3, z=6)
print(p.to_dict())
print(p.to_pickle())
#  again, we can select to change the keys
print(
    p.to_json.select(keys_to_add=[('w',0)])()
)

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

recordclasses-0.0.1.tar.gz (30.4 kB view details)

Uploaded Source

Built Distribution

recordclasses-0.0.1-py3-none-any.whl (35.6 kB view details)

Uploaded Python 3

File details

Details for the file recordclasses-0.0.1.tar.gz.

File metadata

  • Download URL: recordclasses-0.0.1.tar.gz
  • Upload date:
  • Size: 30.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.0.9 CPython/3.8.2 Windows/10

File hashes

Hashes for recordclasses-0.0.1.tar.gz
Algorithm Hash digest
SHA256 2c4184679a4b823d0ea2a2157bcb8ce0da5f6dff61012b75114202d9b7c245a2
MD5 d4afab5b269e950f9a19b2c22cb4aba8
BLAKE2b-256 802c2824237a68aa46ab558825b2af7a2816e64af10d0148208ca043e085ce25

See more details on using hashes here.

File details

Details for the file recordclasses-0.0.1-py3-none-any.whl.

File metadata

  • Download URL: recordclasses-0.0.1-py3-none-any.whl
  • Upload date:
  • Size: 35.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.0.9 CPython/3.8.2 Windows/10

File hashes

Hashes for recordclasses-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 8e7fbc4bc2eb0884b14dcddbfef2ba89ea6368a692af70642839a343be1bd4a3
MD5 7c387086470a894ac2cc9e03441abe1e
BLAKE2b-256 99da81b354ff6d1694e491a952096cc0445b47ce46b048994bedb65a0c00ff67

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page