[FEATURE](codegen) Carry deprecation through extraction and render it in the Markdown reference - #757
Open
Seth Fitzsimmons (sethfitz) wants to merge 1 commit into
Open
Seth Fitzsimmons (sethfitz) wants to merge 1 commit into
Seth Fitzsimmons (sethfitz) wants to merge 1 commit into
Conversation
…markdown FieldSpec had no slot for Pydantic's deprecated, so a field marked Field(deprecated=...) extracted with the signal dropped -- before any renderer saw it. RecordSpec had no equivalent for PEP 702's @deprecated(...) on a model class either. FieldSpec now carries is_deprecated/deprecation_message, normalized from all three forms Pydantic admits: a bare True, a message string, or a deprecated(...) marker usable directly as Annotated metadata (the marker arrives as an object, so its .message needs unwrapping). The flag and the message stay separate because deprecated=True is deprecated with no prose, which a lone str | None can express only as a sentinel. RecordSpec carries deprecated: str | None, read from the class __dict__ rather than by attribute lookup. __deprecated__ is a plain class attribute, so getattr walks the MRO and reports a base's deprecation on every subclass -- which would banner the three TransportationSegment subclasses and the five VehicleSelectorBase ones the moment a base is deprecated. The Markdown renderer gives a deprecated model a :::warning[Deprecated] admonition above its description, since Docusaurus renders this reference and an admonition carries more than bold text. A deprecated field gets a "Deprecated: <message>" note appended to its description cell through the existing constraint-note appender and a (deprecated) tag in its Type column; the note stays inline because an admonition is block-level and a table cell cannot hold one. A bare deprecated=True renders a generic message rather than dropping the signal silently. Closes #674 Signed-off-by: Seth Fitzsimmons <seth@mojodna.net>
🗺️ Schema reference docs preview is live!
Note ♻️ This preview updates automatically with each push to this PR. |
This branch was successfully deployed
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.
Description
Schema authors can already write
Field(deprecated=...)and PEP 702's@deprecated(...)on a model, but nothing downstream sees it: the codegen IR drops it during extraction, so the generated Markdown reference renders a deprecated field exactly like a live one. A data consumer reading the docs has no way to know a field is on its way out.This carries deprecation through extraction and renders it.
Extraction gains
FieldSpec.is_deprecated/FieldSpec.deprecation_messageandRecordSpec.deprecated. The field-level side normalizes all three forms Pydantic accepts onField(deprecated=...): a bareTrue, a message string, and adeprecated(...)marker. The marker is also usable directly asAnnotatedmetadata, and for that form Pydantic surfaces the marker object itself onfield_info.deprecatedrather than a string, so the prose has to be read off its.messageattribute — a plainisinstance(..., str)test drops it.The model-level side reads
__deprecated__off the class__dict__. Attribute lookup would walk the MRO and report a parent's deprecation on every subclass, which in this schema would put a banner on the threeTransportationSegmentsubclasses and the fiveVehicleSelectorBaseones the moment a base is deprecated.typing_extensions.deprecatedsets the attribute on our 3.10 floor; the stdlibwarnings.deprecatedsets the same one from 3.13, so the read does not change when the floor moves.FieldSpeccarries a flag and a message rather than a singlestr | None, becausedeprecated=Trueis deprecated-with-no-prose andstr | Nonecan only encode that as a sentinel string.RecordSpec.deprecatedisstr | None, since@deprecated()'s message argument is required.The Markdown reference then renders both. A deprecated model gets a
:::warning[Deprecated]admonition directly under the H1, above the docstring description — Docusaurus renders this reference, so an admonition is the richer form than bold text. A deprecated field gets a**Deprecated:** <message>note appended to its Description cell through the existing constraint-note mechanism, and a(deprecated)qualifier in its Type column alongside(optional), so the Type column reads`string` (optional, deprecated). The field note stays inline because an admonition is a block-level directive and the note lives in a table cell. A baredeprecated=Truewith no message renders a generic "This field is deprecated." rather than dropping the signal.Enum members and bare type aliases are out of scope, per #674. Neither has a
@deprecatedhook to read: PEP 702's decorator applies to classes and functions, and an enum member is an instance of its enum class rather than a class of its own, whileAnnotated[...]andNewTypeproduce objects the decorator does not accept. Marking either would need a project-specific convention rather than a native mechanism; #639 carries that open question.Reference
deprecationchangelog type. Not landed, so the fragment here is674.feature.mdunder the existingfeaturetype; it would be reclassified if [CHORE] Add a towncrier "deprecation" changelog type #675 lands.Checklist
Checklist of tasks commonly-associated with schema pull requests. Please review the relevant checklists and ensure you do all the tasks that are required for the change you made.
**Deprecated:** <message>and the bare-Truefallback reads "This field is deprecated."Documentation website
Update the hyperlink below to put the pull request number in.
Docs preview for this PR.