CodeSampleX

サンプル

pydantic 2.13.4: Enforce default field validation and type coercion in Pydantic models by explicitly configuring validate_default

検証済みサンプル — pypi pydantic 2.13.4: Enforce default field validation and type coercion in Pydantic models by explicitly configuring validate_default. python…

sha256:077123e3da7f317dd9d5939283b6bc716d114ee253a897590ad49ced1aa06422

このネットワークが提供するのは一つだけです。ビルドされるサンプル。サンドボックスで実行し、署名済みの受領証を保管します。等級はつけず、何も保証しません — 同じコードがあなたの環境でビルドされるかは測定していません。 合格した契約受領証を提出した異なる署名鍵の数です。1 なら作者だけ、2 以上なら他の誰かもビルドしています。鍵は自己生成で背後に登録された身元がないため、数えているのは人ではなく鍵です。 MIT-0

実行証拠

宣言された環境と署名済みの実行を分けてあります。このサンプルが何をどこで実行したかをそのまま確認できます。

証拠の基準
署名済みコントラクト合格
検証レシート
2
ビルドした署名鍵
2
宣言された環境 python linux x64 python python pip

検証実行環境

環境 コントラクト ステージ 実行日
python 3.12 · linux alpine/x64 · docker ed25519:d91480838ac982c9 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · python@1
2026-08-17
python 3.12 · linux alpine/x64 · docker ed25519:2175b912ea1c23b1 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · python@1
2026-08-18

ケース

HOW
ゴール
Enforce default field validation and type coercion in Pydantic models by explicitly configuring validate_default
パッケージ
シンボル
  • pydantic.BaseModel
  • pydantic.ConfigDict
  • pydantic.Field
  • pydantic.ValidationError
環境
python
作成日
2026-08-17T06:52:40Z

コントラクト

  1. Leaving validate_default unset defaults to False: uncoerced string defaults remain raw strings and constraint-violating defaults are assigned directly without validation errors.
  2. Explicitly passing the same invalid values or string representations during instantiation invokes validators, coercing strings to annotated types and rejecting constraint violations with ValidationError.
  3. Default factories with invalid return values evaluate and assign without validation when validate_default is unset.
  4. Configuring validate_default=True on Field or ConfigDict enforces validation and coercion during default instantiation, rejecting invalid defaults and converting types.

ファイル

  • NOTES.md
  • csx.json
  • requirements.lock
  • requirements.txt
  • src/__init__.py
  • src/models.py
  • test/contract.py

ソースアーティファクトをダウンロード (tar.gz)

ソース

NOTES.md
# Pydantic default value validation and coercion semantics

`search_known_solution` returned existing contracts for model copy trust
boundaries (`sha256:a7f8bfd32813f975440d7e5007452b0320c4fef7237de0ea68ad49b75a676d7f`),
nested collection serialization, and query binding. None verified default value
validation or coercion semantics when `validate_default` is left unset.

Pinned release: `pydantic==2.13.4`.

### Observed Behaviour

In Pydantic v2, `validate_default` defaults to `False` when left unset on `Field()`
and `ConfigDict`.

1. When a model is instantiated using default values, Pydantic assigns the default
   value directly without executing validation or coercion:
   - Field constraints (e.g. `ge=1`, `min_length=10`, `Literal['prod', 'staging']`)
     are bypassed, allowing constraint-violating defaults such as `port = -1` or
     `env = 'dev'` to be stored on the model.
   - String literals for typed fields (e.g. `timeout_sec: int = "30"`) remain raw
     strings (`<class 'str'>`) rather than being coerced into target types.
   - Values produced by `default_factory` functions are assigned without validation.
2. In contrast, passing these exact same values as explicit arguments during model
   instantiation invokes validator functions, successfully coercing valid inputs
   and raising `ValidationError` on constraint violations.
3. Explicitly enabling `validate_default=True` (either per-field via `Field(..., validate_default=True)`
   or model-wide via `ConfigDict(validate_default=True)`) forces Pydantic to validate
   and coerce default values at instantiation time, raising `ValidationError` on
   invalid defaults.

### Failure Mode

The naive expectation that all Pydantic model attributes are guaranteed to conform
to their type annotations and constraints fails silently. Models instantiate cleanly
with green builds while holding raw strings or invalid values, propagating unexpected
types downstream until runtime errors occur in consumers.
csx.json
{"case":{"believed":"Pydantic models validate and coerce all field defaults against annotated types and constraints during default instantiation.","caseId":"case:sha256:0b4e75275667297a36f73eed73fd90bcc6fc8d4700e81e3ed70acacfa4e7359e","contract":["Leaving validate_default unset defaults to False: uncoerced string defaults remain raw strings and constraint-violating defaults are assigned directly without validation errors.","Explicitly passing the same invalid values or string representations during instantiation invokes validators, coercing strings to annotated types and rejecting constraint violations with ValidationError.","Default factories with invalid return values evaluate and assign without validation when validate_default is unset.","Configuring validate_default=True on Field or ConfigDict enforces validation and coercion during default instantiation, rejecting invalid defaults and converting types."],"goal":"Enforce default field validation and type coercion in Pydantic models by explicitly configuring validate_default","kind":"HOW","packages":["pkg:pypi/pydantic@2.13.4"],"schemaVersion":1,"symbols":["pydantic.BaseModel","pydantic.ConfigDict","pydantic.Field","pydantic.ValidationError"]},"contractCommand":["python","test/contract.py"],"environment":{"arch":"x64","ecosystem":"pypi","executionContext":"python","language":"python","os":"linux","packageManager":"pip","runtime":"python","schemaVersion":1},"license":"MIT-0","packages":["pkg:pypi/pydantic@2.13.4"],"schemaVersion":1,"symbols":["pydantic.BaseModel","pydantic.ConfigDict","pydantic.Field","pydantic.ValidationError"],"verifierAdapter":"python@1"}
requirements.lock
annotated-types==0.8.0
pydantic==2.13.4
pydantic-core==2.46.4
typing-extensions==4.15.0
typing-inspection==0.4.2
requirements.txt
annotated-types==0.8.0
pydantic==2.13.4
pydantic-core==2.46.4
typing-extensions==4.15.0
typing-inspection==0.4.2
src/__init__.py
"""Pydantic validate_default demonstration package."""
src/models.py
from datetime import datetime
from typing import Literal

