{"id":13494141,"url":"https://github.com/seandstewart/typical","last_synced_at":"2025-10-21T19:37:42.887Z","repository":{"id":34305544,"uuid":"175726271","full_name":"seandstewart/typical","owner":"seandstewart","description":"Typical: Fast, simple, \u0026 correct data-validation using Python 3 typing.","archived":true,"fork":false,"pushed_at":"2024-09-09T15:57:02.000Z","size":2698,"stargazers_count":182,"open_issues_count":0,"forks_count":9,"subscribers_count":5,"default_branch":"main","last_synced_at":"2024-10-30T08:18:02.707Z","etag":null,"topics":["annotations","data-validation","deserialization","python-types","python3","python3-library","python36","python37","python38","serde","serdes","serialization","type-annotations","type-hints","type-safety","typical","typing","validation"],"latest_commit_sha":null,"homepage":"https://python-typical.org","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/seandstewart.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-03-15T01:24:36.000Z","updated_at":"2024-09-15T13:20:27.000Z","dependencies_parsed_at":"2024-11-18T00:45:42.111Z","dependency_job_id":null,"html_url":"https://github.com/seandstewart/typical","commit_stats":{"total_commits":445,"total_committers":9,"mean_commits":49.44444444444444,"dds":0.0561797752808989,"last_synced_commit":"25873c57a2ae05c825b57fface21d05305480d85"},"previous_names":[],"tags_count":116,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seandstewart%2Ftypical","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seandstewart%2Ftypical/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seandstewart%2Ftypical/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seandstewart%2Ftypical/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/seandstewart","download_url":"https://codeload.github.com/seandstewart/typical/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245738882,"owners_count":20664362,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["annotations","data-validation","deserialization","python-types","python3","python3-library","python36","python37","python38","serde","serdes","serialization","type-annotations","type-hints","type-safety","typical","typing","validation"],"created_at":"2024-07-31T19:01:22.272Z","updated_at":"2025-10-21T19:37:37.558Z","avatar_url":"https://github.com/seandstewart.png","language":"Python","funding_links":[],"categories":["Python","Data Validation"],"sub_categories":[],"readme":"# typical: Python's Typing Toolkit\n[![image](https://img.shields.io/pypi/v/typical.svg)](https://pypi.org/project/typical/)\n[![image](https://img.shields.io/pypi/l/typical.svg)](https://pypi.org/project/typical/)\n[![image](https://img.shields.io/pypi/pyversions/typical.svg)](https://pypi.org/project/typical/)\n[![image](https://img.shields.io/github/languages/code-size/seandstewart/typical.svg?style=flat)](https://github.com/seandstewart/typical)\n[![Test \u0026 Lint](https://github.com/seandstewart/typical/workflows/Test%20\u0026%20Lint/badge.svg)](https://github.com/seandstewart/typical/actions)\n[![Coverage](https://codecov.io/gh/seandstewart/typical/branch/master/graph/badge.svg)](https://codecov.io/gh/seandstewart/typical)\n[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black)\n[![Netlify Status](https://api.netlify.com/api/v1/badges/982a0ced-bb7f-4391-87e8-1957071d2f66/deploy-status)](https://app.netlify.com/sites/typical-python/deploys)\n\n![How Typical](static/typical.png)\n\n# :warning: This Project is now Archived :warning:\n\nSee [python-typelib](https://github.com/seandstewart/python-typelib) for a \nmodern successor to this library by the same author.\n\nFor an more extensive alternative, see \n[mashumaro](https://github.com/Fatal1ty/mashumaro).\n\n## Introduction\n\nTypical is a library devoted to runtime analysis, inference,\nvalidation, and enforcement of Python types,\n[PEP 484](https://www.python.org/dev/peps/pep-0484/) Type Hints, and\ncustom user-defined data-types.\n\nTypical is fully compliant with the following Python Typing PEPs:\n\n- [PEP 484 -- Type Hints](https://www.python.org/dev/peps/pep-0484/)\n- [PEP 563 -- Postponed Evaluation of Annotations](https://www.python.org/dev/peps/pep-0563/)\n- [PEP 585 -- Type Hinting Generics In Standard Collections](https://www.python.org/dev/peps/pep-0585/)\n- [PEP 586 -- Literal Types](https://www.python.org/dev/peps/pep-0586/)\n- [PEP 589 -- TypedDict: Type Hints for Dictionaries with a Fixed Set of Keys](https://www.python.org/dev/peps/pep-0589/)\n- [PEP 604 -- Allow writing union types as X | Y](https://www.python.org/dev/peps/pep-0604/)\n\nIt provides a high-level Protocol API, Functional API, and Object API to suit most any\noccasion.\n\n## Getting Started\n\nInstallation is as simple as `pip install -U typical`.\n## Help\n\nThe latest documentation is hosted at\n[python-typical.org](https://python-typical.org/).\n\n\u003e Starting with version 2.0, All documentation is hand-crafted\n\u003e markdown \u0026 versioned documentation can be found at typical's\n\u003e [Git Repo](https://github.com/seandstewart/typical/tree/master/docs).\n\u003e (Versioned documentation is still in-the-works directly on our\n\u003e domain.)\n\n## A Typical Use-Case\n\nThe decorator that started it all:\n\n### `typic.al(...)`\n\n```python\nimport typic\n\n\n@typic.al\ndef hard_math(a: int, b: int, *c: int) -\u003e int:\n    return a + b + sum(c)\n\nhard_math(1, \"3\")\n#\u003e 4\n\n\n@typic.al(strict=True)\ndef strict_math(a: int, b: int, *c: int) -\u003e int:\n    return a + b + sum(c)\n\nstrict_math(1, 2, 3, \"4\")\n#\u003e Traceback (most recent call last):\n#\u003e  ...\n#\u003e typic.constraints.error.ConstraintValueError: Given value \u003c'4'\u003e fails constraints: (type=int, nullable=False, coerce=False)\n  \n```\n\nTypical has both a high-level *Object API* and high-level\n*Functional API*. In general, any method registered to one API is also\navailable to the other.\n\n### The Protocol API\n\n```python\nimport dataclasses\nfrom typing import Iterable\n\nimport typic\n\n\n@typic.constrained(ge=1)\nclass ID(int):\n    ...\n\n\n@typic.constrained(max_length=280)\nclass Tweet(str):\n    ...\n\n\n@dataclasses.dataclass # or typing.TypedDict or typing.NamedTuple or annotated class...\nclass Tweeter:\n    id: ID\n    tweets: Iterable[Tweet]\n\n\njson = '{\"id\":1,\"tweets\":[\"I don\\'t understand Twitter\"]}'\nprotocol = typic.protocol(Tweeter)\n\nt = protocol.transmute(json)\nprint(t)\n#\u003e Tweeter(id=1, tweets=[\"I don't understand Twitter\"])\n\nprint(protocol.tojson(t))\n#\u003e '{\"id\":1,\"tweets\":[\"I don\\'t understand Twitter\"]}'\n\nprotocol.validate({\"id\": 0, \"tweets\": []})\n#\u003e Traceback (most recent call last):\n#\u003e  ...\n#\u003e typic.constraints.error.ConstraintValueError: Tweeter.id: value \u003c0\u003e fails constraints: (type=int, nullable=False, coerce=False, ge=1)\n```\n\n### The Functional API\n\n```python\nimport dataclasses\nfrom typing import Iterable\n\nimport typic\n\n\n@typic.constrained(ge=1)\nclass ID(int):\n    ...\n\n\n@typic.constrained(max_length=280)\nclass Tweet(str):\n    ...\n\n\n@dataclasses.dataclass # or typing.TypedDict or typing.NamedTuple or annotated class...\nclass Tweeter:\n    id: ID\n    tweets: Iterable[Tweet]\n\n\njson = '{\"id\":1,\"tweets\":[\"I don\\'t understand Twitter\"]}'\n\nt = typic.transmute(Tweeter, json)\nprint(t)\n#\u003e Tweeter(id=1, tweets=[\"I don't understand Twitter\"])\n\nprint(typic.tojson(t))\n#\u003e '{\"id\":1,\"tweets\":[\"I don\\'t understand Twitter\"]}'\n\ntypic.validate(Tweeter, {\"id\": 0, \"tweets\": []})\n#\u003e Traceback (most recent call last):\n#\u003e  ...\n#\u003e typic.constraints.error.ConstraintValueError: Tweeter.id: value \u003c0\u003e fails constraints: (type=int, nullable=False, coerce=False, ge=1)\n```\n\n### The Object API\n\n```python\nfrom typing import Iterable\n\nimport typic\n\n\n@typic.constrained(ge=1)\nclass ID(int):\n    ...\n\n\n@typic.constrained(max_length=280)\nclass Tweet(str):\n    ...\n\n\n@typic.klass\nclass Tweeter:\n    id: ID\n    tweets: Iterable[Tweet]\n    \n\njson = '{\"id\":1,\"tweets\":[\"I don\\'t understand Twitter\"]}'\nt = Tweeter.transmute(json)\n\nprint(t)\n#\u003e Tweeter(id=1, tweets=[\"I don't understand Twitter\"])\n\nprint(t.tojson())\n#\u003e '{\"id\":1,\"tweets\":[\"I don\\'t understand Twitter\"]}'\n\nTweeter.validate({\"id\": 0, \"tweets\": []})\n#\u003e Traceback (most recent call last):\n#\u003e  ...\n#\u003e typic.constraints.error.ConstraintValueError: Given value \u003c0\u003e fails constraints: (type=int, nullable=False, coerce=False, ge=1)\n```\n\n\n## Changelog\n\nSee our\n[Releases](https://github.com/seandstewart/typical/releases).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fseandstewart%2Ftypical","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fseandstewart%2Ftypical","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fseandstewart%2Ftypical/lists"}