typedload

raw JSON →
2.40 verified Tue May 12 auth: no python install: verified quickstart: verified

typedload is a Python library designed to load and dump data from JSON-like formats into statically typed data structures. It supports standard Python types such as NamedTuples, dataclasses, sets, and enums, enforcing a schema by performing type checks and casts as needed. It also facilitates dumping typed data structures back to JSON-like dictionaries and lists. This library is particularly useful for projects leveraging Mypy, as it guarantees data conformity to specified schemas at runtime. It is actively maintained, with frequent releases; the current version is 2.40.

pip install typedload
error ModuleNotFoundError: No module named 'typedload'
cause The 'typedload' library has not been installed in the current Python environment.
fix
pip install typedload
error TypeError: 'hello' is not an int
cause The input data provided to `typedload.load()` cannot be converted to the target type specified.
fix
Ensure the input data's type or value is compatible with the expected type for the field or target class.
error KeyError: 'b'
cause The input dictionary provided to `typedload.load()` is missing a required key for the target type (e.g., TypedDict, dataclass).
fix
Ensure the input dictionary contains all required keys for the target type.
error ImportError: cannot import name 'TypedloadException' from 'typedload'
cause The `TypedloadException` class is located within the `typedload.exceptions` submodule, not directly in the top-level `typedload` package.
fix
from typedload.exceptions import TypedloadException
gotcha Untagged Unions can lead to non-deterministic loading results if input data matches multiple types within the union. While `typedload` supports untagged unions, it's safer and faster to use `Literal` fields to tag unions for explicit type identification. For debugging, `uniondebugconflict=True` can detect such ambiguities but incurs a performance cost.
fix Prefer using tagged unions with `typing.Literal` to explicitly differentiate types. If untagged unions are necessary, ensure data unambiguously maps to a single type or be aware of potential non-deterministic behavior. Use `load(data, SomeUnion, uniondebugconflict=True)` for debugging.
gotcha The distinction between `typing.Optional[T]` and a field with a default value is important. `Optional[T]` means the field *must* be present in the input data but can be `None`. A field with a default value, however, can be entirely *omitted* from the input data, and `typedload` will use the default. Misunderstanding this can lead to unexpected validation errors.
fix Always provide `None` explicitly for `Optional[T]` fields in input data if the value is `None`. For truly optional fields that can be omitted, define a default value (e.g., `field: str = 'default'` or `field: List[str] = dataclasses.field(default_factory=list)`).
breaking Directly using a bare `list` (e.g., `my_list: list`) as a type annotation for loading into a dataclass field will cause a crash. This annotation is treated differently by `typedload` and is not equivalent to `list[typing.Any]` at runtime.
fix Always specify the type argument for generic collections like `list`. Use `my_list: list[Any]` or `my_list: list[str]` (or any specific type) instead of `my_list: list`.
deprecated Since version 2.23, the default behavior for dumping `datetime.date`, `datetime.time`, and `datetime.datetime` objects has shifted. The previous method of dumping them as a list of integers (e.g., `[year, month, day, ...]`) is now deprecated. The recommended way is to dump them as ISO 8601 strings.
fix When dumping `datetime` objects and desiring ISO 8601 strings, ensure `isodates=True` is passed to the `dump` function (e.g., `typedload.dump(obj, isodates=True)`). If relying on the old integer list format, be aware it may be removed in future major versions.
gotcha When dumping dataclass instances, fields whose values match their declared default values in the dataclass definition may be implicitly omitted from the serialized output. This behavior can lead to incomplete data being serialized, even if the field was explicitly populated during loading, if its value happens to match the default. This is often done to reduce payload size but can be unexpected.
fix If all fields must always be present in the dumped output, regardless of whether their value matches a default, ensure that `typedload.dump` is configured to include all fields (e.g., check for an `omit_defaults=False` or similar option). Alternatively, if possible, avoid assigning default values to fields that must always be present in the serialized output.
python os / libc status wheel install import disk
3.10 alpine (musl) wheel - 0.01s 18.0M
3.10 alpine (musl) - - 0.01s 18.0M
3.10 slim (glibc) wheel 1.6s 0.00s 18M
3.10 slim (glibc) - - 0.00s 18M
3.11 alpine (musl) wheel - 0.02s 19.9M
3.11 alpine (musl) - - 0.02s 19.9M
3.11 slim (glibc) wheel 1.6s 0.01s 20M
3.11 slim (glibc) - - 0.01s 20M
3.12 alpine (musl) wheel - 0.01s 11.7M
3.12 alpine (musl) - - 0.01s 11.7M
3.12 slim (glibc) wheel 1.5s 0.01s 12M
3.12 slim (glibc) - - 0.01s 12M
3.13 alpine (musl) wheel - 0.01s 11.5M
3.13 alpine (musl) - - 0.01s 11.4M
3.13 slim (glibc) wheel 1.4s 0.01s 12M
3.13 slim (glibc) - - 0.01s 12M
3.9 alpine (musl) wheel - 0.01s 17.5M
3.9 alpine (musl) - - 0.01s 17.5M
3.9 slim (glibc) wheel 1.8s 0.00s 18M
3.9 slim (glibc) - - 0.00s 18M

This example demonstrates how to define typed data structures using dataclasses and NamedTuple, then use `typedload.load` to convert a dictionary (typically from JSON) into these structures. It also shows `typedload.dump` for converting them back to a dictionary. Default values for fields are automatically handled during loading.

import dataclasses
from typing import NamedTuple, List
from typedload import load, dump

@dataclasses.dataclass
class User:
    username: str
    shell: str = 'bash'
    sessions: List[str] = dataclasses.field(default_factory=list)

class Logins(NamedTuple):
    users: List[User]

data_from_json = {
    'users': [
        { 'username': 'salvo', 'shell': 'bash', 'sessions': ['pts/4', 'tty7', 'pts/6'] },
        { 'username': 'lop' }
    ]
}

# Load the dictionary into typed data structures
loaded_data: Logins = load(data_from_json, Logins)
print(f"Loaded Data: {loaded_data}")
assert loaded_data.users[0].username == 'salvo'
assert loaded_data.users[1].shell == 'bash' # Default value applied

# Dump the typed data structure back to a dictionary
dumped_data = dump(loaded_data)
print(f"Dumped Data: {dumped_data}")
assert dumped_data['users'][0]['username'] == 'salvo'