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.
@@ -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.
@@ -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"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,5 @@
1
+ """Pydandict: Pydantic models with validated mapping semantics."""
2
+
3
+ from ._core import DictModel as DictModel
4
+
5
+ __all__ = ["DictModel"]