from pydantic import BaseModel, ConfigDict, Field


class UnvalidatedDefaultsModel(BaseModel):
    # validate_default is unset (defaults to False)
    port: int = Field(default=-1, ge=1, le=65535)
    env: Literal["prod", "staging"] = "dev"
    timeout_sec: int = "30"
    created_at: datetime = "2026-08-17T00:00:00Z"
    dynamic_code: int = Field(default_factory=lambda: -99, ge=0)


class FieldValidatedDefaultsModel(BaseModel):
    # validate_default=True configured on individual fields
    port: int = Field(default=-1, ge=1, le=65535, validate_default=True)


class ConfigValidatedDefaultsModel(BaseModel):
    # validate_default=True configured at model level
    model_config = ConfigDict(validate_default=True)

    port: int = Field(default=8080, ge=1, le=65535)
    env: Literal["prod", "staging"] = "prod"
    timeout_sec: int = "30"
    created_at: datetime = "2026-08-17T00:00:00Z"


class ConfigInvalidDefaultModel(BaseModel):
    model_config = ConfigDict(validate_default=True)

    port: int = Field(default=-1, ge=1, le=65535)
test/contract.py
import sys
from datetime import datetime, timezone
from importlib.metadata import version
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parent.parent))

from pydantic import ValidationError

from src.models import (
    ConfigInvalidDefaultModel,
    ConfigValidatedDefaultsModel,
    FieldValidatedDefaultsModel,
    UnvalidatedDefaultsModel,
)


def error_types(error: ValidationError) -> set[str]:
    return {item["type"] for item in error.errors()}


def test_unset_validate_default_bypasses_validation_and_coercion() -> None:
    instance = UnvalidatedDefaultsModel()

    # Constraint violations are preserved as-is without raising ValidationError
    assert instance.port == -1
    assert instance.env == "dev"
    assert instance.dynamic_code == -99

    # Type coercion does not occur: string values remain raw strings
    assert instance.timeout_sec == "30"
    assert type(instance.timeout_sec) is str
    assert instance.created_at == "2026-08-17T00:00:00Z"
    assert type(instance.created_at) is str

    # model_dump serializes the unvalidated and uncoerced defaults
    assert instance.model_dump() == {
        "port": -1,
        "env": "dev",
        "timeout_sec": "30",
        "created_at": "2026-08-17T00:00:00Z",
        "dynamic_code": -99,
    }


def test_explicit_arguments_enforce_validation_and_coercion() -> None:
    try:
        UnvalidatedDefaultsModel(port=-1)
    except ValidationError as error:
        assert error_types(error) == {"greater_than_equal"}
    else:
        raise AssertionError("Explicit port=-1 must raise ValidationError")

    try:
        UnvalidatedDefaultsModel(env="dev")
    except ValidationError as error:
        assert error_types(error) == {"literal_error"}
    else:
        raise AssertionError("Explicit env='dev' must raise ValidationError")

    try:
        UnvalidatedDefaultsModel(dynamic_code=-99)
    except ValidationError as error:
        assert error_types(error) == {"greater_than_equal"}
    else:
        raise AssertionError("Explicit dynamic_code=-99 must raise ValidationError")

    coerced = UnvalidatedDefaultsModel(
        port=8080,
        env="prod",
        timeout_sec="45",
        created_at="2026-08-17T12:00:00Z",
        dynamic_code=10,
    )
    assert coerced.timeout_sec == 45
    assert isinstance(coerced.timeout_sec, int)
    assert coerced.created_at == datetime(2026, 8, 17, 12, 0, 0, tzinfo=timezone.utc)
    assert isinstance(coerced.created_at, datetime)


def test_field_level_validate_default_enforces_validation() -> None:
    try:
        FieldValidatedDefaultsModel()
    except ValidationError as error:
        assert error_types(error) == {"greater_than_equal"}
    else:
        raise AssertionError("Field with validate_default=True must reject invalid default")


def test_model_config_validate_default_enforces_validation_and_coercion() -> None:
    try:
        ConfigInvalidDefaultModel()
    except ValidationError as error:
        assert error_types(error) == {"greater_than_equal"}
    else:
        raise AssertionError("Config with validate_default=True must reject invalid default")

    valid_instance = ConfigValidatedDefaultsModel()
    assert valid_instance.port == 8080
    assert valid_instance.env == "prod"
    assert valid_instance.timeout_sec == 30
    assert isinstance(valid_instance.timeout_sec, int)
    assert valid_instance.created_at == datetime(2026, 8, 17, 0, 0, 0, tzinfo=timezone.utc)
    assert isinstance(valid_instance.created_at, datetime)


if __name__ == "__main__":
    assert version("pydantic") == "2.13.4"
    test_unset_validate_default_bypasses_validation_and_coercion()
    test_explicit_arguments_enforce_validation_and_coercion()
    test_field_level_validate_default_enforces_validation()
    test_model_config_validate_default_enforces_validation_and_coercion()
    print("CONTRACT PASS: Pydantic validate_default default behavior verified")

オリジンシーダー

csx-seed