Promote spec-defined fields to typed model fields (0.4.0)#31
Merged
Conversation
- Schema: typed ref ($ref), format, enum, default, const, deprecated, nullable, readOnly/writeOnly, example/examples, additionalProperties (Schema | bool), discriminator, and numeric/string/array/object constraints. has_default/has_const distinguish 'default: null' from absent. Boolean JSON schemas (items: true) no longer crash parsing. - New Discriminator model (propertyName + mapping) wired into Schema. - Operation: typed parameters (list[Parameter]), responses (dict[str, Response]), request_body, security (None = inherit global), callbacks (dict[str, Callback]), deprecated, servers, external_docs. - MediaType.schema_ is now a typed Schema instead of a raw dict. - Parameter/Header: typed ref, deprecated, allowEmptyValue. RequestBody/Response: typed ref. Encoding.headers: dict[str, Header]. Link: snake_case fields with camelCase aliases, typed server. - PathItem: typed path-level parameters, summary, description, $ref; unknown keys now preserved in model_extra. - ReferenceResolver reads the typed ref field before falling back to model_extra. - Backwards compatibility: raw source values for all promoted keys are mirrored into model_extra via model_utils.mirror_extras (deprecated, to be removed in 0.5.0). - Import cycle operation -> callback -> path_item -> operation broken with deferred bottom-of-module imports + model_rebuild. - New test suites encode the typed-field and mirroring contracts (tests/spec/test_typed_fields.py, tests/spec/test_discriminator.py). https://claude.ai/code/session_012uMV8n26pbFxhKLu83rTjE
- Schema.types: always-a-list view of the type keyword (3.0 string and
3.1 type arrays).
- Schema.primary_type: first non-'null' type.
- Schema.is_nullable: unifies 3.0 'nullable', 3.1 type arrays containing
'null', and anyOf/oneOf with a {'type': 'null'} member. Consumers no
longer need to normalize 3.1 specs to 3.0 before parsing.
- OpenAPISpec.operations_by_tag() and tags_to_operations() for tag-based
operation lookup.
- Paths is iterable as (path, PathItem) pairs and supports len().
- Reference resolution is now cached: one shared resolver per spec plus
a per-resolver result cache; circular detection still consults the
in-flight resolution stack first.
- Broken reference errors now include a did-you-mean suggestion and the
available keys at the failure point.
https://claude.ai/code/session_012uMV8n26pbFxhKLu83rTjE
- New model_utils.SpecModel base class: shared extra=allow + populate_by_name config, declarative NESTED_FIELDS (object/collection/ list kinds) driving a single generic from_dict, and automatic MIRRORED_EXTRA_KEYS handling. - Migrated Example, MediaType, RequestBody, Response, Parameter, Header, Encoding, and Link to the base, deleting their hand-written from_dict methods. Schema subclasses SpecModel but keeps its custom recursive from_dict. Operation/PathItem keep their custom signatures. - Malformed nested values of the wrong shape now degrade gracefully (skipped, field keeps its default) instead of crashing the parse. - Type-check is now clean: ty exits 0 (8 warnings) vs failing with 124 diagnostics on main. https://claude.ai/code/session_012uMV8n26pbFxhKLu83rTjE
CHANGELOG documents the typed-field promotion with a migration table, the deprecated model_extra mirroring (removal planned for 0.5.0), native OpenAPI 3.1 nullability helpers, the new query API, and robustness improvements. Docs updated for the new Schema/Discriminator fields, Paths iteration, tag queries, and resolver caching/error behavior. https://claude.ai/code/session_012uMV8n26pbFxhKLu83rTjE
- New model_utils.lenient_validator: malformed optional scalar values in real-world specs (e.g. YAML float for 'pattern', Swagger-2-style 'required: true' on a property schema) fall back to the field default instead of rejecting the whole document. Applied to Schema, Parameter, Header, Response, RequestBody, Operation, and PathItem. Raw values stay available via model_extra (where mirrored) and OpenAPISpec.raw. This fixes a strictness regression versus 0.3.0, where these keywords lived unvalidated in model_extra. - Schema.prefix_items: typed prefixItems (JSON Schema tuple validation, OpenAPI 3.1) with recursive parsing, extras mirroring, and __str__ support. Covers the feature proposed in PR #30. - SpecModel collection parsing now skips non-dict items (matching the list kind) instead of crashing on malformed entries. - Simplified PathItem.from_dict: $ref/summary/description resolve via the plain splat and Pydantic aliases. - New tests: tests/spec/test_lenient_parsing.py plus prefixItems cases. https://claude.ai/code/session_012uMV8n26pbFxhKLu83rTjE
Operation-level inline content is now fully parsed (0.3.0 left it as raw
dicts), which exposed malformed data that previously went unvalidated:
- parse_collection: non-dict collections yield {}, non-dict items are
skipped, and non-string keys (YAML parses unquoted 'no:' as boolean
False) are coerced to str. SpecModel's collection kind now delegates
to parse_collection instead of duplicating it.
- Operation.responses: status-code keys coerced to str.
- Example: lenient summary/description/externalValue (YAML bools/dates
appear where strings belong in real specs).
Fixes the remaining 5 APIs.guru regressions (fec.gov, greip.io,
nordigen.com, vercel.com, vtex.local).
https://claude.ai/code/session_012uMV8n26pbFxhKLu83rTjE
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This release promotes spec-defined fields that previously only appeared in
model_extrato proper typed model fields across the OpenAPI spec models. Raw values are mirrored inmodel_extrafor backwards compatibility (deprecated, to be removed in 0.5.0).Key Changes
Schema Model
ref($ref),format,enum,default,const,deprecated,nullable,read_only,write_only,example,examples,discriminator,additional_properties, and numeric/string/array/object constraint fieldshas_defaultandhas_constproperties to distinguish explicitnullvalues from absent fieldstypesproperty (always-a-list view oftypekeyword for OpenAPI 3.1 compatibility)primary_typeandis_nullableproperties for unified 3.0/3.1 type handlingSpecModelbase class with declarativefrom_dict()for nested field parsingOperation Model
parameterstolist[Parameter](typed),responsestodict[str, Response](typed)request_body,security,callbacks,deprecated,servers,external_docsOther Models
ref,deprecated,allow_empty_valuetyped fieldsref,deprecatedtyped fieldsreftyped fieldschema_is now typedSchemainstead of raw dictheadersis nowdict[str, Header]instead of raw dictoperation_ref,operation_id,request_body) with camelCase aliases; added typedserverref,summary,descriptiontyped fields; path-levelparametersnow typedproperty_nameandmappingQuery API Improvements
operations_by_tag(tag)to filter operations by tagtags_to_operations()to group all operations by tag__iter__()toPathsfor direct iteration over (path, PathItem) pairsReferenceResolverfor performanceBackwards Compatibility
model_extravia newmirror_extras()helperpopulate_by_name=Truefor programmatic construction with snake_case namesschema.model_extra.get("enum")continue to work (deprecated)Infrastructure
SpecModelbase class with declarative nested field parsing viaNESTED_FIELDSandMIRRORED_EXTRA_KEYSclass variablesNotable Implementation Details
from_dict()pattern inSpecModelseparates nested field parsing (handled declaratively) from Pydantic validation, enabling proper type conversion while preserving raw values for mirroringtype: str | list[str]with helper properties for unified accesshttps://claude.ai/code/session_012uMV8n26pbFxhKLu83rTjE