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.0NotADirectoryError: [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.0PydanticUserError: 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.0NotADirectoryError: [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.0PydanticUserError: 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.0Generated 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.0Generated 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.0enum.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.0NotADirectoryError: [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.0PydanticUserError: 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.0Avro fixed decimal default must contain exactly 2 bytes: 3
tests/data/avro/invalid_decimal_default_fixed_reference.avsc(dataclasses.dataclass), changed in 0.80.0Avro fixed decimal default must contain exactly 2 bytes: 1
tests/data/avro/invalid_decimal_default_fixed_short.avsc(dataclasses.dataclass), changed in 0.80.0Avro 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.0TypeError: 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.0TypeError: 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.0TypeError: 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.0TypeError: unsupported operand type(s) for |: 'NoneType' and 'NoneType'
tests/data/jsonschema/constraints_on_typing_lookalikes.json(dataclasses.dataclass), changed in 0.70.0ModuleNotFoundError: 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.0ValueError: cannot specify both default and default_factory
tests/data/graphql/collection-options.graphql(dataclasses.dataclass), changed in 0.45.0ValueError: cannot specify both default and default_factory
tests/data/graphql/different-types-of-fields.graphql(dataclasses.dataclass), changed in 0.45.0ValueError: cannot specify both default and default_factory
Examples, now-fails:
tests/data/graphql/github-api.graphql(typing.TypedDict), changed in 0.45.0signature timed out after 300s
tests/data/jsonschema/builtin_field_names_python_315_builtins.json(pydantic_v2.BaseModel), changed in 0.70.0TypeError: 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.0TypeError: unsupported operand type(s) for |: 'NoneType' and 'NoneType'