Fix OpenAPI default, const, and $ref parameter support#247
Merged
Conversation
generate_class_properties ignoring OpenAPI default valuesdefault and const support in schema generation
default and const support in schema generationdefault, const, and $ref parameter support
Owner
|
@chassing thanks for this, I am going to try and look into it tomorrow (Friday) and get this merged and shipped. Please could you update the CHANGELOG.md files with one-sentence notes of the fixes? Feel free to make a new version 2.2.0 |
Properties with explicit `"default"` values in OpenAPI specs (e.g. `[]`, `0`, `true`, `false`, `null`) were generated as required fields without defaults. Now checks for `"default"` in property details and renders the value using `repr()` for correct Python literals. Fields needing both an alias and a default use `pydantic.Field(default=..., alias="...")`.
The `schema_to_dict` compat layer was not extracting `"default"` from cicerone's `__pydantic_extra__`, so defaults from the OpenAPI spec were lost before reaching `generate_class_properties`. Uses `"in"` membership check instead of truthiness since defaults can be falsy (`[]`, `0`, `false`, `null`).
`schema_to_dict` now extracts `"const"` from cicerone's `__pydantic_extra__`. `get_type` returns `typing.Literal[<value>]` when `"const"` is present, which is required for Pydantic discriminated unions to work correctly.
Parameters referencing schemas via `$ref` (e.g. enums like `ActionStatus`) produced bare forward references in `client.py` with no import. Now `generate_parameters` resolves forward refs to `schemas.X` via `resolve_forward_refs_for_client`. Also fixes double-nullable types (`X | None | None`) when `anyOf: [$ref, null]` was wrapped again in `typing.Optional`. `strip_none_from_type` removes existing None before re-wrapping.
aa3f793 to
24db8a2
Compare
Owner
|
Rebasing so CI can run. |
phalt
approved these changes
Jun 5, 2026
phalt
left a comment
Owner
There was a problem hiding this comment.
This is great. I am working to fix a few more bugs on another issue - I think you actually fix one of mine here! So I'll merge your stuff and then continue with my work before I do the final 2.2.0 release :)
phalt
pushed a commit
that referenced
this pull request
Jun 5, 2026
Bug 1 (enum forward refs in client.py) was resolved by PR #247 via resolve_forward_refs_for_client(). Two bugs remain unaddressed: Bug 2 - Array response schemas are emitted as bare type aliases (e.g. UploadFaces200Response = list[FaceItem]). A GenericAlias is not a type, so pydantic rejects it in response_map: dict[int, type[Any]]. Fix should emit a pydantic.RootModel subclass instead. Bug 3 - Generated config.py example says API_BASE_URL but pydantic-settings reads BASE_URL (the field is named base_url). The wrong name is silently ignored (extra='ignore') and the client falls back to http://localhost. Fix should document BASE_URL and base_url= in the example. https://claude.ai/code/session_011e1xPCeW7nD8rn9vWppPPm
phalt
pushed a commit
that referenced
this pull request
Jun 5, 2026
Bug 1 (enum forward refs in client.py) was resolved by PR #247 via resolve_forward_refs_for_client(). Two bugs remain unaddressed: Bug 2 - Array response schemas are emitted as bare type aliases (e.g. UploadFaces200Response = list[FaceItem]). A GenericAlias is not a type, so pydantic rejects it in response_map: dict[int, type[Any]]. Fix should emit a pydantic.RootModel subclass instead. Bug 3 - Generated config.py example says API_BASE_URL but pydantic-settings reads BASE_URL (the field is named base_url). The wrong name is silently ignored (extra='ignore') and the client falls back to http://localhost. Fix should document BASE_URL and base_url= in the example. https://claude.ai/code/session_011e1xPCeW7nD8rn9vWppPPm
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
defaultsupport:generate_class_propertiesnow reads"default"from OpenAPI property definitions and renders the value as a Python literal viarepr(). Fields with both a default and an alias usepydantic.Field(default=..., alias="..."). Uses"default" in arg_details(not truthiness) so falsy defaults like[],0,False,"", andnullare handled correctly.constsupport:get_typenow checks for"const"and generatestyping.Literal[<value>]. This is required for Pydantic discriminated unions to work — withoutLiteral, Pydantic raisesPydanticUserError: Model needs field to be of type Literal.$refin parameters: Parameters referencing schemas via$ref(e.g. enums likeActionStatus) now resolve toschemas.Xinclient.pyinstead of bare forward references with no import.anyOf: [$ref, {type: null}]parameters no longer produceX | None | None— existing nullability is detected and not duplicated.schema_to_dictcompat layer: Extracts both"default"and"const"from cicerone's__pydantic_extra__, which were previously silently dropped during spec parsing.Before:
After:
Test plan
test_generate_class_properties_with_defaults— list[], int0, boolFalse, string"", null defaultstest_generate_class_properties_default_with_alias— field with alias + default usespydantic.Fieldtest_generate_class_properties_no_required_array_with_defaults— schema with norequiredarray, all fields have explicit defaultstest_generate_class_properties_with_const— const generatestyping.Literaltest_generate_class_properties_const_with_default— const + default generatesLiteraltype with default valuetest_generate_class_properties_const_with_alias— const + alias usespydantic.Fieldtest_resolve_forward_refs_for_client— forward refs replaced withschemas.Xtest_strip_none_from_type— handles Optional, Union with None, pipe None, plain typestest_clients_generator_resolves_schema_refs_in_parameters—anyOf: [$ref, null]producestyping.Optional[schemas.X]without double None