Skip to content

fix(http-client-python): escape leading @ in docstring field targets - #11622

Merged
Yuchao Yan (msyyc) merged 4 commits into
microsoft:mainfrom
l0lawrence:l0lawrence-legendary-enigma
Aug 13, 2026
Merged

fix(http-client-python): escape leading @ in docstring field targets#11622
Yuchao Yan (msyyc) merged 4 commits into
microsoft:mainfrom
l0lawrence:l0lawrence-legendary-enigma

Conversation

@l0lawrence

Copy link
Copy Markdown
Member

Problem

When a property/parameter wire name starts with @ (e.g. @search.facets), the generated Python docstrings emit it directly as the target of a Sphinx info field:

:vartype @search.facets: dict[str, list["FacetResult"]]

Sphinx/docutils interprets the leading @, which breaks the rendered docstring.

Fix

Added a shared helper escape_sphinx_field_name (in models/utils.py) that escapes @\@, and applied it at every site that emits a name as a docstring info-field target:

  • Models & TypedDictsmodel_serializer._documentation_string (:ivar/:vartype, :keyword/:paramtype)
  • Operationsbuilder_serializer.param_description (:param/:type, :keyword/:paramtype)
  • Clientsclient_serializer.property_descriptions (client :ivar operation groups, client-level params, and config params)

Scope note

The escaping is applied only where the name lands inside a docstring, because \@ is an RST/Sphinx escape — not a Python one. The raw @ is preserved everywhere else (TypedDict keys, rest_field(name=...), wire serialization), where it's the correct on-the-wire value. In practice @ only ever reaches a docstring via the TypedDict types file (the only path that renders the raw wire_name); the other call sites use the sanitized client_name and are covered defensively / future-proofed.

Tests

Added test_models_mode_typeddict_docstring_escapes_at_sign, which asserts both that the docstring field target is escaped (:vartype \@search.facets:) and that the generated TypedDict key keeps the raw "@search.facets":.

Wire names such as @search.facets are emitted as the target of Sphinx info fields (:ivar/:vartype/:keyword/:paramtype/:param/:type). A leading @ is interpreted by Sphinx and breaks the rendered docstring, so escape it via a shared escape_sphinx_field_name helper applied across model, TypedDict, operation, and client docstring generation. The raw @ is preserved everywhere else (e.g. TypedDict keys, wire names).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 4b38539c-8877-4fdc-8b9d-bc400a50d325
@pkg-pr-new

pkg-pr-new Bot commented Aug 11, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@typespec/http-client-python@11622

commit: fa83dcb

@github-actions

github-actions Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

All changed packages have been documented.

  • @typespec/http-client-python
Show changes

@typespec/http-client-python - fix ✏️

Wrap wire names containing @ (e.g. @search.facets) in double backticks when they are used as Sphinx docstring field targets (:ivar/:vartype/:keyword/:paramtype/:param/:type) across models, TypedDicts, operations, and clients, so the generated docstrings render correctly without introducing an invalid escape sequence in the generated code.

… fields

A leading @ in a Sphinx info-field target is fine in stock autodoc, but escaping it as \@ (the previous approach) emits an invalid Python escape sequence into the generated SDK (SyntaxWarning / SyntaxError under -W error). Instead wrap names containing @ in double backticks (inline literal), which renders correctly across :ivar/:vartype/:keyword/:paramtype/:param/:type with no backslash and no invalid escape.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 4b38539c-8877-4fdc-8b9d-bc400a50d325
@azure-sdk-automation

azure-sdk-automation Bot commented Aug 11, 2026

Copy link
Copy Markdown

You can try these changes here

🛝 Playground 🌐 Website 🛝 VSCode Extension

…atter

An earlier accidental black run at the wrong line length split two function signatures in model_serializer.py across multiple lines. That moved the '# pylint: disable=too-many-return-statements' comment off the def line, breaking the suppression (R0911 + useless-suppression). Restore both signatures to match main.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 4b38539c-8877-4fdc-8b9d-bc400a50d325
@msyyc
Yuchao Yan (msyyc) added this pull request to the merge queue Aug 13, 2026
Merged via the queue into microsoft:main with commit 476cded Aug 13, 2026
41 of 42 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

emitter:client:python Issue for the Python client emitter: @typespec/http-client-python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants