Skip to content

[FEATURE] Carry deprecation through extraction and render it in the Markdown reference #674

Description

Sub-issue of #639 — surface 1 of 3 ("What flows where"), and the one we need first.

Scope

Carry the deprecation message from the Pydantic models through extraction, and render it in the generated Markdown reference. Self-contained and shippable on its own: it delivers the reference-doc value without touching validation or the changelog.

The extraction carrier lands here because Markdown is its first consumer. The PySpark surface (#676) and the deprecation manifest (#677) both read the same carrier, so this issue is their prerequisite.

Marking mechanism

Native Python, no custom marker:

  • Fields — Pydantic's Field(deprecated=...), which accepts True, a message string, or a PEP 702 deprecated(...) marker (also usable directly in Annotated metadata). All forms normalize to FieldInfo.deprecation_message (str | None).
  • Models — PEP 702's @deprecated("message") (typing_extensions.deprecated on our 3.10 floor), which sets __deprecated__ on the class. Read with getattr(cls, "__deprecated__", None).
old_field: str | None = Field(
    default=None,
    deprecated="Use `new_field` instead. Deprecated in v1.18.0.",
)

@deprecated("Use `NewFeature` instead. Deprecated in v1.18.0.")
class OldFeature(Feature):
    ...

Work

  • Add deprecated: str | None to FieldSpec and to the model/record spec.
  • Populate both in model_extraction.py: field_info.deprecation_message for fields, getattr(model_class, "__deprecated__", None) for the model.
  • Field-level rendering: append a **Deprecated:** <message> note to the field's Description cell through the existing constraint-note appender, and tag the Type column with (deprecated) alongside (optional).
  • Model-level rendering: a **Deprecated:** <message> banner at the top of the feature page.
  • Mark one field and one model deprecated in a test fixture (not in the published schema) and assert the rendered output.

Out of scope

Enum members and bare type aliases (Annotated[...], NewType) have no native @deprecated hook and would need a project-specific convention. Deferred — see the open question on #639.

Acceptance

  • A field marked Field(deprecated=...) in any of the three accepted forms renders its message in the reference.
  • A class marked @deprecated(...) renders a banner on its feature page.
  • deprecated=True (bare) renders the generic deprecated message rather than dropping the signal.
  • Nothing changes in the rendered output for undeprecated fields and models.

Integration points

  • Extraction: packages/overture-schema-codegen/.../codegen/extraction/model_extraction.py — reads FieldInfo at ~159, builds FieldSpec at ~175-183 (description at ~179).
  • Carrier: packages/overture-schema-codegen/.../codegen/extraction/specs.pyFieldSpec at ~122-135, RecordSpec at ~139.
  • Markdown: packages/overture-schema-codegen/.../codegen/markdown/renderer.py_field_template_context (~203) building _FieldRow (~122), appending via _annotate_constraint_notes (~218). Template codegen/markdown/templates/feature.md.jinja2: field loop (~11-12), page header (~2-4).

Metadata

Metadata

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions