Metadata-Version: 2.1
Name: typical
Version: 2.8.0
Summary: Typical: Python's Typing Toolkit.
Home-page: https://github.com/seandstewart/typical
License: MIT
Keywords: typing,data,annotations,validation,json-schema
Author: Sean Stewart
Author-email: sean_stewart@me.com
Requires-Python: >=3.7,<4.0
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Natural Language :: English
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Topic :: Utilities
Classifier: Typing :: Typed
Provides-Extra: benchmarks
Provides-Extra: docs
Provides-Extra: json
Provides-Extra: lint
Provides-Extra: schema
Provides-Extra: tests
Requires-Dist: black (>=21,<22); extra == "lint"
Requires-Dist: django (>=2.2,<3.0); extra == "benchmarks"
Requires-Dist: djangorestframework (>=3.10,<4.0); extra == "benchmarks"
Requires-Dist: fastjsonschema (>=2.14,<3.0); extra == "schema" or extra == "tests"
Requires-Dist: flake8 (>=3.7.9,<4.0.0); extra == "lint"
Requires-Dist: future-typing (>=0.4.1,<0.5.0)
Requires-Dist: inflection (>=0.5,<0.6)
Requires-Dist: marshmallow (>=3.2,<4.0); extra == "benchmarks"
Requires-Dist: mkdocs (>=1.1,<2.0); extra == "docs"
Requires-Dist: mkdocs-awesome-pages-plugin (>=2.2.1,<3.0.0); extra == "docs"
Requires-Dist: mkdocs-material (>=8,<9); extra == "docs"
Requires-Dist: mypy (>=0.910,<0.911); extra == "tests" or extra == "lint"
Requires-Dist: orjson (>=3.6.3,<4.0.0); extra == "tests"
Requires-Dist: pandas (>=1.1.3,<2.0.0); (python_full_version >= "3.7.1" and python_version <= "3.9") and (extra == "tests")
Requires-Dist: pendulum (>=2.1,<3.0)
Requires-Dist: pydantic[email] (>=1.0,<2.0); extra == "tests" or extra == "benchmarks" or extra == "benchmarks"
Requires-Dist: pymdown-extensions (>=9.0,<10.0); extra == "docs"
Requires-Dist: pytest (>=6.2,<7.0); extra == "tests"
Requires-Dist: pytest-benchmark[histogram] (>=3.2,<4.0); extra == "benchmarks"
Requires-Dist: pytest-cov (>=2.8,<3.0); extra == "tests"
Requires-Dist: sqlalchemy (>=1.3.13,<2.0.0); extra == "tests" or extra == "benchmarks"
Requires-Dist: toastedmarshmallow (>=2.15,<3.0); extra == "benchmarks"
Requires-Dist: types-python-dateutil; extra == "lint"
Requires-Dist: types-setuptools; extra == "lint"
Requires-Dist: types-toml; extra == "lint"
Requires-Dist: types-typed-ast; extra == "lint"
Requires-Dist: types-ujson; extra == "lint"
Requires-Dist: typing-extensions (>=3.10.0,<4.0.0); python_version < "3.10"
Requires-Dist: ujson (>=2.0); extra == "json" or extra == "tests"
Project-URL: Repository, https://github.com/seandstewart/typical
Description-Content-Type: text/markdown

# typical: Python's Typing Toolkit
[![image](https://img.shields.io/pypi/v/typical.svg)](https://pypi.org/project/typical/)
[![image](https://img.shields.io/pypi/l/typical.svg)](https://pypi.org/project/typical/)
[![image](https://img.shields.io/pypi/pyversions/typical.svg)](https://pypi.org/project/typical/)
[![image](https://img.shields.io/github/languages/code-size/seandstewart/typical.svg?style=flat)](https://github.com/seandstewart/typical)
[![Test & Lint](https://github.com/seandstewart/typical/workflows/Test%20&%20Lint/badge.svg)](https://github.com/seandstewart/typical/actions)
[![Coverage](https://codecov.io/gh/seandstewart/typical/branch/master/graph/badge.svg)](https://codecov.io/gh/seandstewart/typical)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black)
[![Netlify Status](https://api.netlify.com/api/v1/badges/982a0ced-bb7f-4391-87e8-1957071d2f66/deploy-status)](https://app.netlify.com/sites/typical-python/deploys)

![How Typical](static/typical.png)

## Introduction

Typical is a library devoted to runtime analysis, inference,
validation, and enforcement of Python types,
[PEP 484](https://www.python.org/dev/peps/pep-0484/) Type Hints, and
custom user-defined data-types.

Typical is fully compliant with the following Python Typing PEPs:

- [PEP 484 -- Type Hints](https://www.python.org/dev/peps/pep-0484/)
- [PEP 563 -- Postponed Evaluation of Annotations](https://www.python.org/dev/peps/pep-0563/)
- [PEP 585 -- Type Hinting Generics In Standard Collections](https://www.python.org/dev/peps/pep-0585/)
- [PEP 586 -- Literal Types](https://www.python.org/dev/peps/pep-0586/)
- [PEP 589 -- TypedDict: Type Hints for Dictionaries with a Fixed Set of Keys](https://www.python.org/dev/peps/pep-0589/)
- [PEP 604 -- Allow writing union types as X | Y](https://www.python.org/dev/peps/pep-0604/)

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](https://python-typical.org/).

> Starting with version 2.0, All documentation is hand-crafted
> markdown & versioned documentation can be found at typical's
> [Git Repo](https://github.com/seandstewart/typical/tree/master/docs).
> (Versioned documentation is still in-the-works directly on our
> domain.)

## A Typical Use-Case

The decorator that started it all:

### `typic.al(...)`

```python
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

```python
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

```python
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

```python
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](https://github.com/seandstewart/typical/releases).

