fix: support default {} on freeform object schemas#1449
Open
alexander-wenzel-dev wants to merge 1 commit into
Open
fix: support default {} on freeform object schemas#1449alexander-wenzel-dev wants to merge 1 commit into
{} on freeform object schemas#1449alexander-wenzel-dev wants to merge 1 commit into
Conversation
A schema declared as `type: object` with `additionalProperties: true` and no
declared properties (often appearing inside an `anyOf` with `null`) could not
carry a `default: {}`. `ModelProperty.convert_value` rejected the default with
`ModelProperty cannot have a default value`, which propagated up as a warning
and silently dropped the enclosing schema and every endpoint referencing it.
`ModelProperty.convert_value` now accepts the empty dict on a freeform model
and emits a `ClassName()` constructor call. When `required_properties` has not
yet been populated, the check falls back to the raw schema (`data.properties`,
`data.allOf`, `data.anyOf`, `data.oneOf`) so referenced schemas not yet
processed still get the correct decision.
A default value also forces the generated client to import the inner model at
runtime rather than only under `TYPE_CHECKING`, otherwise the default
initializer would `NameError` at class-definition time. `get_imports` and
`get_lazy_imports` are updated accordingly on both `ModelProperty` and
`UnionProperty` so inner-property imports are promoted when the property has a
non-`None` default.
Tests: a functional test in `end_to_end_tests/functional_tests` covers the
inline spec, and unit tests in
`tests/test_parser/test_properties/test_model_property.py` cover the new
branches in `convert_value`, `get_imports`, and `get_lazy_imports`.
This was referenced Jun 6, 2026
alexander-wenzel-dev
added a commit
to alexander-wenzel-dev/mealie-mcp
that referenced
this pull request
Jun 6, 2026
Adds a [tool.uv.sources] override resolving openapi-python-client from alexander-wenzel-dev/openapi-python-client at branch pin/mealie-mcp-combined. The branch carries two unmerged generator fixes (upstream PRs openapi-generators/openapi-python-client#1448 and openapi-generators/openapi-python-client#1449) that unblock the Recipe-Input / Recipe-Output models and the PUT/PATCH recipe endpoints in the generated client. This commit only changes resolution; the generated client tree is untouched and gets regenerated in a separate PR. Removal plan is inline in pyproject.toml.
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.
fix: support default
{}on freeform object schemasSummary
A freeform object schema (
type: object,additionalProperties: true,no declared properties) inside an
anyOfcould not carry adefault: {}. The parser rejected the default, which silently droppedthe enclosing schema and every endpoint that referenced it. This PR
accepts the empty-dict default and generates a working empty-container
initializer.
Problem
A schema declared as
type: objectwithadditionalProperties: trueand no declared properties (often appearing inside an
anyOfwithnull) could not carry adefault: {}.ModelProperty.convert_valuerejected the default with
ModelProperty cannot have a default value,which propagated up as a warning and silently dropped the enclosing
schema and every endpoint that referenced it.
Minimal reproduction
Before this PR:
ModelWithFreeformDefaultis missing from thegenerated client; the only signal is a warning on stderr.
Fix
Three coordinated changes in
model_property.pyandunion.py:ModelProperty.convert_valueaccepts{}on a freeform modeland emits a
ClassName()constructor call. Whenrequired_propertieshas not yet been populated, the check fallsback to the raw schema (
data.properties,data.allOf,data.anyOf,data.oneOf) so a referenced schema still gets thecorrect decision before its properties have been processed.
Import promotion in
ModelProperty. A default value forces thegenerated client to import the inner model at runtime rather than
only under
TYPE_CHECKING, otherwise the default initializer wouldNameErrorat class-definition time.get_importsandget_lazy_importsare updated so inner-property imports arepromoted when the property has a non-
Nonedefault.Import promotion in
UnionProperty. The same promotion appliesto unions that carry a default — every inner property's lazy
imports become runtime imports so the union's default expression
resolves at class-definition time.
Tests
end_to_end_tests/functional_tests/generated_code_execution/test_freeform_object_defaults.py— uses the inline spec above, asserts the model is instantiable
and that the default
extrasis the empty container.tests/test_parser/test_properties/test_model_property.py:test_get_imports_with_defaultandtest_get_lazy_imports_with_defaultcover the import-promotion branches.
test_convert_valueandtest_convert_value_unprocessedcoverconvert_value's new accept/reject decisions, including thepre-processing fallback path.
Local verification
All green on Python 3.14. 100% coverage on both changed files
(
model_property.py,union.py) when measured across the fullupstream suite. Golden-record snapshot tests pass without
regeneration — the import-promotion paths are only reachable when a
model has a non-
Nonedefault, which previously errored, so noexisting snapshot can depend on the old behaviour.
Risk
ModelProperty.convert_valuechanges from a@classmethodto aninstance method. A grep across
openapi_python_client/,tests/,and
end_to_end_tests/finds zeroModelProperty.convert_value(...)class-level call sites; every caller uses
prop.convert_value(...)via the
PropertyProtocol. The signature change is invisible toexisting call sites.
{}is accepted, and only ona model that is genuinely freeform (no
properties,allOf,anyOf, oroneOf). Any other default value still returnsPropertyErrorwith the original message, so models with requiredfields can't slip through with an empty default.
pdm regen.Related
Companion PR: #1448 — a second independent fix for the
title-collision case surfaced from the same downstream spec. The two
PRs share no code paths and can land in either order.