Skip to content

Upgrading from an older release

How the models 0.87.0 generates differ in behaviour from the models each recorded older release generates, with default options, for every test fixture and payload validation case of the repository. Each older release ran in an environment with the package versions of its release day; the models were compared by behaviour as on the release pages. Each change is attributed to the recorded releases that made it.

From same no-behaviour crash-fix behaviour-change now-fails both-fail unsupported
0.86.0 15375 57 414 17 0 679 82
0.80.0 14405 80 740 616 68 633 82
0.70.0 13178 151 1089 1399 236 489 82
0.45.0 2249 5989 1214 2293 127 294 4458
0.25.9 256 2298 1180 2704 119 299 9768
  • same: identical output
  • no-behaviour: the output differs, the models behave the same
  • crash-fix: the older release failed to generate, import or validate; the newer one works
  • behaviour-change: the models behave differently (types, constraints, names, defaults, validation results)
  • now-fails: the older release worked; the newer one fails on the input
  • both-fail: both releases fail on the input
  • unsupported: one of the releases does not have the output model type or an option the generation uses

From 0.86.0 to 0.87.0

Output model type same no-behaviour crash-fix behaviour-change both-fail unsupported
dataclasses.dataclass 3433 10 80 1 139 20
msgspec.Struct 3411 6 103 0 143 20
pydantic_v2.BaseModel 3399 17 91 13 142 21
pydantic_v2.dataclass 3411 17 90 2 142 21
typing.TypedDict 1721 7 50 1 113 0

Changed in (each recorded release counts the generations it changed since the recorded release before it, classified on that pair of releases alone, so a change that was made and later undone counts under both releases although the counts above compare only the two ends):

Release crash-fix behaviour-change
0.87.0 414 17

Changed aspects: type 38, constraints 8, payload-verdict 7, config 5, kind 2, parsed-value 2, default 1.

Examples, behaviour-change:

  • tests/data/jsonschema/collapse_root_models_property_names_reference.json (pydantic_v2.BaseModel), changed in 0.87.0
    • [type] KeyMap: dict[Key, int] -> dict[str, int]
  • tests/data/jsonschema/compound_property_names (pydantic_v2.BaseModel), changed in 0.87.0
    • [type] allof_branch_title:Root: dict[Root1, int] -> dict[str, int]
    • [type] allof_lookbehind:Root: dict[Root2, int] -> dict[str, int]
  • tests/data/jsonschema/external_anchor (dataclasses.dataclass), changed in 0.87.0
    • [type] root:ExternalAnchor:anchored: Union[NestedChild, None] -> Union[AnchoredChild, None]
    • [type] root:ExternalAnchor:anchored_again: Union[NestedChild, None] -> Union[AnchoredChild, None]

Examples, crash-fix:

  • tests/data/asyncapi/avro-named-types.yaml (dataclasses.dataclass), changed in 0.87.0
    • NotADirectoryError: [Errno 20] Not a directory: 'tests/data/asyncapi/avro-named-types.yaml/__asyncapi_schemas__/channels
  • tests/data/asyncapi/edge-cases.yaml (pydantic_v2.BaseModel), changed in 0.87.0
    • PydanticUserError: Model 'User' needs field 'kind' to be of type `Literal`
  • tests/data/jsonschema/additional_pattern_intersections (msgspec.Struct), changed in 0.87.0
    • [type] anchored_disjoint:Root: Union[dict[str, Root1], dict[str, Root2]] -> dict[str, Union[Root1, Root2]]
    • [type] minimum:Root: Union[dict[str, Root3], dict[str, Root4]] -> dict[str, Union[Root3, Root4]]

From 0.80.0 to 0.87.0

Output model type same no-behaviour crash-fix behaviour-change now-fails both-fail unsupported
dataclasses.dataclass 3348 8 128 37 14 128 20
msgspec.Struct 3177 10 266 63 12 135 20
pydantic_v2.BaseModel 3302 19 126 68 14 133 21
pydantic_v2.dataclass 2901 35 157 420 15 134 21
typing.TypedDict 1677 8 63 28 13 103 0

Changed in (each recorded release counts the generations it changed since the recorded release before it, classified on that pair of releases alone, so a change that was made and later undone counts under both releases although the counts above compare only the two ends):

Release crash-fix behaviour-change now-fails
0.86.0 332 599 68
0.87.0 414 17 0

