PydanDict
Pydantic models with dictionary semantics.
PydanDict is a Python library whose primary base class, DictModel, is
both a genuine Pydantic BaseModel and a Python mutable mapping. It is designed
to let existing mapping-oriented code consume models directly, and to let
package authors keep internal records valid as they change.
Status: Phase 0.1 implementation baseline. The installable source package is in
src/pydandict, at release version 0.1.0.
It has 87 passing runtime tests, installed typing checks and working library/FastAPI
consumers in the recorded dependency envelope. See the findings and limitations
for exact evidence. The package is a release candidate and is not published yet;
the original prototype guide remains as a reproducible evidence fixture.
The plan prioritizes a dependable dependency: atomic failure behavior, protected nested values, complete public typing, tested ecosystem compatibility, measured costs, and verified distribution artifacts. Start with the roadmap, implementation work packages, and quality bar. Qualification uses automated consumer projects and maintainer checks; no external trials or participants are required.
For a local Phase 0.1 checkout, install the package and development tools with
python -m pip install -e ".[dev]". A public install command will be documented
when the release is published.
One model, two ways to work
from collections.abc import Mapping, MutableMapping
from pydantic import BaseModel, Field, ValidationError
from pydandict import DictModel
class User(DictModel):
name: str
age: int = Field(ge=0)
user = User(name="Eddie", age=40)
assert user.name == user["name"] == "Eddie"
user["age"] = 41
assert user.age == 41
try:
user["age"] = -1
except ValidationError:
assert user.age == 41 # Failed mutations leave the model unchanged.
assert isinstance(user, BaseModel)
assert isinstance(user, Mapping)
assert isinstance(user, MutableMapping)
assert list(user) == ["name", "age"]
assert dict(user) == {"name": "Eddie", "age": 41}
Attribute and mapping access address the same model state. Pydantic supplies validation, field definitions, serializers, and JSON Schema. PydanDict supplies mapping behavior and a transaction boundary around supported mutations.
For existing Python systems
An API written against Mapping[str, object] should need no PydanDict-specific
branch, adapter, or model_dump() call:
from collections.abc import Mapping
def describe(record: Mapping[str, object]) -> str:
return ", ".join(f"{key}={value}" for key, value in record.items())
description = describe(user)
The target includes [], get, containment, key iteration, live mapping views,
dict(model), and keyword unpacking. It does not include isinstance(model, dict)
or compatibility with APIs that insist on a concrete built-in dictionary.
dict(model) is a shallow mapping copy; model_dump() is the serialization API.
For package internals
from pydantic import Field
from pydandict import DictModel
class RetryConfig(DictModel):
timeout: float = Field(default=30.0, gt=0)
retries: int = Field(default=3, ge=0)
config = RetryConfig()
config.update(timeout=60.0, retries=5) # One validation transaction.
assert config.timeout == config["timeout"] == 60.0
Successful writes must satisfy the complete model contract. Failed writes must
preserve values and model metadata. Required fields cannot disappear; the
proposed deletion policy protects all declared fields, with an explicit reset
operation for defaults. Extras follow a documented Pydantic configuration policy.
Continuous validation is a release requirement, including nested mutations.
It cannot be delivered merely by enabling validate_assignment. The design
requires ownership and mutation guards for supported mutable values, validation
of affected parent constraints, and rejection of values that cannot be protected.
The exact supported value set and guard implementation remain Phase 0.2 hardening gates;
there is no silent fallback to unvalidated nested state. See
mutation semantics and
nested ownership.
A Pydantic model for FastAPI
The intended integration uses ordinary model annotations:
from fastapi import FastAPI
app = FastAPI()
@app.post("/users", response_model=User)
def create_user(user: User) -> User:
user.update(age=user.age + 1)
return user
Request parsing, response serialization, and OpenAPI should continue through Pydantic. This is an acceptance target, with explicit integration tests required before a release. See the compatibility plan.
Scope and typing
V1 centers on schema-defined DictModel records. It excludes a public TypedMap,
replacement TypedDict, generalized collection framework, persistence,
reactivity, and a new validation engine. Internal guards needed to protect model
fields are part of validation, not separate collection products.
Pyright support is a first-class requirement: attributes retain their declared
types, while generic mapping reads return object and require narrowing. Automatic
per-key inference such as user["age"] -> int is not promised by the base class.
See the typing strategy.
Read the plan
| Document | Purpose |
|---|---|
| Phase 0.1 package | Installable DictModel implementation |
| Prototype guide | Reproducible evidence commands and runnable example |
| Prototype findings | Demonstrated solutions, evidence and remaining limitations |
| Documentation index | Reading paths and requirement traceability |
| Product and scope | Audiences, use cases, success criteria |
| Architecture | BaseModel integration and transactional state |
| API specification | Mapping surface, names, return values, errors |
| Mutation semantics | Invariants, atomicity, deletion, defaults, extras |
| Nested values | Ownership, escaped references, parent validation |
| Typing | Pyright, protocols, limitations, typing checks |
| Compatibility | Pydantic, serialization, schema, FastAPI |
| Interoperability | What existing consumers can and cannot assume |
| Competition | Alternatives and focused positioning |
| Testing | Acceptance cases and release gates |
| Roadmap | Sequenced implementation and release policy |
| Implementation work packages | Priorities, dependencies, first increments and stop criteria |
| Quality bar | Measurable gates, automated consumer journeys and maintenance standards |
| Release automation | Tag-gated checks, artifact build, and PyPI Trusted Publishing |
| Security and performance | Trust boundary, costs, benchmarks |
| Decision log | Established requirements and proposed choices |
| Upstream evidence | Sources and reproducible baseline observations |
Contributing
Start with CONTRIBUTING.md. Design contributions should identify the invariant they preserve and the acceptance test that will prove it. The next work is Phase 0.2 hardening and contract finalization on the Phase 0.1 package.
The package is distributed under the MIT license; package-name ownership and the private security reporting route remain pre-release checks. See security reporting and the changelog.
Metadata
Release files for pydandict 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pydandict-0.1.0.tar.gz | 27.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pydandict-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 43.2 kB
Release files / pydandict-0.1.0.tar.gz
| Download URL | pydandict-0.1.0.tar.gz |
|---|---|
| Size | 27.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e162228ef9c5ca8047f98a8ef97c87c6158140ca852d75e8156f32f871c64fd5
|
|
BLAKE2b-256 checksum How to use checksums |
f9b908901760a2c1ab9477da31cc7f48f8387eed7b69b1049b364f9fe7ff8a9a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 14, 2026.
Transparency logRelease files / pydandict-0.1.0-py3-none-any.whl
| Download URL | pydandict-0.1.0-py3-none-any.whl |
|---|---|
| Size | 15.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3d9cf41abe837783bd8fb5740712ae47c8da7c259e0d07acb069742cb8c19ef3
|
|
BLAKE2b-256 checksum How to use checksums |
d08b398ee63c45655e232f52a7743254a9f9f9313e9092c129ddfcece579540b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 14, 2026.
Transparency log