[FEATURE] Add an extension mechanism with discovery and codegen support - #655
Draft
Roel Bollens (RoelBollens-TomTom) wants to merge 1 commit into
Draft
[FEATURE] Add an extension mechanism with discovery and codegen support#655Roel Bollens (RoelBollens-TomTom) wants to merge 1 commit into
Roel Bollens (RoelBollens-TomTom) wants to merge 1 commit into
Conversation
Signed-off-by: Roel <75250264+RoelBollens-TomTom@users.noreply.github.com>
🗺️ Schema reference docs preview is live!
Note ♻️ This preview updates automatically with each push to this PR. |
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.
closes #634
This PR adds a model extension mechanism that lets packages contribute optional fields to models they do not own.
Extensions use the existing
overture.modelsentry-point group. Discovery identifies them throughExtendsmetadata.A model extension uses
@extends:Non-model types use
ExtendsinsideAnnotated, optionally behind aNewType:Both are registered like ordinary models:
During discovery, each extension becomes a standalone one-field wrapper model. This wrapper can validate extension-only payloads when extension data is stored separately from the base feature.
By default,
discover_models()also adds the optional extension field—named after its entry point—to every matching registered model.Target resolution
Targets can be model classes or model-bearing unions,
Annotated,NewType, andRootModelexpressions.Place | intis rejected.RootModelis treated as an alias for its root annotation. Targeting it targets the models in its root, while extending a registeredRootModelrebuilds the root with the extended models.RootModelover a scalar does not resolve to a model and cannot be used as a target.list[Place]anddict[str, Place]are not traversed.Stacked
@extendsdecorators and multipleExtendsdeclarations in oneAnnotatedlayer merge their targets. A subclass’s own declaration shadows an inherited declaration. Field-name collisions are skipped with a warning, while invalid entry-point names are rejected during wrapping.Codegen changes
Extracted fields record whether they came from an extension. Generated Markdown marks these fields with (extension), and union deduplication keeps native and extension fields separate even when their shapes match.
Extendsdeclarations are metadata rather than validation constraints, so they are excluded from constraint collection.Follow-up branches
Two branches build on this one:
extensions-examplesadds two example packages:overture-schema-extensions-operating-hours, a model extension targetingPlace, andoverture-schema-extensions-capacity, a scalarNewTypeextension targetingPlaceandBuilding. Both include valid and invalid GeoJSON examples and tests covering the complete wrap-and-merge path.extensions-typing-refactortypes the declaration API withExtensionTarget: TypeAlias = TypeForm[BaseModel]. It also raises the mypy floor to 2.2.0, the first release that supportsTypeFormwithout an experimental flag.Trying the examples
Extensions are ordinary packages connected through entry points, so they can be installed without changing application code:
This installs them into the current environment only.
The extension entries and extended
Placemodel are then available through the existing CLI:Changing
capacityto300violates theuint8range. Changingopento"9:00"violates the time pattern. Extension fields are validated in the same way as native fields.Each example package also includes ready-made valid and invalid GeoJSON files. Their tests cover the complete wrap-and-merge path, including validation of extension-only payloads against the standalone wrappers.