Changed aspects: type 574, constraints 283, payload-verdict 157, kind 119, default 39, import-path-removed 25, config 11, field-added 7, field-removed 7, bases 6, name-removed 6, module-removed 5, constructor-order 4, enum-member-removed 4, numbered-name-removed 4, required 4, parsed-value 3, alias 1.

Examples, behaviour-change:

  • tests/data/avro/constructs.avsc (pydantic_v2.dataclass), changed in 0.86.0
    • [type] MD5: Annotated[bytes, None, Len(max_length=16,min_length=16)] -> Annotated[bytes, MinLen(min_length=16),MaxLen(max_length=16)]
    • [constraints] User:hash: Annotated[bytes, None, Len(max_length=16,min_length=16)] -> Annotated[bytes, MinLen(min_length=16),MaxLen(max_length=16)]
  • tests/data/avro/container_bytes_defaults.avsc (pydantic_v2.dataclass), changed in 0.86.0
    • [constraints] ContainerDefaults:fixed_array: Union[None, list[Annotated[bytes, None, Len(max_length=1,min_length=1)]]] -> Union[None, list[Annotated[bytes, M...
    • [constraints] ContainerDefaults:fixed_map: Union[None, dict[str, list[Annotated[bytes, None, Len(max_length=1,min_length=1)]]]] -> Union[None, dict[str, list...
  • tests/data/avro/decimal_defaults.avsc (pydantic_v2.dataclass), changed in 0.86.0
    • [constraints] DecimalDefaults:plain_fixed: Union[Annotated[bytes, None, Len(max_length=2,min_length=2)], None] -> Union[Annotated[bytes, MinLen(min_length=2)...
    • [type] Raw: Annotated[bytes, None, Len(max_length=2,min_length=2)] -> Annotated[bytes, MinLen(min_length=2),MaxLen(max_length=2)]

Examples, crash-fix:

  • tests/data/asyncapi/avro-named-types.yaml (dataclasses.dataclass), changed in 0.87.0
    • NotADirectoryError: [Errno 20] Not a directory: 'tests/data/asyncapi/avro-named-types.yaml/__asyncapi_schemas__/channels
  • tests/data/asyncapi/edge-cases.yaml (pydantic_v2.BaseModel), changed in 0.87.0
    • PydanticUserError: Model 'User' needs field 'kind' to be of type `Literal`
  • tests/data/avro/spec_matrix.avsc (msgspec.Struct), changed in 0.86.0
    • [constraints] SpecMatrix:sameKindNamedUnion: Union[Annotated[bytes, Meta(max_length=4,min_length=4)], Annotated[bytes, Meta(max_length=8,min_length=8)], EA, ...

Examples, now-fails:

  • tests/data/jsonschema/allof_inheritance_errors/cycle_multi_base.json (dataclasses.dataclass), changed in 0.86.0
    • Generated model inheritance cycle: A (cycle_multi_base.json#/$defs/A) -> B (cycle_multi_base.json#/$defs/B) -> A (cycle_multi_base.json#/$defs/A)
  • tests/data/jsonschema/allof_inheritance_errors (dataclasses.dataclass), changed in 0.86.0
    • Generated model inheritance cycle: A (cycle_multi_base.json#/$defs/A) -> B (cycle_multi_base.json#/$defs/B) -> A (cycle_multi_base.json#/$defs/A)
  • tests/data/jsonschema/custom_type_path_overridden.json (dataclasses.dataclass), changed in 0.86.0
    • enum.StrEnum is unavailable for target Python 3.10

From 0.70.0 to 0.87.0

Output model type same no-behaviour crash-fix behaviour-change now-fails both-fail unsupported
dataclasses.dataclass 3092 32 194 198 53 94 20
msgspec.Struct 2864 50 345 252 51 101 20
pydantic_v2.BaseModel 3059 23 185 243 52 100 21
pydantic_v2.dataclass 2650 33 274 551 53 101 21
typing.TypedDict 1513 13 91 155 27 93 0

Changed in (each recorded release counts the generations it changed since the recorded release before it, classified on that pair of releases alone, so a change that was made and later undone counts under both releases although the counts above compare only the two ends):

Release crash-fix behaviour-change now-fails
0.80.0 406 919 221
0.86.0 332 599 68
0.87.0 414 17 0

Changed aspects: type 1024, payload-verdict 379, kind 376, constraints 330, default 319, required 257, parsed-value 63, constructor-order 51, name-removed 35, import-path-removed 25, enum-member-removed 24, field-added 24, numbered-name-removed 16, config 14, bases 8, field-removed 7, module-removed 5, alias 1.

Examples, behaviour-change:

  • tests/data/asyncapi/multi-format-schemas.yaml (dataclasses.dataclass), changed in 0.80.0
    • [required] UserSignupUserSignupPayload:age: True -> False
    • [default] UserSignupUserSignupPayload:age: None -> 'None'
  • tests/data/asyncapi/protobuf-schema-format.yaml (pydantic_v2.dataclass), changed in 0.80.0
    • [default] ProtoEvent:children: 'FieldInfo(annotation=NoneType, required=False, default=[], validate_default=True)' -> 'FieldInfo(annotation=NoneType, require...
  • tests/data/avro/constructs.avsc (dataclasses.dataclass), changed in 0.80.0
    • [required] Address:zip: True -> False
    • [default] Address:zip: None -> 'None'

Examples, crash-fix:

  • tests/data/asyncapi/avro-named-types.yaml (dataclasses.dataclass), changed in 0.87.0
    • NotADirectoryError: [Errno 20] Not a directory: 'tests/data/asyncapi/avro-named-types.yaml/__asyncapi_schemas__/channels
  • tests/data/asyncapi/edge-cases.yaml (pydantic_v2.BaseModel), changed in 0.87.0
    • PydanticUserError: Model 'User' needs field 'kind' to be of type `Literal`
  • tests/data/avro/container_bytes_defaults.avsc (msgspec.Struct), changed in 0.80.0
    • [type] ContainerDefaults:array: list[bytes] -> Union[list[bytes], msgspec.UnsetType]
    • [required] ContainerDefaults:array: True -> False

Examples, now-fails:

  • tests/data/avro/invalid_decimal_default_fixed_long.avsc (dataclasses.dataclass), changed in 0.80.0
    • Avro fixed decimal default must contain exactly 2 bytes: 3
  • tests/data/avro/invalid_decimal_default_fixed_reference.avsc (dataclasses.dataclass), changed in 0.80.0
    • Avro fixed decimal default must contain exactly 2 bytes: 1
  • tests/data/avro/invalid_decimal_default_fixed_short.avsc (dataclasses.dataclass), changed in 0.80.0
    • Avro fixed decimal default must contain exactly 2 bytes: 1

From 0.45.0 to 0.87.0

Output model type same no-behaviour crash-fix behaviour-change now-fails both-fail unsupported
dataclasses.dataclass 647 1949 259 529 29 72 198
msgspec.Struct 603 1672 484 617 30 79 198
pydantic_v2.BaseModel 595 1671 318 787 38 73 201
pydantic_v2.dataclass 0 0 0 0 0 0 3683
typing.TypedDict 404 697 153 360 30 70 178

Changed in (each recorded release counts the generations it changed since the recorded release before it, classified on that pair of releases alone, so a change that was made and later undone counts under both releases although the counts above compare only the two ends):

Release crash-fix behaviour-change now-fails
0.70.0 747 1841 226
0.80.0 406 919 221
0.86.0 332 599 68
0.87.0 414 17 0

Changed aspects: type 1488, default 417, kind 395, payload-verdict 343, constraints 313, config 239, required 197, parsed-value 169, name-removed 165, field-added 56, enum-member-removed 53, field-removed 47, constructor-order 37, enum-member-added 35, import-path-removed 27, numbered-name-removed 25, bases 20, alias 7, module-removed 4.

Examples, behaviour-change:

  • tests/data/graphql/annotated.graphql (msgspec.Struct), changed in 0.70.0
    • [field-removed] A:field: removed
    • [field-added] A:field_: required
  • tests/data/graphql/different-types-of-fields.graphql (msgspec.Struct), changed in 0.70.0
    • [field-removed] A:field: removed
    • [field-added] A:field_: required
  • tests/data/graphql/empty_list_default.graphql (dataclasses.dataclass), changed in 0.70.0
    • [required] PodSpec:container_list: True -> False
    • [default] PodSpec:container_list: None -> 'factory:list'

Examples, crash-fix:

  • tests/data/graphql/github-api-issue-states.graphql (msgspec.Struct), changed in 0.70.0
    • [kind] IssueFilters: error -> msgspec.Struct
  • tests/data/graphql/github-api.graphql (msgspec.Struct), changed in 0.80.0, 0.86.0
    • TypeError: Required field 'id' cannot follow optional fields. Either reorder the struct fields, or set `kw_only=True` in
  • tests/data/graphql/interface_mro.graphql (dataclasses.dataclass), changed in 0.70.0
    • TypeError: Cannot create a consistent method resolution order (MRO) for bases object, Node, Notification

Examples, now-fails:

  • tests/data/jsonschema/builtin_field_names_python_315_builtins.json (pydantic_v2.BaseModel), changed in 0.70.0
    • TypeError: unsupported operand type(s) for |: 'NoneType' and 'NoneType'
  • tests/data/jsonschema/builtin_field_names_target_python_version.json (pydantic_v2.BaseModel), changed in 0.70.0
    • TypeError: unsupported operand type(s) for |: 'NoneType' and 'NoneType'
  • tests/data/jsonschema/constraints_on_typing_lookalikes.json (dataclasses.dataclass), changed in 0.70.0
    • ModuleNotFoundError: No module named 'mypkg'

From 0.25.9 to 0.87.0

Output model type same no-behaviour crash-fix behaviour-change now-fails both-fail unsupported
dataclasses.dataclass 87 714 258 554 27 74 1969
msgspec.Struct 78 84 400 1044 28 80 1969
pydantic_v2.BaseModel 90 673 295 547 35 74 1969
pydantic_v2.dataclass 0 0 0 0 0 0 3683
typing.TypedDict 1 827 227 559 29 71 178

Changed in (each recorded release counts the generations it changed since the recorded release before it, classified on that pair of releases alone, so a change that was made and later undone counts under both releases although the counts above compare only the two ends):

Release crash-fix behaviour-change now-fails
0.45.0 582 2012 197
0.70.0 747 1841 226
0.80.0 406 919 221
0.86.0 332 599 68
0.87.0 414 17 0

Changed aspects: type 2231, default 1280, required 299, kind 234, config 205, bases 138, name-removed 128, constructor-order 126, field-added 119, field-removed 108, import-path-removed 107, enum-base 81, constraints 72, enum-member-removed 36, enum-member-added 29, numbered-name-removed 25, alias 6, enum-value 6, module-removed 4.

Examples, behaviour-change:

  • tests/data/graphql/additional-imports.graphql (msgspec.Struct), changed in 0.45.0
    • [type] A:typename__: Union[Literal['A'], None] -> Union[Literal['A'], msgspec.UnsetType]
  • tests/data/graphql/alias_generator_empty_union.graphql (msgspec.Struct), changed in 0.45.0
    • [type] A:typename__: Union[Literal['A'], None] -> Union[Literal['A'], msgspec.UnsetType]
    • [type] B:typename__: Union[Literal['B'], None] -> Union[Literal['B'], msgspec.UnsetType]
  • tests/data/graphql/annotated.graphql (pydantic_v2.BaseModel), changed in 0.45.0
    • [default] A:optionalListField: 'factory:list' -> 'None'
    • [default] A:optionalListOptionalField: 'factory:list' -> 'None'

Examples, crash-fix:

  • tests/data/graphql/annotated.graphql (dataclasses.dataclass), changed in 0.45.0
    • ValueError: cannot specify both default and default_factory
  • tests/data/graphql/collection-options.graphql (dataclasses.dataclass), changed in 0.45.0
    • ValueError: cannot specify both default and default_factory
  • tests/data/graphql/different-types-of-fields.graphql (dataclasses.dataclass), changed in 0.45.0
    • ValueError: cannot specify both default and default_factory

Examples, now-fails:

  • tests/data/graphql/github-api.graphql (typing.TypedDict), changed in 0.45.0
    • signature timed out after 300s
  • tests/data/jsonschema/builtin_field_names_python_315_builtins.json (pydantic_v2.BaseModel), changed in 0.70.0
    • TypeError: unsupported operand type(s) for |: 'NoneType' and 'NoneType'
  • tests/data/jsonschema/builtin_field_names_target_python_version.json (pydantic_v2.BaseModel), changed in 0.70.0
    • TypeError: unsupported operand type(s) for |: 'NoneType' and 'NoneType'