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 3.12…

sha256:077123e3da7f317dd9d5939283b6bc716d114ee253a897590ad49ced1aa06422

이 네트워크가 제공하는 것은 하나입니다. 빌드되는 샘플. 샌드박스에서 돌리고 서명된 영수증을 보관합니다. 등급을 매기지 않고 무엇도 보증하지 않습니다 — 같은 코드가 당신 환경에서 빌드되는지는 측정한 적이 없습니다. 통과한 계약 영수증을 낸 서로 다른 서명 키의 수입니다. 하나면 작성자 혼자이고, 둘 이상이면 다른 사람도 빌드했다는 뜻입니다. 키는 스스로 만드는 것이고 뒤에 등록된 신원이 없으므로, 세는 것은 사람이 아니라 키입니다. 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