pydandict 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.
- pydandict-0.1.0/LICENSE +21 -0
- pydandict-0.1.0/PKG-INFO +211 -0
- pydandict-0.1.0/README.md +182 -0
- pydandict-0.1.0/pyproject.toml +58 -0
- pydandict-0.1.0/setup.cfg +4 -0
- pydandict-0.1.0/src/pydandict/__init__.py +5 -0
- pydandict-0.1.0/src/pydandict/_containers.py +366 -0
- pydandict-0.1.0/src/pydandict/_core.py +899 -0
- pydandict-0.1.0/src/pydandict/py.typed +0 -0
- pydandict-0.1.0/src/pydandict.egg-info/PKG-INFO +211 -0
- pydandict-0.1.0/src/pydandict.egg-info/SOURCES.txt +15 -0
- pydandict-0.1.0/src/pydandict.egg-info/dependency_links.txt +1 -0
- pydandict-0.1.0/src/pydandict.egg-info/requires.txt +11 -0
- pydandict-0.1.0/src/pydandict.egg-info/top_level.txt +1 -0
- pydandict-0.1.0/tests/test_inventory.py +445 -0
- pydandict-0.1.0/tests/test_prototype.py +529 -0
- pydandict-0.1.0/tests/test_stateful.py +130 -0
pydandict-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Pydandict contributors
|
|
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.
|
pydandict-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pydandict
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Pydantic models with validated mapping semantics
|
|
5
|
+
Author: Pydandict contributors
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Classifier: Development Status :: 3 - Alpha
|
|
8
|
+
Classifier: Intended Audience :: Developers
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
14
|
+
Classifier: Typing :: Typed
|
|
15
|
+
Requires-Python: >=3.11
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: pydantic==2.13.4
|
|
19
|
+
Provides-Extra: dev
|
|
20
|
+
Requires-Dist: build; extra == "dev"
|
|
21
|
+
Requires-Dist: fastapi==0.141.1; extra == "dev"
|
|
22
|
+
Requires-Dist: httpx==0.28.1; extra == "dev"
|
|
23
|
+
Requires-Dist: hypothesis; extra == "dev"
|
|
24
|
+
Requires-Dist: pyright==1.1.411; extra == "dev"
|
|
25
|
+
Requires-Dist: pytest; extra == "dev"
|
|
26
|
+
Requires-Dist: ruff; extra == "dev"
|
|
27
|
+
Requires-Dist: twine; extra == "dev"
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
# PydanDict
|
|
31
|
+
|
|
32
|
+
**Pydantic models with dictionary semantics.**
|
|
33
|
+
|
|
34
|
+
PydanDict is a Python library whose primary base class, `DictModel`, is
|
|
35
|
+
both a genuine Pydantic `BaseModel` and a Python mutable mapping. It is designed
|
|
36
|
+
to let existing mapping-oriented code consume models directly, and to let
|
|
37
|
+
package authors keep internal records valid as they change.
|
|
38
|
+
|
|
39
|
+
**Status: Phase 0.1 implementation baseline.** The installable source package is in
|
|
40
|
+
[`src/pydandict`](src/pydandict/__init__.py), at release version `0.1.0`.
|
|
41
|
+
It has 87 passing runtime tests, installed typing checks and working library/FastAPI
|
|
42
|
+
consumers in the recorded dependency envelope. See the [findings and limitations](docs/research/prototype-findings.md)
|
|
43
|
+
for exact evidence. The package is a release candidate and is not published yet;
|
|
44
|
+
the original [prototype guide](prototypes/README.md) remains as a reproducible evidence fixture.
|
|
45
|
+
|
|
46
|
+
The plan prioritizes a dependable dependency: atomic failure behavior, protected
|
|
47
|
+
nested values, complete public typing, tested ecosystem compatibility, measured
|
|
48
|
+
costs, and verified distribution artifacts. Start with the
|
|
49
|
+
[roadmap](ROADMAP.md), [implementation work packages](docs/implementation-plan.md),
|
|
50
|
+
and [quality bar](docs/quality-bar.md). Qualification uses automated consumer
|
|
51
|
+
projects and maintainer checks; no external trials or participants are required.
|
|
52
|
+
|
|
53
|
+
For a local Phase 0.1 checkout, install the package and development tools with
|
|
54
|
+
`python -m pip install -e ".[dev]"`. A public install command will be documented
|
|
55
|
+
when the release is published.
|
|
56
|
+
|
|
57
|
+
## One model, two ways to work
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
from collections.abc import Mapping, MutableMapping
|
|
61
|
+
|
|
62
|
+
from pydantic import BaseModel, Field, ValidationError
|
|
63
|
+
from pydandict import DictModel
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class User(DictModel):
|
|
67
|
+
name: str
|
|
68
|
+
age: int = Field(ge=0)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
user = User(name="Eddie", age=40)
|
|
72
|
+
assert user.name == user["name"] == "Eddie"
|
|
73
|
+
|
|
74
|
+
user["age"] = 41
|
|
75
|
+
assert user.age == 41
|
|
76
|
+
|
|
77
|
+
try:
|
|
78
|
+
user["age"] = -1
|
|
79
|
+
except ValidationError:
|
|
80
|
+
assert user.age == 41 # Failed mutations leave the model unchanged.
|
|
81
|
+
|
|
82
|
+
assert isinstance(user, BaseModel)
|
|
83
|
+
assert isinstance(user, Mapping)
|
|
84
|
+
assert isinstance(user, MutableMapping)
|
|
85
|
+
assert list(user) == ["name", "age"]
|
|
86
|
+
assert dict(user) == {"name": "Eddie", "age": 41}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Attribute and mapping access address the same model state. Pydantic supplies
|
|
90
|
+
validation, field definitions, serializers, and JSON Schema. PydanDict supplies
|
|
91
|
+
mapping behavior and a transaction boundary around supported mutations.
|
|
92
|
+
|
|
93
|
+
## For existing Python systems
|
|
94
|
+
|
|
95
|
+
An API written against `Mapping[str, object]` should need no PydanDict-specific
|
|
96
|
+
branch, adapter, or `model_dump()` call:
|
|
97
|
+
|
|
98
|
+
```python
|
|
99
|
+
from collections.abc import Mapping
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def describe(record: Mapping[str, object]) -> str:
|
|
103
|
+
return ", ".join(f"{key}={value}" for key, value in record.items())
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
description = describe(user)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The target includes `[]`, `get`, containment, key iteration, live mapping views,
|
|
110
|
+
`dict(model)`, and keyword unpacking. It does not include `isinstance(model, dict)`
|
|
111
|
+
or compatibility with APIs that insist on a concrete built-in dictionary.
|
|
112
|
+
`dict(model)` is a shallow mapping copy; `model_dump()` is the serialization API.
|
|
113
|
+
|
|
114
|
+
## For package internals
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
from pydantic import Field
|
|
118
|
+
from pydandict import DictModel
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class RetryConfig(DictModel):
|
|
122
|
+
timeout: float = Field(default=30.0, gt=0)
|
|
123
|
+
retries: int = Field(default=3, ge=0)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
config = RetryConfig()
|
|
127
|
+
config.update(timeout=60.0, retries=5) # One validation transaction.
|
|
128
|
+
assert config.timeout == config["timeout"] == 60.0
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Successful writes must satisfy the complete model contract. Failed writes must
|
|
132
|
+
preserve values and model metadata. Required fields cannot disappear; the
|
|
133
|
+
proposed deletion policy protects all declared fields, with an explicit `reset`
|
|
134
|
+
operation for defaults. Extras follow a documented Pydantic configuration policy.
|
|
135
|
+
|
|
136
|
+
**Continuous validation is a release requirement, including nested mutations.**
|
|
137
|
+
It cannot be delivered merely by enabling `validate_assignment`. The design
|
|
138
|
+
requires ownership and mutation guards for supported mutable values, validation
|
|
139
|
+
of affected parent constraints, and rejection of values that cannot be protected.
|
|
140
|
+
The exact supported value set and guard implementation remain Phase 0.2 hardening gates;
|
|
141
|
+
there is no silent fallback to unvalidated nested state. See
|
|
142
|
+
[mutation semantics](docs/mutation-semantics.md) and
|
|
143
|
+
[nested ownership](docs/nested-values.md).
|
|
144
|
+
|
|
145
|
+
## A Pydantic model for FastAPI
|
|
146
|
+
|
|
147
|
+
The intended integration uses ordinary model annotations:
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
from fastapi import FastAPI
|
|
151
|
+
|
|
152
|
+
app = FastAPI()
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
@app.post("/users", response_model=User)
|
|
156
|
+
def create_user(user: User) -> User:
|
|
157
|
+
user.update(age=user.age + 1)
|
|
158
|
+
return user
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Request parsing, response serialization, and OpenAPI should continue through
|
|
162
|
+
Pydantic. This is an acceptance target, with explicit integration tests required
|
|
163
|
+
before a release. See the [compatibility plan](docs/compatibility.md).
|
|
164
|
+
|
|
165
|
+
## Scope and typing
|
|
166
|
+
|
|
167
|
+
V1 centers on schema-defined `DictModel` records. It excludes a public `TypedMap`,
|
|
168
|
+
replacement `TypedDict`, generalized collection framework, persistence,
|
|
169
|
+
reactivity, and a new validation engine. Internal guards needed to protect model
|
|
170
|
+
fields are part of validation, not separate collection products.
|
|
171
|
+
|
|
172
|
+
Pyright support is a first-class requirement: attributes retain their declared
|
|
173
|
+
types, while generic mapping reads return `object` and require narrowing. Automatic
|
|
174
|
+
per-key inference such as `user["age"] -> int` is not promised by the base class.
|
|
175
|
+
See the [typing strategy](docs/typing.md).
|
|
176
|
+
|
|
177
|
+
## Read the plan
|
|
178
|
+
|
|
179
|
+
| Document | Purpose |
|
|
180
|
+
| --- | --- |
|
|
181
|
+
| [Phase 0.1 package](src/pydandict/__init__.py) | Installable `DictModel` implementation |
|
|
182
|
+
| [Prototype guide](prototypes/README.md) | Reproducible evidence commands and runnable example |
|
|
183
|
+
| [Prototype findings](docs/research/prototype-findings.md) | Demonstrated solutions, evidence and remaining limitations |
|
|
184
|
+
| [Documentation index](docs/README.md) | Reading paths and requirement traceability |
|
|
185
|
+
| [Product and scope](docs/product.md) | Audiences, use cases, success criteria |
|
|
186
|
+
| [Architecture](docs/architecture.md) | BaseModel integration and transactional state |
|
|
187
|
+
| [API specification](docs/api.md) | Mapping surface, names, return values, errors |
|
|
188
|
+
| [Mutation semantics](docs/mutation-semantics.md) | Invariants, atomicity, deletion, defaults, extras |
|
|
189
|
+
| [Nested values](docs/nested-values.md) | Ownership, escaped references, parent validation |
|
|
190
|
+
| [Typing](docs/typing.md) | Pyright, protocols, limitations, typing checks |
|
|
191
|
+
| [Compatibility](docs/compatibility.md) | Pydantic, serialization, schema, FastAPI |
|
|
192
|
+
| [Interoperability](docs/interoperability.md) | What existing consumers can and cannot assume |
|
|
193
|
+
| [Competition](docs/competitive-landscape.md) | Alternatives and focused positioning |
|
|
194
|
+
| [Testing](docs/testing.md) | Acceptance cases and release gates |
|
|
195
|
+
| [Roadmap](ROADMAP.md) | Sequenced implementation and release policy |
|
|
196
|
+
| [Implementation work packages](docs/implementation-plan.md) | Priorities, dependencies, first increments and stop criteria |
|
|
197
|
+
| [Quality bar](docs/quality-bar.md) | Measurable gates, automated consumer journeys and maintenance standards |
|
|
198
|
+
| [Release automation](docs/release.md) | Tag-gated checks, artifact build, and PyPI Trusted Publishing |
|
|
199
|
+
| [Security and performance](docs/security-performance.md) | Trust boundary, costs, benchmarks |
|
|
200
|
+
| [Decision log](docs/decisions/README.md) | Established requirements and proposed choices |
|
|
201
|
+
| [Upstream evidence](docs/research/upstream-behavior.md) | Sources and reproducible baseline observations |
|
|
202
|
+
|
|
203
|
+
## Contributing
|
|
204
|
+
|
|
205
|
+
Start with [CONTRIBUTING.md](CONTRIBUTING.md). Design contributions should identify
|
|
206
|
+
the invariant they preserve and the acceptance test that will prove it. The next
|
|
207
|
+
work is Phase 0.2 hardening and contract finalization on the Phase 0.1 package.
|
|
208
|
+
|
|
209
|
+
The package is distributed under the MIT license; package-name ownership and the
|
|
210
|
+
private security reporting route remain pre-release checks. See [security reporting](SECURITY.md)
|
|
211
|
+
and the [changelog](CHANGELOG.md).
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# PydanDict
|
|
2
|
+
|
|
3
|
+
**Pydantic models with dictionary semantics.**
|
|
4
|
+
|
|
5
|
+
PydanDict is a Python library whose primary base class, `DictModel`, is
|
|
6
|
+
both a genuine Pydantic `BaseModel` and a Python mutable mapping. It is designed
|
|
7
|
+
to let existing mapping-oriented code consume models directly, and to let
|
|
8
|
+
package authors keep internal records valid as they change.
|
|
9
|
+
|
|
10
|
+
**Status: Phase 0.1 implementation baseline.** The installable source package is in
|
|
11
|
+
[`src/pydandict`](src/pydandict/__init__.py), at release version `0.1.0`.
|
|
12
|
+
It has 87 passing runtime tests, installed typing checks and working library/FastAPI
|
|
13
|
+
consumers in the recorded dependency envelope. See the [findings and limitations](docs/research/prototype-findings.md)
|
|
14
|
+
for exact evidence. The package is a release candidate and is not published yet;
|
|
15
|
+
the original [prototype guide](prototypes/README.md) remains as a reproducible evidence fixture.
|
|
16
|
+
|
|
17
|
+
The plan prioritizes a dependable dependency: atomic failure behavior, protected
|
|
18
|
+
nested values, complete public typing, tested ecosystem compatibility, measured
|
|
19
|
+
costs, and verified distribution artifacts. Start with the
|
|
20
|
+
[roadmap](ROADMAP.md), [implementation work packages](docs/implementation-plan.md),
|
|
21
|
+
and [quality bar](docs/quality-bar.md). Qualification uses automated consumer
|
|
22
|
+
projects and maintainer checks; no external trials or participants are required.
|
|
23
|
+
|
|
24
|
+
For a local Phase 0.1 checkout, install the package and development tools with
|
|
25
|
+
`python -m pip install -e ".[dev]"`. A public install command will be documented
|
|
26
|
+
when the release is published.
|
|
27
|
+
|
|
28
|
+
## One model, two ways to work
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
from collections.abc import Mapping, MutableMapping
|
|
32
|
+
|
|
33
|
+
from pydantic import BaseModel, Field, ValidationError
|
|
34
|
+
from pydandict import DictModel
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class User(DictModel):
|
|
38
|
+
name: str
|
|
39
|
+
age: int = Field(ge=0)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
user = User(name="Eddie", age=40)
|
|
43
|
+
assert user.name == user["name"] == "Eddie"
|
|
44
|
+
|
|
45
|
+
user["age"] = 41
|
|
46
|
+
assert user.age == 41
|
|
47
|
+
|
|
48
|
+
try:
|
|
49
|
+
user["age"] = -1
|
|
50
|
+
except ValidationError:
|
|
51
|
+
assert user.age == 41 # Failed mutations leave the model unchanged.
|
|
52
|
+
|
|
53
|
+
assert isinstance(user, BaseModel)
|
|
54
|
+
assert isinstance(user, Mapping)
|
|
55
|
+
assert isinstance(user, MutableMapping)
|
|
56
|
+
assert list(user) == ["name", "age"]
|
|
57
|
+
assert dict(user) == {"name": "Eddie", "age": 41}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Attribute and mapping access address the same model state. Pydantic supplies
|
|
61
|
+
validation, field definitions, serializers, and JSON Schema. PydanDict supplies
|
|
62
|
+
mapping behavior and a transaction boundary around supported mutations.
|
|
63
|
+
|
|
64
|
+
## For existing Python systems
|
|
65
|
+
|
|
66
|
+
An API written against `Mapping[str, object]` should need no PydanDict-specific
|
|
67
|
+
branch, adapter, or `model_dump()` call:
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
from collections.abc import Mapping
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def describe(record: Mapping[str, object]) -> str:
|
|
74
|
+
return ", ".join(f"{key}={value}" for key, value in record.items())
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
description = describe(user)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The target includes `[]`, `get`, containment, key iteration, live mapping views,
|
|
81
|
+
`dict(model)`, and keyword unpacking. It does not include `isinstance(model, dict)`
|
|
82
|
+
or compatibility with APIs that insist on a concrete built-in dictionary.
|
|
83
|
+
`dict(model)` is a shallow mapping copy; `model_dump()` is the serialization API.
|
|
84
|
+
|
|
85
|
+
## For package internals
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
from pydantic import Field
|
|
89
|
+
from pydandict import DictModel
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class RetryConfig(DictModel):
|
|
93
|
+
timeout: float = Field(default=30.0, gt=0)
|
|
94
|
+
retries: int = Field(default=3, ge=0)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
config = RetryConfig()
|
|
98
|
+
config.update(timeout=60.0, retries=5) # One validation transaction.
|
|
99
|
+
assert config.timeout == config["timeout"] == 60.0
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Successful writes must satisfy the complete model contract. Failed writes must
|
|
103
|
+
preserve values and model metadata. Required fields cannot disappear; the
|
|
104
|
+
proposed deletion policy protects all declared fields, with an explicit `reset`
|
|
105
|
+
operation for defaults. Extras follow a documented Pydantic configuration policy.
|
|
106
|
+
|
|
107
|
+
**Continuous validation is a release requirement, including nested mutations.**
|
|
108
|
+
It cannot be delivered merely by enabling `validate_assignment`. The design
|
|
109
|
+
requires ownership and mutation guards for supported mutable values, validation
|
|
110
|
+
of affected parent constraints, and rejection of values that cannot be protected.
|
|
111
|
+
The exact supported value set and guard implementation remain Phase 0.2 hardening gates;
|
|
112
|
+
there is no silent fallback to unvalidated nested state. See
|
|
113
|
+
[mutation semantics](docs/mutation-semantics.md) and
|
|
114
|
+
[nested ownership](docs/nested-values.md).
|
|
115
|
+
|
|
116
|
+
## A Pydantic model for FastAPI
|
|
117
|
+
|
|
118
|
+
The intended integration uses ordinary model annotations:
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
from fastapi import FastAPI
|
|
122
|
+
|
|
123
|
+
app = FastAPI()
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
@app.post("/users", response_model=User)
|
|
127
|
+
def create_user(user: User) -> User:
|
|
128
|
+
user.update(age=user.age + 1)
|
|
129
|
+
return user
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Request parsing, response serialization, and OpenAPI should continue through
|
|
133
|
+
Pydantic. This is an acceptance target, with explicit integration tests required
|
|
134
|
+
before a release. See the [compatibility plan](docs/compatibility.md).
|
|
135
|
+
|
|
136
|
+
## Scope and typing
|
|
137
|
+
|
|
138
|
+
V1 centers on schema-defined `DictModel` records. It excludes a public `TypedMap`,
|
|
139
|
+
replacement `TypedDict`, generalized collection framework, persistence,
|
|
140
|
+
reactivity, and a new validation engine. Internal guards needed to protect model
|
|
141
|
+
fields are part of validation, not separate collection products.
|
|
142
|
+
|
|
143
|
+
Pyright support is a first-class requirement: attributes retain their declared
|
|
144
|
+
types, while generic mapping reads return `object` and require narrowing. Automatic
|
|
145
|
+
per-key inference such as `user["age"] -> int` is not promised by the base class.
|
|
146
|
+
See the [typing strategy](docs/typing.md).
|
|
147
|
+
|
|
148
|
+
## Read the plan
|
|
149
|
+
|
|
150
|
+
| Document | Purpose |
|
|
151
|
+
| --- | --- |
|
|
152
|
+
| [Phase 0.1 package](src/pydandict/__init__.py) | Installable `DictModel` implementation |
|
|
153
|
+
| [Prototype guide](prototypes/README.md) | Reproducible evidence commands and runnable example |
|
|
154
|
+
| [Prototype findings](docs/research/prototype-findings.md) | Demonstrated solutions, evidence and remaining limitations |
|
|
155
|
+
| [Documentation index](docs/README.md) | Reading paths and requirement traceability |
|
|
156
|
+
| [Product and scope](docs/product.md) | Audiences, use cases, success criteria |
|
|
157
|
+
| [Architecture](docs/architecture.md) | BaseModel integration and transactional state |
|
|
158
|
+
| [API specification](docs/api.md) | Mapping surface, names, return values, errors |
|
|
159
|
+
| [Mutation semantics](docs/mutation-semantics.md) | Invariants, atomicity, deletion, defaults, extras |
|
|
160
|
+
| [Nested values](docs/nested-values.md) | Ownership, escaped references, parent validation |
|
|
161
|
+
| [Typing](docs/typing.md) | Pyright, protocols, limitations, typing checks |
|
|
162
|
+
| [Compatibility](docs/compatibility.md) | Pydantic, serialization, schema, FastAPI |
|
|
163
|
+
| [Interoperability](docs/interoperability.md) | What existing consumers can and cannot assume |
|
|
164
|
+
| [Competition](docs/competitive-landscape.md) | Alternatives and focused positioning |
|
|
165
|
+
| [Testing](docs/testing.md) | Acceptance cases and release gates |
|
|
166
|
+
| [Roadmap](ROADMAP.md) | Sequenced implementation and release policy |
|
|
167
|
+
| [Implementation work packages](docs/implementation-plan.md) | Priorities, dependencies, first increments and stop criteria |
|
|
168
|
+
| [Quality bar](docs/quality-bar.md) | Measurable gates, automated consumer journeys and maintenance standards |
|
|
169
|
+
| [Release automation](docs/release.md) | Tag-gated checks, artifact build, and PyPI Trusted Publishing |
|
|
170
|
+
| [Security and performance](docs/security-performance.md) | Trust boundary, costs, benchmarks |
|
|
171
|
+
| [Decision log](docs/decisions/README.md) | Established requirements and proposed choices |
|
|
172
|
+
| [Upstream evidence](docs/research/upstream-behavior.md) | Sources and reproducible baseline observations |
|
|
173
|
+
|
|
174
|
+
## Contributing
|
|
175
|
+
|
|
176
|
+
Start with [CONTRIBUTING.md](CONTRIBUTING.md). Design contributions should identify
|
|
177
|
+
the invariant they preserve and the acceptance test that will prove it. The next
|
|
178
|
+
work is Phase 0.2 hardening and contract finalization on the Phase 0.1 package.
|
|
179
|
+
|
|
180
|
+
The package is distributed under the MIT license; package-name ownership and the
|
|
181
|
+
private security reporting route remain pre-release checks. See [security reporting](SECURITY.md)
|
|
182
|
+
and the [changelog](CHANGELOG.md).
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "pydandict"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Pydantic models with validated mapping semantics"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
authors = [{ name = "Pydandict contributors" }]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 3 - Alpha",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3.11",
|
|
19
|
+
"Programming Language :: Python :: 3.12",
|
|
20
|
+
"Programming Language :: Python :: 3.13",
|
|
21
|
+
"Programming Language :: Python :: 3.14",
|
|
22
|
+
"Typing :: Typed",
|
|
23
|
+
]
|
|
24
|
+
dependencies = ["pydantic==2.13.4"]
|
|
25
|
+
|
|
26
|
+
[project.optional-dependencies]
|
|
27
|
+
dev = [
|
|
28
|
+
"build",
|
|
29
|
+
"fastapi==0.141.1",
|
|
30
|
+
"httpx==0.28.1",
|
|
31
|
+
"hypothesis",
|
|
32
|
+
"pyright==1.1.411",
|
|
33
|
+
"pytest",
|
|
34
|
+
"ruff",
|
|
35
|
+
"twine",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
[tool.setuptools.packages.find]
|
|
39
|
+
where = ["src"]
|
|
40
|
+
|
|
41
|
+
[tool.setuptools.package-data]
|
|
42
|
+
pydandict = ["py.typed"]
|
|
43
|
+
|
|
44
|
+
[tool.pytest.ini_options]
|
|
45
|
+
testpaths = ["tests"]
|
|
46
|
+
|
|
47
|
+
[tool.ruff]
|
|
48
|
+
line-length = 100
|
|
49
|
+
target-version = "py311"
|
|
50
|
+
|
|
51
|
+
[tool.ruff.lint]
|
|
52
|
+
select = ["E", "F", "I"]
|
|
53
|
+
|
|
54
|
+
[tool.pyright]
|
|
55
|
+
include = ["src/pydandict/__init__.py", "tests/typing_positive.py"]
|
|
56
|
+
exclude = ["tests/typing_negative.py"]
|
|
57
|
+
pythonVersion = "3.11"
|
|
58
|
+
typeCheckingMode = "strict"
|