Skip to content
This repository was archived by the owner on Sep 9, 2024. It is now read-only.

seandstewart/typical

Repository files navigation

typical: Python's Typing Toolkit

image image image image Test & Lint Coverage Code style: black Netlify Status

How Typical

⚠️ This Project is now Archived ⚠️

See python-typelib for a modern successor to this library by the same author.

For an more extensive alternative, see mashumaro.

Introduction

Typical is a library devoted to runtime analysis, inference, validation, and enforcement of Python types, PEP 484 Type Hints, and custom user-defined data-types.

Typical is fully compliant with the following Python Typing PEPs:

It provides a high-level Protocol API, Functional API, and Object API to suit most any occasion.

Getting Started

Installation is as simple as pip install -U typical.

Help

The latest documentation is hosted at python-typical.org.

Starting with version 2.0, All documentation is hand-crafted markdown & versioned documentation can be found at typical's Git Repo. (Versioned documentation is still in-the-works directly on our domain.)

A Typical Use-Case

The decorator that started it all:

typic.al(...)

import typic @typic.al def hard_math(a: int, b: int, *c: int) -> int: return a + b + sum(c) hard_math(1, "3") #> 4 @typic.al(strict=True) def strict_math(a: int, b: int, *c: int) -> int: return a + b + sum(c) strict_math(1, 2, 3, "4") #> Traceback (most recent call last): #> ... #> typic.constraints.error.ConstraintValueError: Given value <'4'> fails constraints: (type=int, nullable=False, coerce=False) 

Typical has both a high-level Object API and high-level Functional API. In general, any method registered to one API is also available to the other.

The Protocol API

import dataclasses from typing import Iterable import typic @typic.constrained(ge=1) class ID(int): ... @typic.constrained(max_length=280) class Tweet(str): ... @dataclasses.dataclass # or typing.TypedDict or typing.NamedTuple or annotated class... class Tweeter: id: ID tweets: Iterable[Tweet] json = '{"id":1,"tweets":["I don\'t understand Twitter"]}' protocol = typic.protocol(Tweeter) t = protocol.transmute(json) print(t) #> Tweeter(id=1, tweets=["I don't understand Twitter"]) print(protocol.tojson(t)) #> '{"id":1,"tweets":["I don\'t understand Twitter"]}' protocol.validate({"id": 0, "tweets": []}) #> Traceback (most recent call last): #> ... #> typic.constraints.error.ConstraintValueError: Tweeter.id: value <0> fails constraints: (type=int, nullable=False, coerce=False, ge=1)

The Functional API

import dataclasses from typing import Iterable import typic @typic.constrained(ge=1) class ID(int): ... @typic.constrained(max_length=280) class Tweet(str): ... @dataclasses.dataclass # or typing.TypedDict or typing.NamedTuple or annotated class... class Tweeter: id: ID tweets: Iterable[Tweet] json = '{"id":1,"tweets":["I don\'t understand Twitter"]}' t = typic.transmute(Tweeter, json) print(t) #> Tweeter(id=1, tweets=["I don't understand Twitter"]) print(typic.tojson(t)) #> '{"id":1,"tweets":["I don\'t understand Twitter"]}' typic.validate(Tweeter, {"id": 0, "tweets": []}) #> Traceback (most recent call last): #> ... #> typic.constraints.error.ConstraintValueError: Tweeter.id: value <0> fails constraints: (type=int, nullable=False, coerce=False, ge=1)

The Object API

from typing import Iterable import typic @typic.constrained(ge=1) class ID(int): ... @typic.constrained(max_length=280) class Tweet(str): ... @typic.klass class Tweeter: id: ID tweets: Iterable[Tweet] json = '{"id":1,"tweets":["I don\'t understand Twitter"]}' t = Tweeter.transmute(json) print(t) #> Tweeter(id=1, tweets=["I don't understand Twitter"]) print(t.tojson()) #> '{"id":1,"tweets":["I don\'t understand Twitter"]}' Tweeter.validate({"id": 0, "tweets": []}) #> Traceback (most recent call last): #> ... #> typic.constraints.error.ConstraintValueError: Given value <0> fails constraints: (type=int, nullable=False, coerce=False, ge=1)

Changelog

See our Releases.