Immutable Data Records with Type Coercion
Project description
Data Records
In certain Functional languages there is a concept of Records. They are a Product Data Type of immutable data that has typed attributes.
Goals
The following are the goals and the "north star" for design during the development of this project:
- Ease Of Use
- Simple Interface
- Does the obvious thing in most cases
- Immutability
- Follow Immutability Patterns such as replace and pattern matching
- Safety
- Include Type Coercion Where Possible
- Guarantee that a record has the resulting types
- Throw Warning when it is implemented Incorrectly
Motivation
Enforced Typing
I love @dataclass
, and was ecstatic when it was added to python. However certain things like:
>>> from dataclasses import dataclass, field
>>> @dataclass
... class Foo:
... bar: str
... baz: int
>>> Foo(1, 2)
Foo(bar=1, baz=2)
is not what I would expect when coming from other typed languages. In statically typed languages, this should throw an
error because bar
should be a string. In languages with type coercion, I would expect that bar
would be "1"
. The default
behavior of dataclasses here does neither, and if I were to use this dataclass somewhere that expected bar to be a string
it would fail with a runtime exception; exactly what the types were supposed to help prevent.
>>> from data_records import datarecord
>>> @datarecord
... class Foo:
... bar: str
... baz: int
>>> Foo(1, 2)
Foo(bar='1', baz=2)
>>> Foo("a", "b")
Traceback (most recent call last):
...
ValueError: invalid literal for int() with base 10: 'b'
Extraneous Field Handling
Another Problem with dataclasses occurs when trying to pass in a dictionary that has more keys than are required for creating a dataclass:
>>> from dataclasses import dataclass
>>> @dataclass
... class Foo:
... bar: str
... baz: int
>>> Foo(**{'bar': 'test', 'baz': 1, 'other': 'nothing'})
Traceback (most recent call last):
...
TypeError: __init__() got an unexpected keyword argument 'other'
This makes it hard to pull data records out of larger database calls or received data.
>>> from data_records import datarecord
>>> @datarecord
... class Foo:
... bar: str
... baz: int
>>> Foo(**{'bar': 'test', 'baz': 1, 'other': 'test'})
Foo(bar='test', baz=1)
>>> Foo.from_dict({'bar': 'test', 'baz': 1, 'other': 'test'})
Foo(bar='test', baz=1)
Immutable Handling
Data records are immutable (much like frozen dataclasses) and the handling for such is builtin:
>>> from data_records import datarecord
>>> @datarecord
... class Foo:
... bar: str
... baz: int
... lat: float
... long: float
>>> example = Foo('test', 2, 65.1, -127.5)
>>> example2 = example.replace(bar='testing')
>>> example
Foo(bar='test', baz=2, lat=65.1, long=-127.5)
>>> example2
Foo(bar='testing', baz=2, lat=65.1, long=-127.5)
>>> latitude, longitude = example.extract('lat', 'long')
>>> latitude
65.1
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Hashes for data_records-0.4.2-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 47c905401016e5119a0bf96a5aab9f921b777ae6fe78d59ef2388353bd8c1595 |
|
MD5 | ba4b7321723994c7894ff01dbc6f0d0d |
|
BLAKE2b-256 | b4a54d7992133a1945f901e65af60ed8a3bcb8c3b4436387bb175dcf3042decc |