-
Notifications
You must be signed in to change notification settings - Fork 36
Description
Summary
Currently the generator performs a limited flattening of allOf when (and only when) the composed schema has no own properties. This helps fill in otherwise empty models (ex: schemas composed only from parents) but it does not implement true inheritance semantics.
Problems With Current Behavior
- Mixed augmentation is lost: A schema that has its own properties and
allOfparents only emits its direct properties; inherited ones are ignored. - Pure reference composition stays empty:
allOf: [{ "$ref": A }, { "$ref": B }]does not surface any fields. - Required propagation incomplete:
requiredfrom referenced parents is not carried over unless the parent was inline with properties (and only in the current edge flattening case). - Diagnostic ambiguity: Generated models give no indication that inheritance occurred or was intended.
Desired Behavior (Preferred Approach)
Implement true inheritance for allOf chains by generating base classes first and then emitting subclasses that inherit from them rather than flattening fields. This preserves structural intent, yields cleaner diffs against the source spec, and reduces accidental name collisions.
Example (conceptual):
components:
schemas:
Base:
type: object
properties:
id:
type: string
required: [id]
Child:
allOf:
- $ref: '#/components/schemas/Base'
- type: object
properties:
name: { type: string }
required: [name]Generated (Pydantic v2 template example):
class Base(BaseModel):
id: str
class Child(Base):
name: strIf multiple parents:
Child:
allOf:
- $ref: '#/components/schemas/BaseA'
- $ref: '#/components/schemas/BaseB'
- type: object
properties: { extra: { type: integer } }Becomes:
class Child(BaseA, BaseB):
extra: intProposed Implementation Phases
-
Graph Analysis
- Build dependency graph of schemas using
allOfreferences. - Topologically sort to ensure parent models are emitted before children.
- Detect cycles (fail fast with clear error or skip inheritance).
- Build dependency graph of schemas using
-
Parent Extraction
- For each schema with
allOf, separate referenced parents ($ref) from inline augmentation schemas (object schemas that add properties / required / description).
- For each schema with
-
Code Generation Adjustments
- Modify model template context to accept a list of base class names (instead of always
BaseModel). - Preserve existing flatten fallback only for pathological cases (e.g., cycle, invalid parent reference, no valid object parent found).
- Modify model template context to accept a list of base class names (instead of always
-
Required Handling
- Do NOT re-declare inherited properties in child class.
- Only emit properties from inline augmentation fragments.
-
Edge Cases / Guards
- Multiple parents: maintain order of appearance in
allOf. - Conflicting property names: inline augmentation property names that clash with parent names should raise a warning (or skip with note) instead of silently overriding.
- Non-object fragments inside
allOf(e.g., constraints-only fragments) should be merged into validation metadata later (out of scope for first cut—document limitation).
- Multiple parents: maintain order of appearance in
-
Backwards Compatibility
- Keep current flatten logic behind a feature flag (e.g.,
--flatten-allofvs default inheritance) OR - Introduce new flag
--inherit-allofdefaulting to True in next minor version; mark flattening behavior as deprecated.
- Keep current flatten logic behind a feature flag (e.g.,
Alternatives (for discussion)
- Always Flatten (Current + merging refs) – simplest but loses intent.
- Hybrid: Inherit if only refs + one inline object, otherwise flatten.
- Recursive Full Merge – produce a single class with all merged fields; potential name conflicts & loss of structure.
- True Inheritance (Preferred) – described above.
Preference
Adopt Option 4 (True Inheritance) with implementation phases outlined.
Acceptance Criteria
- A schema composed purely of references generates a subclass inheriting all parents (empty body ->
pass). - A schema with inline augmentation emits only augmentation fields; inherited ones appear via base classes.
- Multiple parent references preserved in declared order.
- Tests cover: single parent, multiple parents, parent + augmentation, pure refs, cycle detection.
- Flag / configuration documented in README and quick start.
Follow-Up / Future Enhancements
- Merge validation keywords from parent and inline fragments (minLength, pattern, etc.) into field constraints.
- Support discriminator-based polymorphism for oneOf / anyOf.
Requested Labels
enhancement, openapi-3.1, models, inheritance
Requested by user; preference strongly for true inheritance approach.