-
-
Notifications
You must be signed in to change notification settings - Fork 107
Use format_annotation to render class attribute type annotations #299
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Resolves issue tox-dev#298. This is a bit hard to do because autodoc doesn't emit any events to help us adjust the type rendering for attributes and because the type annotation is currently converted to text and then rendered from text by the `PyAttribute` directive. The system in autodoc for attribute rendering is: 1. In `AttributeDocumenter.get_directive_header`, call `stringify_annotation` to render the annotation to a string 2. add `:type: stringified annotation` to the directive header of `PyAttribute` 3. When `sphinx.domains.python.PyAttribute` sees the `:type:` it calls `format_annotation` which attempts to convert the string representation of the type into a more fancy representation with cross referencing Notes: 2. we don't get an opportunity to adjust the directive header with `autodoc-process-docstring` or some other event 3. there isn't enough information retained in the string for `_inject_types_to_docstring` to work. So my approach is: 1. Patch `AttributeDocumenter.get_directive_header` to use `format_annotation` instead of `stringify_annotation`. Add a prefix to the output to indicate that it is rst not a plain text type annotation. 3. Patch `PyAttribute` so that when it sees the prefix, it formats the output as rst rather than trying to handle it as a plain text type annotation. This is a bit horrible. As future proofing, we check that the patch targets exist and bail if they don't exist. If they move this patch should gracefully decay into a no-op rather than crashing.
# We want to patch: | ||
# * sphinx.ext.autodoc.stringify_typehint (in sphinx < 6.1) | ||
# * sphinx.ext.autodoc.stringify_annotation (in sphinx >= 6.1) | ||
STRINGIFY_PATCH_TARGET = "" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could use none just need to annotation it str | None
, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That makes a type error when I try to use it unless I add an extra assert. Empty string is falsey and this makes the type checker happy without adding the assert.
Resolves #298.
This is a bit hard to do because autodoc doesn't emit any events to help us adjust the type rendering for attributes and because the type annotation is currently converted to text and then rendered from text by the
PyAttribute
directive.The system in autodoc for attribute rendering is:
AttributeDocumenter.get_directive_header
, callstringify_annotation
to render the annotation to a string:type: stringified annotation
to the directive header ofPyAttribute
sphinx.domains.python.PyAttribute
sees the:type:
it callsformat_annotation
which attempts to convert the string representation of the type into a more fancy representation with cross referencingNotes:
2. we don't get an opportunity to adjust the directive header with
autodoc-process-docstring
or some other event3. there isn't enough information retained in the string for
_inject_types_to_docstring
to work.So my approach is:
AttributeDocumenter.get_directive_header
to useformat_annotation
instead ofstringify_annotation
. Add a prefix to the output to indicate that it is rst not a plain text type annotation.PyAttribute
so that when it sees the prefix, it formats the output as rst rather than trying to handle it as a plain text type annotation.As future proofing, we check that the patch targets exist and bail if they don't exist. If they move this patch should gracefully decay into a no-op rather than crashing.