Skip to content

fix: enforce minProperties on generated models#55

Merged
damaz91 merged 5 commits into
Universal-Commerce-Protocol:mainfrom
vishkaty:fix/min-properties-49
Jul 17, 2026
Merged

fix: enforce minProperties on generated models#55
damaz91 merged 5 commits into
Universal-Commerce-Protocol:mainfrom
vishkaty:fix/min-properties-49

Conversation

@vishkaty

Copy link
Copy Markdown
Contributor

Fixes #49: datamodel-code-generator drops minProperties on object schemas with declared properties, so Description() validates with zero fields in violation of description.json's minProperties: 1. (The free-form-object case is unaffected — the generator already maps that to Field(min_length=...) on the dict field, e.g. AvailablePaymentInstrument.constraints.)

Implements the post-processing option proposed in the issue: a new postprocess_models.py step (wired into generate_models.sh between generation and formatting) scans the preprocessed schemas for root-level minProperties constraints and injects a model_validator(mode="after") into each matching generated class.

Counting semantics follow JSON Schema (keys present on the object), verified empirically against pydantic: provided fields (model_fields_set) unioned with extra keys (model_extra) — an explicit null is a present key, and unknown keys on extra="allow" models count too; the union avoids double-counting since pydantic includes extras in model_fields_set.

Properties of the step:

  • Data-driven: future minProperties additions to any schema are picked up on regeneration, no code change needed (currently description.json is the only root-level case on ucp main; there are no nested property-carrying cases).
  • Idempotent, and fails generation loudly if a constraint can't be mapped to a generated class — a constraint can never be silently dropped again.
  • The committed Description model is regenerated with the validator.

Validation

  • tests/test_min_properties.py: dependency-free injector tests (insertion, idempotency, schema scan, multi-class modules) + semantic tests on the real Description model (empty rejected; single field, explicit-null key, and extra-only key accepted). Full unittest discover: 23/23 green.
  • The workflow now runs pip install -e . so the semantic tests execute in CI rather than skipping.
  • Downstream check: the conformance suite (editable SDK) run against the samples Flower Shop stays green with the patched model.
  • ruff format + ruff check clean.

…otocol#49)

datamodel-code-generator drops minProperties on object schemas with declared
properties, so Description() validated with zero fields in violation of
description.json's minProperties: 1. (minProperties on free-form object
properties is unaffected — the generator already maps those to
Field(min_length=...) on the dict field.)

A new post-generation step (postprocess_models.py, wired into
generate_models.sh before formatting) scans the preprocessed schemas for
root-level minProperties constraints and injects a
model_validator(mode="after") into each matching generated class. JSON
Schema counts the keys present on the object, so the validator counts
provided fields (model_fields_set) unioned with extra keys (model_extra):
an explicit null is a present key, and unknown keys on extra="allow"
models count too. The step is idempotent, data-driven from the schemas
(future minProperties additions are picked up on regeneration), and fails
generation loudly if a constraint can't be mapped to a generated class.

The committed Description model is regenerated with the validator. Tests
cover the injector (dependency-free) and the enforced semantics on
Description; the workflow now installs the package so those semantic tests
run in CI.
@damaz91 damaz91 added the status:needs-triage Signal that the PR is ready for human triage label Jul 16, 2026
@damaz91 damaz91 added status:under-review and removed status:needs-triage Signal that the PR is ready for human triage labels Jul 16, 2026
damaz91 and others added 4 commits July 17, 2026 10:04
Deletes tests/test_min_properties.py and merges its test cases into tests/test_codegen_pipeline.py (renamed from test_preprocess_schemas.py to better reflect its expanded scope of testing both pre- and post-processing).
Replaces print statements with sys.stdout.write/sys.stderr.write (T201), splits long lines (E501), and adds docstring to main (D103) to comply with project lint configuration.
Replaces propert{y_ies} template variable with properties_noun to avoid codespell false positive on propert. Regenerated models to apply template change.
@damaz91
damaz91 merged commit c1ffd1b into Universal-Commerce-Protocol:main Jul 17, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: minProperties constraint is ignored in generated Pydantic models

2 participants