Skip to content

feat: render a property's description as an attribute docstring - #11

Merged
goduni merged 2 commits into
mainfrom
feat/field-docstrings
Aug 17, 2026
Merged

feat: render a property's description as an attribute docstring#11
goduni merged 2 commits into
mainfrom
feat/field-docstrings

Conversation

@goduni

@goduni goduni commented Aug 16, 2026

Copy link
Copy Markdown
Owner

Description

A schema's description became a class docstring, but a property's went nowhere: the IR
carried it and every serializer dropped it. Prose the spec author wrote for a field was
invisible in the generated client.

It is now emitted as a PEP 258 attribute docstring under the field:

class Pet(BaseModel):
    id: int
    """Server-assigned identifier."""

Why this device and not the native ones:

  • it is what the method classes already do for parameters and body fields, so the two
    halves of a generated package read the same way;
  • it renders identically for all three serializers — pydantic would otherwise need
    Field(description=...) on every documented field, msgspec an
    Annotated[..., Meta(description=...)], and adaptix has no equivalent at all;
  • it is inert at runtime. The class body just evaluates a string, so constructors,
    decoding, and the emitted JSON schema are unchanged. Editors show it on hover.

Wrapping, embedded quotes, and backslashes are handled by the existing docstring
helper, which already switches to a raw string when the prose contains a backslash.

Relation to #10

Independent, and they compose: #10 keeps a subtype's explicit re-declaration (and its
prose) in the IR, this one puts that prose in the output. Both touch the field loop in
the three render_model methods, so whichever merges second has a one-line conflict per
serializer.

Type of change

  • New feature (a non-breaking change that adds functionality)
  • This change requires a documentation update

Verification

  • uv run pytest --cov src --cov-fail-under=80 --cov-report=term — 328 passed, 100% coverage
  • uv run ruff check
  • uv run ruff format --check
  • uv run mypy
  • all three example libraries regenerated via their regen.sh, each passing its own
    ruff check --isolated + mypy --strict gate

Note on the examples diff

The committed example libraries are regenerated here, and most of that diff predates this
change: they were already stale by 31 lines' worth of method-parameter docstrings from an
earlier release. The 5 lines under models/ are this change.

Checklist

  • My code adheres to the style guidelines of this project
  • I have conducted a self-review of my own code
  • I have made the necessary changes to the documentation
  • My changes do not generate any new warnings
  • I have added tests to validate the effectiveness of my change
  • I have ensured that type checking passes by running uv run mypy

goduni added 2 commits August 17, 2026 00:16
A schema's `description` became a class docstring, but a property's went
nowhere: the IR carried it and every serializer dropped it, so prose the spec
author wrote for a field was invisible in the generated client.

Emit it as a PEP 258 attribute docstring under the field. That is the device
the method classes already use for parameters and body fields, and it is the
only one that renders identically for all three serializers: pydantic would
otherwise need `Field(description=...)` on every documented field, msgspec an
`Annotated[..., Meta(description=...)]`, and adaptix has no equivalent at all.
It is also inert -- the class body just evaluates a string -- so constructors,
decoding, and the emitted JSON schema are untouched, while editors show the
prose on hover.

Wrapping, embedded quotes, and backslashes are handled by the existing
`docstring` helper, so a raw string is used where the prose needs one.

The committed example libraries are regenerated. Most of that diff predates
this change: they were already stale by 31 lines' worth of method-parameter
docstrings from an earlier release. The 5 lines under `models/` are this one.
The unit tests import the rendered module, which proves an attribute docstring
is inert, but nothing ran ruff or mypy over one: neither compile-gate fixture
had a property with prose. The wrapping width the docstring helper targets is
ruff's, so the one gate that would catch a regression was the one not looking.

Give the sample spec a described property, long enough to wrap and carrying
embedded quotes, so every gate combination -- three serializers, both file
layouts, and the stubs pass -- checks the rendered prose.

Also drop the unused ``indent`` parameter from ``field_doc_lines``: every
strategy renders at the class-body indent, and nothing passed anything else.
@goduni
goduni force-pushed the feat/field-docstrings branch from 7cffe06 to 8aeba77 Compare August 17, 2026 00:19
@codecov

codecov Bot commented Aug 17, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (6eefcd0) to head (8aeba77).

Additional details and impacted files
@@            Coverage Diff            @@
##              main       #11   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           31        31           
  Lines         2726      2735    +9     
=========================================
+ Hits          2726      2735    +9     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@goduni
goduni merged commit ea9f9c6 into main Aug 17, 2026
5 checks passed
@goduni
goduni deleted the feat/field-docstrings branch August 17, 2026 00:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant