talea 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- talea-0.1.0/.gitignore +32 -0
- talea-0.1.0/LICENSE +21 -0
- talea-0.1.0/PKG-INFO +317 -0
- talea-0.1.0/README.md +275 -0
- talea-0.1.0/pyproject.toml +183 -0
- talea-0.1.0/talea/__init__.py +51 -0
- talea-0.1.0/talea/codegen.py +25 -0
- talea-0.1.0/talea/constraints.py +179 -0
- talea-0.1.0/talea/contract/__init__.py +5 -0
- talea-0.1.0/talea/contract/api.py +247 -0
- talea-0.1.0/talea/contract/artifacts.py +67 -0
- talea-0.1.0/talea/declaration/__init__.py +12 -0
- talea-0.1.0/talea/declaration/metadata.py +26 -0
- talea-0.1.0/talea/declaration/models.py +291 -0
- talea-0.1.0/talea/declaration/policies.py +256 -0
- talea-0.1.0/talea/errors/__init__.py +6 -0
- talea-0.1.0/talea/errors/codes.py +37 -0
- talea-0.1.0/talea/errors/models.py +619 -0
- talea-0.1.0/talea/errors/safety.py +100 -0
- talea-0.1.0/talea/input/__init__.py +3 -0
- talea-0.1.0/talea/input/artifacts.py +151 -0
- talea-0.1.0/talea/input/compilation.py +427 -0
- talea-0.1.0/talea/input/current.py +209 -0
- talea-0.1.0/talea/input/emission.py +911 -0
- talea-0.1.0/talea/input/json.py +144 -0
- talea-0.1.0/talea/input/references.py +100 -0
- talea-0.1.0/talea/input/value.py +57 -0
- talea-0.1.0/talea/introspection.py +349 -0
- talea-0.1.0/talea/json/__init__.py +3 -0
- talea-0.1.0/talea/json/representations.py +108 -0
- talea-0.1.0/talea/json_schema/__init__.py +5 -0
- talea-0.1.0/talea/json_schema/api.py +47 -0
- talea-0.1.0/talea/json_schema/errors.py +13 -0
- talea-0.1.0/talea/json_schema/projection.py +563 -0
- talea-0.1.0/talea/metadata/__init__.py +298 -0
- talea-0.1.0/talea/py.typed +1 -0
- talea-0.1.0/talea/resources/__init__.py +6 -0
- talea-0.1.0/talea/resources/errors.py +29 -0
- talea-0.1.0/talea/resources/policy.py +65 -0
- talea-0.1.0/talea/resources/state.py +98 -0
- talea-0.1.0/talea/schema/__init__.py +63 -0
- talea-0.1.0/talea/schema/nodes.py +329 -0
- talea-0.1.0/talea/schema/references.py +100 -0
- talea-0.1.0/talea/schema/resolution.py +636 -0
- talea-0.1.0/talea/serialization/__init__.py +6 -0
- talea-0.1.0/talea/serialization/api.py +183 -0
- talea-0.1.0/talea/serialization/artifacts.py +156 -0
- talea-0.1.0/talea/serialization/compilation.py +163 -0
- talea-0.1.0/talea/serialization/declaration.py +77 -0
- talea-0.1.0/talea/serialization/emission.py +641 -0
- talea-0.1.0/talea/serialization/errors.py +53 -0
- talea-0.1.0/talea/serialization/hooks.py +43 -0
- talea-0.1.0/talea/serialization/json.py +49 -0
- talea-0.1.0/talea/serialization/references.py +79 -0
- talea-0.1.0/talea/spec/__init__.py +7 -0
- talea-0.1.0/talea/spec/construction.py +213 -0
- talea-0.1.0/talea/spec/declaration.py +483 -0
- talea-0.1.0/talea/spec/derivation.py +187 -0
- talea-0.1.0/talea/spec/dynamic.py +211 -0
- talea-0.1.0/talea/spec/fields.py +57 -0
- talea-0.1.0/talea/spec/generics.py +227 -0
- talea-0.1.0/talea/spec/hooks.py +127 -0
- talea-0.1.0/talea/spec/lifecycle.py +334 -0
- talea-0.1.0/talea/spec/metaclass.py +458 -0
- talea-0.1.0/talea/spec/presence.py +186 -0
- talea-0.1.0/talea/spec/replacement.py +160 -0
- talea-0.1.0/talea/spec/specialization.py +57 -0
- talea-0.1.0/talea/tagged/__init__.py +24 -0
- talea-0.1.0/talea/tagged/dispatch.py +19 -0
- talea-0.1.0/talea/tagged/validation.py +186 -0
- talea-0.1.0/talea/validation/__init__.py +6 -0
- talea-0.1.0/talea/validation/compilation.py +95 -0
- talea-0.1.0/talea/validation/emission.py +916 -0
- talea-0.1.0/talea/validation/errors.py +5 -0
- talea-0.1.0/talea/validation/failure_contracts.py +166 -0
- talea-0.1.0/talea/validation/references.py +73 -0
talea-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# folders
|
|
2
|
+
*.egg-info/
|
|
3
|
+
.hypothesis/
|
|
4
|
+
.idea/
|
|
5
|
+
.mypy_cache/
|
|
6
|
+
.pytest_cache/
|
|
7
|
+
.scannerwork/
|
|
8
|
+
.tox/
|
|
9
|
+
.venv/
|
|
10
|
+
.vscode/
|
|
11
|
+
__pycache__/
|
|
12
|
+
virtualenv/
|
|
13
|
+
build/
|
|
14
|
+
dist/
|
|
15
|
+
docs/generated/
|
|
16
|
+
node_modules/
|
|
17
|
+
results/
|
|
18
|
+
site/
|
|
19
|
+
site_lang/
|
|
20
|
+
target/
|
|
21
|
+
|
|
22
|
+
# files
|
|
23
|
+
**/*.so
|
|
24
|
+
**/*.sqlite
|
|
25
|
+
*.iml
|
|
26
|
+
**/*_test*
|
|
27
|
+
.DS_Store
|
|
28
|
+
.coverage
|
|
29
|
+
.coverage.*
|
|
30
|
+
.python-version
|
|
31
|
+
coverage.*
|
|
32
|
+
example.sqlite
|
talea-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Tiago Silva.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
talea-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: talea
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Modern Python data contracts with strict validation, serialization, and JSON Schema
|
|
5
|
+
Project-URL: Homepage, https://github.com/tarsil/talea
|
|
6
|
+
Project-URL: Documentation, https://talea.tarsild.io
|
|
7
|
+
Project-URL: Changelog, https://talea.tarsild.io/release-notes/
|
|
8
|
+
Project-URL: Funding, https://github.com/sponsors/tarsil
|
|
9
|
+
Project-URL: Issues, https://github.com/tarsil/talea/issues
|
|
10
|
+
Project-URL: Source, https://github.com/tarsil/talea
|
|
11
|
+
Author-email: Tiago Silva <tiago.arasilva@gmail.com>
|
|
12
|
+
License-Expression: MIT
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Keywords: data-contracts,data-validation,deserialization,json,json-schema,openapi,pure-python,runtime-validation,schema,serialization,strict-validation,structured-data,type-validation,typing,validation,zero-dependencies
|
|
15
|
+
Classifier: Development Status :: 3 - Alpha
|
|
16
|
+
Classifier: Intended Audience :: Developers
|
|
17
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
18
|
+
Classifier: Operating System :: OS Independent
|
|
19
|
+
Classifier: Programming Language :: Python
|
|
20
|
+
Classifier: Programming Language :: Python :: 3
|
|
21
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
23
|
+
Classifier: Topic :: Software Development
|
|
24
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
25
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
26
|
+
Classifier: Typing :: Typed
|
|
27
|
+
Requires-Python: >=3.14
|
|
28
|
+
Provides-Extra: benchmarking
|
|
29
|
+
Requires-Dist: msgspec<1.0.0,>=0.20.0; extra == 'benchmarking'
|
|
30
|
+
Requires-Dist: pydantic<3.0.0,>=2.12.0; extra == 'benchmarking'
|
|
31
|
+
Provides-Extra: testing
|
|
32
|
+
Requires-Dist: autoflake<3.0.0,>=2.0.2; extra == 'testing'
|
|
33
|
+
Requires-Dist: black<25.0,==24.1.1; extra == 'testing'
|
|
34
|
+
Requires-Dist: hypothesis<7.0,>=6.0; extra == 'testing'
|
|
35
|
+
Requires-Dist: isort<6.0.0,>=5.12.0; extra == 'testing'
|
|
36
|
+
Requires-Dist: jsonschema<5.0.0,>=4.26.0; extra == 'testing'
|
|
37
|
+
Requires-Dist: openapi-spec-validator<1.0.0,>=0.9.0; extra == 'testing'
|
|
38
|
+
Requires-Dist: pytest-cov<5.0.0,>=4.0.0; extra == 'testing'
|
|
39
|
+
Requires-Dist: pytest<9.0.0,>=7.2.2; extra == 'testing'
|
|
40
|
+
Requires-Dist: zensical<0.1.0,>=0.0.23; extra == 'testing'
|
|
41
|
+
Description-Content-Type: text/markdown
|
|
42
|
+
|
|
43
|
+
# Talea
|
|
44
|
+
|
|
45
|
+
<p align="center">
|
|
46
|
+
<a href="https://talea.tarsild.io"><img src="https://res.cloudinary.com/dymmond/image/upload/v1787765742/Talea/logo_gn9nx6.png" alt='Talea'></a>
|
|
47
|
+
</p>
|
|
48
|
+
|
|
49
|
+
<p align="center">
|
|
50
|
+
<em>Data contracts, built for modern Python</em>
|
|
51
|
+
</p>
|
|
52
|
+
|
|
53
|
+
<p align="center">
|
|
54
|
+
<a href="https://github.com/tarsil/talea/actions/workflows/test-suite.yml/badge.svg?event=push&branch=main" target="_blank">
|
|
55
|
+
<img src="https://github.com/tarsil/talea/actions/workflows/test-suite.yml/badge.svg?event=push&branch=main" alt="Test Suite">
|
|
56
|
+
</a>
|
|
57
|
+
|
|
58
|
+
<a href="https://pypi.org/project/talea" target="_blank">
|
|
59
|
+
<img src="https://img.shields.io/pypi/v/talea?color=%2334D058&label=pypi%20package" alt="Package version">
|
|
60
|
+
</a>
|
|
61
|
+
|
|
62
|
+
<a href="https://pypi.org/project/talea" target="_blank">
|
|
63
|
+
<img src="https://img.shields.io/pypi/pyversions/talea.svg?color=%2334D058" alt="Supported Python versions">
|
|
64
|
+
</a>
|
|
65
|
+
</p>
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
**Documentation**: [https://talea.tarsild.io](https://talea.tarsild.io) 📚
|
|
70
|
+
|
|
71
|
+
**Source Code**: [https://github.com/tarsil/talea](https://github.com/tarsil/talea)
|
|
72
|
+
|
|
73
|
+
**The official supported version is always the latest released**.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
Talea is a **2026+ Python data-contract library** for applications that want
|
|
78
|
+
strict Python semantics, explicit external boundaries, immutable records, and
|
|
79
|
+
standards-aware schemas without a required runtime dependency graph.
|
|
80
|
+
|
|
81
|
+
It is built for Python 3.14 and newer. An annotation is resolved once into one
|
|
82
|
+
canonical contract, then Talea compiles specialized pure-Python operations for
|
|
83
|
+
construction, external Mapping input, JSON input, Python output, JSON output,
|
|
84
|
+
and schema projection.
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
from typing import Annotated
|
|
88
|
+
from uuid import UUID
|
|
89
|
+
|
|
90
|
+
from talea import Alias, MinLength, Sensitive, Spec
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class Credentials(Spec):
|
|
94
|
+
token: Annotated[str, Sensitive(), MinLength(16)]
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class UserCreate(Spec):
|
|
98
|
+
user_id: Annotated[UUID, Alias("id")]
|
|
99
|
+
display_name: Annotated[str, Alias("displayName"), MinLength(1)]
|
|
100
|
+
credentials: Credentials
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
request = UserCreate.from_json(
|
|
104
|
+
"""{
|
|
105
|
+
"id": "12345678-1234-5678-1234-567812345678",
|
|
106
|
+
"displayName": "Ada Lovelace",
|
|
107
|
+
"credentials": {"token": "correct-horse-battery-staple"}
|
|
108
|
+
}"""
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
assert request.user_id == UUID("12345678-1234-5678-1234-567812345678")
|
|
112
|
+
assert request.display_name == "Ada Lovelace"
|
|
113
|
+
assert "correct-horse-battery-staple" not in repr(request)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
The conversion above is deliberately attached to `from_json()`. Ordinary
|
|
117
|
+
Python construction is strict:
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
UserCreate(
|
|
121
|
+
user_id="12345678-1234-5678-1234-567812345678", # ValidationError
|
|
122
|
+
display_name="Ada Lovelace",
|
|
123
|
+
credentials=Credentials(token="correct-horse-battery-staple"),
|
|
124
|
+
)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
A UUID field accepts a Python `UUID` on the trusted path. JSON has no UUID
|
|
128
|
+
value, so the JSON boundary owns its documented string representation. That
|
|
129
|
+
separation is the core of Talea's mental model: conversion is explicit, and
|
|
130
|
+
already-valid Python values do not pass through a general parsing pipeline.
|
|
131
|
+
|
|
132
|
+
## Why Talea exists
|
|
133
|
+
|
|
134
|
+
Python applications often need more than a typed record. At an API, event,
|
|
135
|
+
configuration, or third-party boundary they need to answer all of these
|
|
136
|
+
questions consistently:
|
|
137
|
+
|
|
138
|
+
- Which Python values are valid without conversion?
|
|
139
|
+
- Which external representations are accepted from Mapping and JSON input?
|
|
140
|
+
- Where does hostile input receive finite work and error budgets?
|
|
141
|
+
- What locations and stable codes does invalid nested data produce?
|
|
142
|
+
- Which names and representations appear in serialized output?
|
|
143
|
+
- Can a framework project the same contract as Draft 2020-12 JSON Schema or
|
|
144
|
+
an OpenAPI 3.1 Schema Object?
|
|
145
|
+
- Can tooling inspect the contract without reconstructing annotations?
|
|
146
|
+
|
|
147
|
+
Talea answers them from one canonical schema graph, while retaining separate
|
|
148
|
+
execution paths for operations that have different trust and performance
|
|
149
|
+
requirements.
|
|
150
|
+
|
|
151
|
+
“2026+” describes that starting point. Talea began with Python 3.14+, PEP 695
|
|
152
|
+
generics, deferred annotations, recursive type graphs, current typing behavior,
|
|
153
|
+
and modern JSON Schema as architectural assumptions. It did not need to carry
|
|
154
|
+
compatibility requirements for historical Python releases or retrofit those
|
|
155
|
+
assumptions into an older public contract. This is a design circumstance—not a
|
|
156
|
+
claim that mature libraries are obsolete, a prediction of ecosystem
|
|
157
|
+
replacement, or a guarantee of future superiority.
|
|
158
|
+
|
|
159
|
+
## The boundary model
|
|
160
|
+
|
|
161
|
+
| Operation | Use it when | What it does |
|
|
162
|
+
| --- | --- | --- |
|
|
163
|
+
| `User(...)` | application code already has Python values | strict, keyword-only construction |
|
|
164
|
+
| `Contract(T).validate(value)` | an arbitrary root is already Python-shaped | strict validation without conversion |
|
|
165
|
+
| `User.from_mapping(data)` | an external Python Mapping represents an object | structural conversion with finite traversal policy |
|
|
166
|
+
| `Contract(T).from_python(data)` | an external root may be a list, union, alias, or TypedDict | structural conversion with finite traversal policy |
|
|
167
|
+
| `from_json(data)` | text or bytes crosses a serialized boundary | strict decoding, JSON representations, conversion, and resource policy |
|
|
168
|
+
| `to_dict()` / `to_python()` | an application needs detached Python output | schema-aware projection and current-state validation |
|
|
169
|
+
| `to_json()` | an application needs JSON text | schema-aware projection followed by encoding |
|
|
170
|
+
| `json_schema()` / `openapi_schema()` | tooling needs a standards description | projection from the same canonical graph |
|
|
171
|
+
|
|
172
|
+
JSON and Mapping boundaries are not aliases for the constructor. For example,
|
|
173
|
+
`Decimal`, UUID, temporal values, paths, IP values, bytes, enums, nested Specs,
|
|
174
|
+
and tagged unions each retain an explicit Python contract and an explicit JSON
|
|
175
|
+
representation.
|
|
176
|
+
|
|
177
|
+
## What is implemented
|
|
178
|
+
|
|
179
|
+
Talea currently provides:
|
|
180
|
+
|
|
181
|
+
- strict, keyword-only, immutable, slotted `Spec` records;
|
|
182
|
+
- defaults and factories, inheritance, safe narrowing, custom transforms,
|
|
183
|
+
field checks, whole-Spec checks, and serializers;
|
|
184
|
+
- built-in numeric, length, and pattern constraints carried by `Annotated`;
|
|
185
|
+
- aliases, titles, descriptions, examples, deprecation, read/write metadata,
|
|
186
|
+
and sensitive-value handling;
|
|
187
|
+
- `Contract` for primitives, containers, unions, `TypedDict`, type aliases,
|
|
188
|
+
recursive graphs, tagged unions, and concrete generic specializations;
|
|
189
|
+
- first-class Mapping and JSON input with structured nested errors;
|
|
190
|
+
- finite transport-size, depth, traversal-node, and error-aggregation policy;
|
|
191
|
+
- presence-aware partial Specs, `derive_spec()`, and `apply_patch()` for PATCH
|
|
192
|
+
semantics where absent is not confused with `None`;
|
|
193
|
+
- canonical discriminator-based union dispatch and OpenAPI discriminator maps;
|
|
194
|
+
- Python and JSON serialization with explicit per-call codec boundaries;
|
|
195
|
+
- JSON Schema Draft 2020-12 and OpenAPI 3.1-compatible Schema Objects;
|
|
196
|
+
- public immutable introspection and runtime `create_spec()` declarations;
|
|
197
|
+
- compile-once specialized pure-Python execution with permanent benchmark
|
|
198
|
+
canaries for distinct workloads.
|
|
199
|
+
|
|
200
|
+
The documentation proves these features with executable account API, REST
|
|
201
|
+
PATCH, event, financial, recursive AST, arbitrary Contract, error/security,
|
|
202
|
+
schema/OpenAPI, dynamic declaration, and immutable replacement examples.
|
|
203
|
+
|
|
204
|
+
## A complete service boundary
|
|
205
|
+
|
|
206
|
+
A framework-neutral request flow looks like this:
|
|
207
|
+
|
|
208
|
+
```text
|
|
209
|
+
raw request bytes
|
|
210
|
+
-> ResourcePolicy
|
|
211
|
+
-> UserCreate.from_json(...)
|
|
212
|
+
-> ValidationError or ResourceLimitError
|
|
213
|
+
-> application/domain operation
|
|
214
|
+
-> UserResponse
|
|
215
|
+
-> to_json()
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Talea does not choose routes, dependency injection, HTTP status codes, ORM
|
|
219
|
+
behavior, or response envelopes. A FastAPI, Lilya, Django, Starlette, Flask, or
|
|
220
|
+
other adapter can own those framework concerns while calling the explicit
|
|
221
|
+
Talea boundary operations. The manual includes the entire executable flow,
|
|
222
|
+
plus presence-aware PATCH and generated input/output OpenAPI fragments.
|
|
223
|
+
|
|
224
|
+
## Installation
|
|
225
|
+
|
|
226
|
+
Talea requires Python 3.14+. Install the published release from PyPI:
|
|
227
|
+
|
|
228
|
+
```console
|
|
229
|
+
python -m pip install talea
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
To install from a source checkout instead:
|
|
233
|
+
|
|
234
|
+
```console
|
|
235
|
+
git clone https://github.com/tarsil/talea.git
|
|
236
|
+
cd talea
|
|
237
|
+
python -m pip install .
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
The core package declares `dependencies = []`. Development, test, benchmark,
|
|
241
|
+
build, and documentation tools remain separate development dependencies.
|
|
242
|
+
|
|
243
|
+
## Not a competition
|
|
244
|
+
|
|
245
|
+
Talea is not trying to replace Pydantic, msgspec, dataclasses, attrs, or
|
|
246
|
+
manually written validation.
|
|
247
|
+
|
|
248
|
+
Pydantic has broad adoption, extensive integrations, a mature ecosystem, and
|
|
249
|
+
coercive/parsing workflows many applications actively want. msgspec has an
|
|
250
|
+
extremely fast native implementation, mature serialization, and a different
|
|
251
|
+
set of representation and performance tradeoffs. Dataclasses and attrs remain
|
|
252
|
+
excellent for internal records that do not need a full external-boundary
|
|
253
|
+
contract. Direct Python is often clearest for three checks in one specialized
|
|
254
|
+
function.
|
|
255
|
+
|
|
256
|
+
Talea is another design point: strict, dependency-light, Python-native,
|
|
257
|
+
compile-once, explicit-boundary, introspectable, standards-aware, and
|
|
258
|
+
security-conscious. Selection is a requirements decision, not a winner/loser
|
|
259
|
+
ranking.
|
|
260
|
+
|
|
261
|
+
## When Talea fits—and when it does not
|
|
262
|
+
|
|
263
|
+
Talea is worth evaluating when a project uses Python 3.14+, wants strict
|
|
264
|
+
ordinary Python construction, needs Mapping or JSON boundaries, values an
|
|
265
|
+
empty required dependency graph, and can benefit from structured errors,
|
|
266
|
+
finite external-input policy, schemas, or framework introspection.
|
|
267
|
+
|
|
268
|
+
It is likely the wrong choice when:
|
|
269
|
+
|
|
270
|
+
- the application depends heavily on Pydantic-specific integrations or wants
|
|
271
|
+
broad coercion by default;
|
|
272
|
+
- Python 3.13 or earlier must remain supported;
|
|
273
|
+
- settings, ORM extraction, or a large plugin ecosystem must come from the
|
|
274
|
+
same package;
|
|
275
|
+
- msgspec already exactly matches a high-throughput native serialization
|
|
276
|
+
workflow;
|
|
277
|
+
- the only requirement is a small internal record, where a dataclass or attrs
|
|
278
|
+
class is simpler;
|
|
279
|
+
- specialized validation is shorter and clearer as manually written Python;
|
|
280
|
+
- adopting a pre-1.0 library with a small ecosystem is unacceptable.
|
|
281
|
+
|
|
282
|
+
## Documentation
|
|
283
|
+
|
|
284
|
+
- [Documentation home](https://talea.tarsild.io)
|
|
285
|
+
- [Why Talea?](https://talea.tarsild.io/getting-started/why-talea/)
|
|
286
|
+
- [Five-minute quickstart](https://talea.tarsild.io/getting-started/quickstart/)
|
|
287
|
+
- [Progressive tutorial](https://talea.tarsild.io/getting-started/tutorial/)
|
|
288
|
+
- [Production service boundary](https://talea.tarsild.io/getting-started/production-service/)
|
|
289
|
+
- [Concepts and mental model](https://talea.tarsild.io/concepts/)
|
|
290
|
+
- [How-to recipes](https://talea.tarsild.io/guides/recipes/)
|
|
291
|
+
- [Complete API reference](https://talea.tarsild.io/reference/api/)
|
|
292
|
+
- [Security and resource model](https://talea.tarsild.io/resource-security/)
|
|
293
|
+
- [Performance method and evidence](https://talea.tarsild.io/engineering/performance/)
|
|
294
|
+
- [Known limitations](https://talea.tarsild.io/engineering/limitations/)
|
|
295
|
+
|
|
296
|
+
For a local checkout, `task docs_test` executes all `docs_src` examples and
|
|
297
|
+
checks navigation, links, API inventory, and documentation policy. `task build`
|
|
298
|
+
builds the site; `task build_with_checks` verifies release artifacts.
|
|
299
|
+
|
|
300
|
+
## Maturity and evidence
|
|
301
|
+
|
|
302
|
+
Talea is pre-1.0. Compatibility, deprecation, support, and release governance
|
|
303
|
+
are not yet frozen, and its ecosystem is necessarily much smaller than mature
|
|
304
|
+
alternatives. The project does not call that tradeoff complete or invisible.
|
|
305
|
+
|
|
306
|
+
Repository gates include unit and integration tests, 100% line coverage,
|
|
307
|
+
linting, formatting, static typing, package checks, executable documentation,
|
|
308
|
+
standards-conformance tests, security/adversarial cases, and 18 permanent
|
|
309
|
+
benchmark workloads. Performance comparisons require semantically equivalent
|
|
310
|
+
operations; no claim is based on removing validation from one side.
|
|
311
|
+
|
|
312
|
+
See [Contributing](https://talea.tarsild.io/contributing/) for exact commands,
|
|
313
|
+
[Maturity and support](https://talea.tarsild.io/release-ledger/) for current
|
|
314
|
+
governance, and [Security](https://talea.tarsild.io/engineering/security/) for
|
|
315
|
+
the technical threat model and reporting status.
|
|
316
|
+
|
|
317
|
+
Talea is licensed under the MIT License.
|
talea-0.1.0/README.md
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
# Talea
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<a href="https://talea.tarsild.io"><img src="https://res.cloudinary.com/dymmond/image/upload/v1787765742/Talea/logo_gn9nx6.png" alt='Talea'></a>
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<em>Data contracts, built for modern Python</em>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://github.com/tarsil/talea/actions/workflows/test-suite.yml/badge.svg?event=push&branch=main" target="_blank">
|
|
13
|
+
<img src="https://github.com/tarsil/talea/actions/workflows/test-suite.yml/badge.svg?event=push&branch=main" alt="Test Suite">
|
|
14
|
+
</a>
|
|
15
|
+
|
|
16
|
+
<a href="https://pypi.org/project/talea" target="_blank">
|
|
17
|
+
<img src="https://img.shields.io/pypi/v/talea?color=%2334D058&label=pypi%20package" alt="Package version">
|
|
18
|
+
</a>
|
|
19
|
+
|
|
20
|
+
<a href="https://pypi.org/project/talea" target="_blank">
|
|
21
|
+
<img src="https://img.shields.io/pypi/pyversions/talea.svg?color=%2334D058" alt="Supported Python versions">
|
|
22
|
+
</a>
|
|
23
|
+
</p>
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
**Documentation**: [https://talea.tarsild.io](https://talea.tarsild.io) 📚
|
|
28
|
+
|
|
29
|
+
**Source Code**: [https://github.com/tarsil/talea](https://github.com/tarsil/talea)
|
|
30
|
+
|
|
31
|
+
**The official supported version is always the latest released**.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
Talea is a **2026+ Python data-contract library** for applications that want
|
|
36
|
+
strict Python semantics, explicit external boundaries, immutable records, and
|
|
37
|
+
standards-aware schemas without a required runtime dependency graph.
|
|
38
|
+
|
|
39
|
+
It is built for Python 3.14 and newer. An annotation is resolved once into one
|
|
40
|
+
canonical contract, then Talea compiles specialized pure-Python operations for
|
|
41
|
+
construction, external Mapping input, JSON input, Python output, JSON output,
|
|
42
|
+
and schema projection.
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
from typing import Annotated
|
|
46
|
+
from uuid import UUID
|
|
47
|
+
|
|
48
|
+
from talea import Alias, MinLength, Sensitive, Spec
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class Credentials(Spec):
|
|
52
|
+
token: Annotated[str, Sensitive(), MinLength(16)]
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class UserCreate(Spec):
|
|
56
|
+
user_id: Annotated[UUID, Alias("id")]
|
|
57
|
+
display_name: Annotated[str, Alias("displayName"), MinLength(1)]
|
|
58
|
+
credentials: Credentials
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
request = UserCreate.from_json(
|
|
62
|
+
"""{
|
|
63
|
+
"id": "12345678-1234-5678-1234-567812345678",
|
|
64
|
+
"displayName": "Ada Lovelace",
|
|
65
|
+
"credentials": {"token": "correct-horse-battery-staple"}
|
|
66
|
+
}"""
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
assert request.user_id == UUID("12345678-1234-5678-1234-567812345678")
|
|
70
|
+
assert request.display_name == "Ada Lovelace"
|
|
71
|
+
assert "correct-horse-battery-staple" not in repr(request)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The conversion above is deliberately attached to `from_json()`. Ordinary
|
|
75
|
+
Python construction is strict:
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
UserCreate(
|
|
79
|
+
user_id="12345678-1234-5678-1234-567812345678", # ValidationError
|
|
80
|
+
display_name="Ada Lovelace",
|
|
81
|
+
credentials=Credentials(token="correct-horse-battery-staple"),
|
|
82
|
+
)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
A UUID field accepts a Python `UUID` on the trusted path. JSON has no UUID
|
|
86
|
+
value, so the JSON boundary owns its documented string representation. That
|
|
87
|
+
separation is the core of Talea's mental model: conversion is explicit, and
|
|
88
|
+
already-valid Python values do not pass through a general parsing pipeline.
|
|
89
|
+
|
|
90
|
+
## Why Talea exists
|
|
91
|
+
|
|
92
|
+
Python applications often need more than a typed record. At an API, event,
|
|
93
|
+
configuration, or third-party boundary they need to answer all of these
|
|
94
|
+
questions consistently:
|
|
95
|
+
|
|
96
|
+
- Which Python values are valid without conversion?
|
|
97
|
+
- Which external representations are accepted from Mapping and JSON input?
|
|
98
|
+
- Where does hostile input receive finite work and error budgets?
|
|
99
|
+
- What locations and stable codes does invalid nested data produce?
|
|
100
|
+
- Which names and representations appear in serialized output?
|
|
101
|
+
- Can a framework project the same contract as Draft 2020-12 JSON Schema or
|
|
102
|
+
an OpenAPI 3.1 Schema Object?
|
|
103
|
+
- Can tooling inspect the contract without reconstructing annotations?
|
|
104
|
+
|
|
105
|
+
Talea answers them from one canonical schema graph, while retaining separate
|
|
106
|
+
execution paths for operations that have different trust and performance
|
|
107
|
+
requirements.
|
|
108
|
+
|
|
109
|
+
“2026+” describes that starting point. Talea began with Python 3.14+, PEP 695
|
|
110
|
+
generics, deferred annotations, recursive type graphs, current typing behavior,
|
|
111
|
+
and modern JSON Schema as architectural assumptions. It did not need to carry
|
|
112
|
+
compatibility requirements for historical Python releases or retrofit those
|
|
113
|
+
assumptions into an older public contract. This is a design circumstance—not a
|
|
114
|
+
claim that mature libraries are obsolete, a prediction of ecosystem
|
|
115
|
+
replacement, or a guarantee of future superiority.
|
|
116
|
+
|
|
117
|
+
## The boundary model
|
|
118
|
+
|
|
119
|
+
| Operation | Use it when | What it does |
|
|
120
|
+
| --- | --- | --- |
|
|
121
|
+
| `User(...)` | application code already has Python values | strict, keyword-only construction |
|
|
122
|
+
| `Contract(T).validate(value)` | an arbitrary root is already Python-shaped | strict validation without conversion |
|
|
123
|
+
| `User.from_mapping(data)` | an external Python Mapping represents an object | structural conversion with finite traversal policy |
|
|
124
|
+
| `Contract(T).from_python(data)` | an external root may be a list, union, alias, or TypedDict | structural conversion with finite traversal policy |
|
|
125
|
+
| `from_json(data)` | text or bytes crosses a serialized boundary | strict decoding, JSON representations, conversion, and resource policy |
|
|
126
|
+
| `to_dict()` / `to_python()` | an application needs detached Python output | schema-aware projection and current-state validation |
|
|
127
|
+
| `to_json()` | an application needs JSON text | schema-aware projection followed by encoding |
|
|
128
|
+
| `json_schema()` / `openapi_schema()` | tooling needs a standards description | projection from the same canonical graph |
|
|
129
|
+
|
|
130
|
+
JSON and Mapping boundaries are not aliases for the constructor. For example,
|
|
131
|
+
`Decimal`, UUID, temporal values, paths, IP values, bytes, enums, nested Specs,
|
|
132
|
+
and tagged unions each retain an explicit Python contract and an explicit JSON
|
|
133
|
+
representation.
|
|
134
|
+
|
|
135
|
+
## What is implemented
|
|
136
|
+
|
|
137
|
+
Talea currently provides:
|
|
138
|
+
|
|
139
|
+
- strict, keyword-only, immutable, slotted `Spec` records;
|
|
140
|
+
- defaults and factories, inheritance, safe narrowing, custom transforms,
|
|
141
|
+
field checks, whole-Spec checks, and serializers;
|
|
142
|
+
- built-in numeric, length, and pattern constraints carried by `Annotated`;
|
|
143
|
+
- aliases, titles, descriptions, examples, deprecation, read/write metadata,
|
|
144
|
+
and sensitive-value handling;
|
|
145
|
+
- `Contract` for primitives, containers, unions, `TypedDict`, type aliases,
|
|
146
|
+
recursive graphs, tagged unions, and concrete generic specializations;
|
|
147
|
+
- first-class Mapping and JSON input with structured nested errors;
|
|
148
|
+
- finite transport-size, depth, traversal-node, and error-aggregation policy;
|
|
149
|
+
- presence-aware partial Specs, `derive_spec()`, and `apply_patch()` for PATCH
|
|
150
|
+
semantics where absent is not confused with `None`;
|
|
151
|
+
- canonical discriminator-based union dispatch and OpenAPI discriminator maps;
|
|
152
|
+
- Python and JSON serialization with explicit per-call codec boundaries;
|
|
153
|
+
- JSON Schema Draft 2020-12 and OpenAPI 3.1-compatible Schema Objects;
|
|
154
|
+
- public immutable introspection and runtime `create_spec()` declarations;
|
|
155
|
+
- compile-once specialized pure-Python execution with permanent benchmark
|
|
156
|
+
canaries for distinct workloads.
|
|
157
|
+
|
|
158
|
+
The documentation proves these features with executable account API, REST
|
|
159
|
+
PATCH, event, financial, recursive AST, arbitrary Contract, error/security,
|
|
160
|
+
schema/OpenAPI, dynamic declaration, and immutable replacement examples.
|
|
161
|
+
|
|
162
|
+
## A complete service boundary
|
|
163
|
+
|
|
164
|
+
A framework-neutral request flow looks like this:
|
|
165
|
+
|
|
166
|
+
```text
|
|
167
|
+
raw request bytes
|
|
168
|
+
-> ResourcePolicy
|
|
169
|
+
-> UserCreate.from_json(...)
|
|
170
|
+
-> ValidationError or ResourceLimitError
|
|
171
|
+
-> application/domain operation
|
|
172
|
+
-> UserResponse
|
|
173
|
+
-> to_json()
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Talea does not choose routes, dependency injection, HTTP status codes, ORM
|
|
177
|
+
behavior, or response envelopes. A FastAPI, Lilya, Django, Starlette, Flask, or
|
|
178
|
+
other adapter can own those framework concerns while calling the explicit
|
|
179
|
+
Talea boundary operations. The manual includes the entire executable flow,
|
|
180
|
+
plus presence-aware PATCH and generated input/output OpenAPI fragments.
|
|
181
|
+
|
|
182
|
+
## Installation
|
|
183
|
+
|
|
184
|
+
Talea requires Python 3.14+. Install the published release from PyPI:
|
|
185
|
+
|
|
186
|
+
```console
|
|
187
|
+
python -m pip install talea
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
To install from a source checkout instead:
|
|
191
|
+
|
|
192
|
+
```console
|
|
193
|
+
git clone https://github.com/tarsil/talea.git
|
|
194
|
+
cd talea
|
|
195
|
+
python -m pip install .
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
The core package declares `dependencies = []`. Development, test, benchmark,
|
|
199
|
+
build, and documentation tools remain separate development dependencies.
|
|
200
|
+
|
|
201
|
+
## Not a competition
|
|
202
|
+
|
|
203
|
+
Talea is not trying to replace Pydantic, msgspec, dataclasses, attrs, or
|
|
204
|
+
manually written validation.
|
|
205
|
+
|
|
206
|
+
Pydantic has broad adoption, extensive integrations, a mature ecosystem, and
|
|
207
|
+
coercive/parsing workflows many applications actively want. msgspec has an
|
|
208
|
+
extremely fast native implementation, mature serialization, and a different
|
|
209
|
+
set of representation and performance tradeoffs. Dataclasses and attrs remain
|
|
210
|
+
excellent for internal records that do not need a full external-boundary
|
|
211
|
+
contract. Direct Python is often clearest for three checks in one specialized
|
|
212
|
+
function.
|
|
213
|
+
|
|
214
|
+
Talea is another design point: strict, dependency-light, Python-native,
|
|
215
|
+
compile-once, explicit-boundary, introspectable, standards-aware, and
|
|
216
|
+
security-conscious. Selection is a requirements decision, not a winner/loser
|
|
217
|
+
ranking.
|
|
218
|
+
|
|
219
|
+
## When Talea fits—and when it does not
|
|
220
|
+
|
|
221
|
+
Talea is worth evaluating when a project uses Python 3.14+, wants strict
|
|
222
|
+
ordinary Python construction, needs Mapping or JSON boundaries, values an
|
|
223
|
+
empty required dependency graph, and can benefit from structured errors,
|
|
224
|
+
finite external-input policy, schemas, or framework introspection.
|
|
225
|
+
|
|
226
|
+
It is likely the wrong choice when:
|
|
227
|
+
|
|
228
|
+
- the application depends heavily on Pydantic-specific integrations or wants
|
|
229
|
+
broad coercion by default;
|
|
230
|
+
- Python 3.13 or earlier must remain supported;
|
|
231
|
+
- settings, ORM extraction, or a large plugin ecosystem must come from the
|
|
232
|
+
same package;
|
|
233
|
+
- msgspec already exactly matches a high-throughput native serialization
|
|
234
|
+
workflow;
|
|
235
|
+
- the only requirement is a small internal record, where a dataclass or attrs
|
|
236
|
+
class is simpler;
|
|
237
|
+
- specialized validation is shorter and clearer as manually written Python;
|
|
238
|
+
- adopting a pre-1.0 library with a small ecosystem is unacceptable.
|
|
239
|
+
|
|
240
|
+
## Documentation
|
|
241
|
+
|
|
242
|
+
- [Documentation home](https://talea.tarsild.io)
|
|
243
|
+
- [Why Talea?](https://talea.tarsild.io/getting-started/why-talea/)
|
|
244
|
+
- [Five-minute quickstart](https://talea.tarsild.io/getting-started/quickstart/)
|
|
245
|
+
- [Progressive tutorial](https://talea.tarsild.io/getting-started/tutorial/)
|
|
246
|
+
- [Production service boundary](https://talea.tarsild.io/getting-started/production-service/)
|
|
247
|
+
- [Concepts and mental model](https://talea.tarsild.io/concepts/)
|
|
248
|
+
- [How-to recipes](https://talea.tarsild.io/guides/recipes/)
|
|
249
|
+
- [Complete API reference](https://talea.tarsild.io/reference/api/)
|
|
250
|
+
- [Security and resource model](https://talea.tarsild.io/resource-security/)
|
|
251
|
+
- [Performance method and evidence](https://talea.tarsild.io/engineering/performance/)
|
|
252
|
+
- [Known limitations](https://talea.tarsild.io/engineering/limitations/)
|
|
253
|
+
|
|
254
|
+
For a local checkout, `task docs_test` executes all `docs_src` examples and
|
|
255
|
+
checks navigation, links, API inventory, and documentation policy. `task build`
|
|
256
|
+
builds the site; `task build_with_checks` verifies release artifacts.
|
|
257
|
+
|
|
258
|
+
## Maturity and evidence
|
|
259
|
+
|
|
260
|
+
Talea is pre-1.0. Compatibility, deprecation, support, and release governance
|
|
261
|
+
are not yet frozen, and its ecosystem is necessarily much smaller than mature
|
|
262
|
+
alternatives. The project does not call that tradeoff complete or invisible.
|
|
263
|
+
|
|
264
|
+
Repository gates include unit and integration tests, 100% line coverage,
|
|
265
|
+
linting, formatting, static typing, package checks, executable documentation,
|
|
266
|
+
standards-conformance tests, security/adversarial cases, and 18 permanent
|
|
267
|
+
benchmark workloads. Performance comparisons require semantically equivalent
|
|
268
|
+
operations; no claim is based on removing validation from one side.
|
|
269
|
+
|
|
270
|
+
See [Contributing](https://talea.tarsild.io/contributing/) for exact commands,
|
|
271
|
+
[Maturity and support](https://talea.tarsild.io/release-ledger/) for current
|
|
272
|
+
governance, and [Security](https://talea.tarsild.io/engineering/security/) for
|
|
273
|
+
the technical threat model and reporting status.
|
|
274
|
+
|
|
275
|
+
Talea is licensed under the MIT License.
|