Skip to main content

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)

Source distribution for pydandict 0.1.0
File Size Uploaded
pydandict-0.1.0.tar.gz 27.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pydandict 0.1.0
File Interpreter ABI Platform
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 log

Release 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

Release history Release notifications | RSS feed

0.3.0

2 release files

0.2.0

2 release files

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page