Skip to content

upstream(pydantic): protected_namespaces replaces the default instead of extending it #139

Open

Description

@cdwilson

Tracks upstream friction in Pydantic. The explanation lives in the docs; this issue is the unit of work.

Explanation: protected_namespaces replaces the default instead of extending it — the limitation, why it matters to an ODM, the workaround tinydantic carries, and the change that would remove it. That section is written to be read standalone by an upstream maintainer, so it doubles as the ready-to-send proposal if we ever file this.

Reproduction

Upstream only — no tinydantic import.

import warnings

from pydantic import BaseModel, ConfigDict

with warnings.catch_warnings(record=True) as caught:
    warnings.simplefilter("always")

    class Plain(BaseModel):
        model_dump_toml: str

    class Own(BaseModel):
        model_config = ConfigDict(protected_namespaces=("app_",))
        model_dump_toml: str

for warning in caught:
    print("warning:", warning.message)
print("total warnings:", len(caught))

Run with python repro.py.

Actual output:

warning: Field 'model_dump_toml' in 'Plain' conflicts with protected namespace 'model_dump'.

You may be able to solve this by setting the 'protected_namespaces' configuration to ('model_validate',).

total warnings: 1

One warning, for Plain. Own reserved its own prefix and silently gave up the inherited one — nothing says the model_dump protection is gone. Restating the defaults alongside app_ is the only fix, and the values to restate live in pydantic._internal._config.config_defaults, with no public constant to read them from.

Expected: two warnings — protected_namespaces accumulates across the MRO, since a subclass reserving its own prefix almost never means "and drop the ones my base reserved". Failing that, a public DEFAULT_PROTECTED_NAMESPACES constant to extend rather than copy.

Environment: pydantic 2.13.4, Python 3.10.20, macOS. Run 2026-08-13.

What tinydantic carries today

Restating Pydantic's defaults explicitly: protected_namespaces = ("tinydantic_", "model_validate", "model_dump") in src/tinydantic/_model.py, so a tinydantic model is never less protected than a plain BaseModel.

Private API (test-only): pydantic._internal._config.config_defaults["protected_namespaces"] in tests/model/test_model_config.py, which asserts our tuple still covers Pydantic's default — so a Pydantic release reserving a new prefix fails the suite instead of silently losing protection.

Upstream status

Not filed. Related upstream context: pydantic#10315.

What would close this

Exporting DEFAULT_PROTECTED_NAMESPACES as a public constant, or making protected_namespaces accumulate across the MRO — or a maintainer decision to carry the workaround indefinitely.

Assisted-by: Claude:claude-opus-5

Activity

  1. added
    enhancementNew feature or request
    upstreamTracks a defect or request in an upstream dependency
    ai-assistedCreated or investigated with help from an AI agent
    on Aug 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    ai-assistedCreated or investigated with help from an AI agentenhancementNew feature or requestupstreamTracks a defect or request in an upstream dependency

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions