Breaking Changes
Code Generation Changes
- msgspec: Required nullable fields no longer receive a spurious default - Previously, required fields with nullable types (e.g.,
str | None) in msgspec Structs were incorrectly rendered with= None. They are now correctly rendered without a default assignment (e.g.,label: str | Noneinstead oflabel: str | None = None), which means callers must provide the value explicitly (#3292) - msgspec: Array length constraints now render as Meta annotations -
minItems/maxItemsschema constraints on array fields were previously silently ignored for msgspec output. They now render asAnnotated[list[T], Meta(min_length=..., max_length=...)]when--use-annotatedis enabled (e.g.,list[Pet]becomesAnnotated[list[Pet], Meta(max_length=10, min_length=1)]) (#3292) - msgspec: Inherited Structs with field ordering conflicts now use
kw_only=True- When a child Struct inherits optional fields from a parent and adds required fields, the child now renders withkw_only=Trueas a base class kwarg (e.g.,class Child(Base, kw_only=True):), changing the calling convention to keyword-only arguments (#3292) - Non-finite float values now use
float()calls instead ofmathimports - Generated code previously renderedinf,-inf, andnan(withfrom math import inf, nan). Now rendersfloat('inf'),float('-inf'), andfloat('nan')without themathimport. Semantically equivalent but changes generated output. (#3289) - Decimal constraint arguments now use
Decimal()objects -condecimal()constraints previously used bare int/float values (e.g.,condecimal(ge=0, le=1000)). Now usesDecimalobjects (e.g.,condecimal(ge=Decimal('0'), le=Decimal('1000'))) with an addedfrom decimal import Decimalimport in generated code. (#3289) - Integer fields with fractional constraints are normalized to integer-safe bounds - Fractional constraint values on integer types are now converted:
gt: 0.5becomesge: 1,lt: 2.5becomesle: 2, andmultiple_of: 1is dropped entirely. Previously these fractional values were passed through as-is toconint()orField(). (#3289) - msgspec array length constraints are now rendered -
min_itemsandmax_itemsschema constraints on array fields are now emitted asMeta(min_length=..., max_length=...)annotations in msgspec output. Previously these constraints were silently ignored. (#3289) - msgspec required nullable fields no longer get default
= None- Required nullable fields in msgspec Structs previously received a= Nonedefault assignment. Now they are rendered without a default, requiring callers to provide the value explicitly. (#3289) - TypedDict
extra_itemsnow uses direct identifiers instead of string forward references - WhenadditionalPropertiesreferences another type, the generatedextra_items=keyword argument changed from a quoted string to a bare identifier (e.g.,extra_items='BaseExtra'→extra_items=BaseExtra). The generated code remains valid because files includefrom __future__ import annotations, but the textual output differs (#3301) - Functional-syntax TypedDict description placement changed - Description docstrings for functional-syntax TypedDicts (using
TypedDict('Name', {...})) are now rendered before the definition instead of after it. Previously the docstring appeared as a string literal following the assignment; it now appears as a comment block preceding it (#3301) - UUID2 format now generates
uuid.UUIDinstead ofpydantic.UUID2- Schemas using"format": "uuid2"now generateUUIDimported from theuuidstandard library instead of the non-existentUUID2frompydantic. This is a bug fix sincepydantic.UUID2was never a valid Pydantic v2 type (the old generated code would raiseImportError), but the generated import and type annotation will differ for any schema using this format (#3297)
Custom Template Update Required
- msgspec.jinja2 default assignment condition simplified - The Jinja2 template condition for rendering default values was changed from
not field.field and (not field.required or field.use_default_with_required or field.data_type.is_optional or field.nullable)tonot field.field and (not field.required or field.use_default_with_required). Users with custom msgspec templates that replicate the old logic should update accordingly (#3292) - msgspec.jinja2 template default value condition changed - The condition for rendering default value assignments changed from
not field.required or field.use_default_with_required or field.data_type.is_optional or field.nullabletonot field.required or field.use_default_with_required. Custom templates derived from the built-in msgspec template may need to be updated. (#3289) TypedDictFunction.jinja2template restructured - The built-in functional TypedDict template moved thedescriptionblock from after the class definition to before it and added support for field-level docstrings. Users with custom templates that were based on or extend this template may need to update accordingly (#3301)
Error Handling Changes
- XML Schema schemaLocation references outside the input base path are now blocked - Any
xs:include,xs:import,xs:redefine, orxs:overridewith aschemaLocationthat resolves outside the input base directory now raises an unconditional error. Previously, these references were silently resolved regardless of location. Users with XML schemas that include files from parent or sibling directories must move the included schemas under the input directory before generating models. (#3308)
Default Behavior Changes
- Local JSON Schema
$refreferences outside the input base path now emit deprecation warnings - Relative path refs (e.g.,$ref: "../other/schema.json") andfile://URL refs that resolve outside the input base directory now emit aFutureWarningunder the default behavior (no--allow-remote-refsflag). Previously these were silently resolved. Pass--allow-remote-refsto suppress the warning, or move referenced schemas under the input directory. (#3308) --no-allow-remote-refsnow blocksfile://URLs and local refs outside the base path - Previously--no-allow-remote-refsonly blocked HTTP(S)$reffetching. It now also blocksfile://URL references and relative local$refreferences that resolve outside the input base path. Users who rely onfile://refs or out-of-tree local refs with--no-allow-remote-refsmust switch to--allow-remote-refsor restructure their schemas. (#3308)
What's Changed
- Add security policy by @koxudaxi in #3283
- Update CHANGELOG for 0.61.0 by @dcg-generated-docs[bot] in #3282
- Optimize DataType prototype copying and import collection by @koxudaxi in #3291
- Cache dynamically created context DataType classes by @koxudaxi in #3294
- Reuse ModelResolver for field name collision resolution by @koxudaxi in #3295
- Reduce redundant Field() data computation in pydantic fields by @koxudaxi in #3293
- Fix raw input parsing by @koxudaxi in #3290
- Fix msgspec field ordering by @koxudaxi in #3292
- Fix pydantic constraint rendering by @koxudaxi in #3289
- Break reference cycles in parsed graph after generation by @koxudaxi in #3298
- Compute field statement check once when collecting imports by @koxudaxi in #3296
- Cache ref schema facts in get_ref_data_type by @koxudaxi in #3301
- Sync generated docs by @dcg-generated-docs[bot] in #3300
- Fall back uuid2 format to uuid.UUID by @koxudaxi in #3305
- Iterate the smaller side in transform_kwargs by @koxudaxi in #3297
- Sync generated docs by @dcg-generated-docs[bot] in #3307
- Fix msgspec constraint and default rendering by @koxudaxi in #3302
- Avoid building unused Field strings and empty extras dicts by @koxudaxi in #3304
- Fix TypedDict functional descriptions and extra_items forward references by @koxudaxi in #3306
- Fix playground options layout by @koxudaxi in #3308
- Improve private network option help by @koxudaxi in #3309
- Fix enum member default resolution by @koxudaxi in #3303
- Use Claude Opus 4.8 by @koxudaxi in #3312
- Sync generated docs by @dcg-generated-docs[bot] in #3311
Full Changelog: 0.61.0...0.62.0