Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Improve sphinx documentation rendering to use autodoc type hints for params and not in signatures #928

Merged
merged 21 commits into from
Dec 20, 2023

Conversation

sirosen
Copy link
Member

@sirosen sirosen commented Dec 19, 2023

This includes some minor additional fixes but is mostly a long procedural change from using explicit :type: documentation to using autodoc type hints as much as possible.
This reduces a great deal of duplication and visual noise, making signatures significantly more readable in our rendered docs.

In a couple of cases, we need to get slightly "clever" in order for the hints to render well.

One of the more obvious ones of these is customized rendering of globus_sdk.MISSING as the bare string MISSING in signatures.
That makes MISSING usage look highly ergonomic in signatures.

In the case of Groups, there was one case of a class, GroupPolicies, whose docstring did not render correctly under autodoc.
A decorator, local to the module where GroupPolicies is defined, makes a modification to the __doc__ of that class to give sphinx the appropriate values.

In globus_sdk.paging, there was a minor fix as this changeset uncovered a discrepancy between the type annotations and documented type.
The documentation was more correct (splatted args are a tuple, not a list), so changes have been made to align with that.

In AuthClient, there are some unions of Literal[...] with MissingType which sphinx only renders correctly if MissingType is the first member of the union, so for simplicitly these are handled by changing the union order to put MissingType first.
(This looks to be a sphinx bug, which will need a MRE + bug report.)

Under Flows, several methods had constraints (e.g. string length) documented in the type information.
That doesn't fit within the auspices of the Python type system -- there's no definition for constrained types within the language -- so this information was preserved by moving it to the parameter documentation in each case.

In a few cases, :rtype: and :type: have been used to explicitly document overrides which replace the autodoc type hint behavior.


📚 Documentation preview 📚: https://globus-sdk-python--928.org.readthedocs.build/en/928/


Here's a pair of before/after clips of AuthClient. First of some innocuous methods, then of a pathological one.

case before after
simple image image
pathological image image

Note how the return type is now always annotated. Although things might be slightly longer in the simple cases, in the pathological cases they are dramatically improved.

These are needed in order for doc references to these values to work.
Sphinx will default to picking up the repr of an object, which for
MISSING turns into `<globus_sdk.MISSING>`, and makes the signature
lines bulky.

Attach a listener for the autodoc signature event which rewrites any
instance of this to the simple string `MISSING`.
This allows sphinx autodoc typehints to populate the type values.
The only exception is `get_jwk` because it uses type overloads. In
that one case, the explicit type documentation must be retained to
instruct Sphinx on how to document it.
- remove `:type ...:` and `:rtype ...:` documentation
- set `autodoc_typehints_description_target="documented_params"` to
  improve client class initializer documentation
- reorder unions of `MissingType|Literal[...]` in order to avoid a
  sphinx bug which appears to incorrectly render a Literal union in
  which the Literal is the left-hand side
- alter ScopeCollectionType to allow autodoc inspection

Regarding ScopeCollectionType, the basic change is that we now allow
`globus_sdk._types` to import `MutableScope` at runtime and move the
deferred type-checking imports into `globus_sdk.scopes`. As a result,
the runtime-visible value contains the proper `MutableScope` object,
not a string forward reference (which sphinx doesn't know how to
resolve). This slight rearrangement basically makes sphinx work.

Additionally, since we were changing the type, remove two elements of
the union which are redundant. Most likely, this had previously been
written with `list`, which is invariant, and was not correctly fixed
when it was widened to `Iterable`.
- remove `:type:` docs
- move *non typing* information from the `:type:` area to `:param:` as
  appropriate, always as a simple append
- remove all uses of `:type:` docs
- add `ArrayResponse` (which was missing) so that doc linking works
  for rtype and docs are more complete
- in the case of `GroupPolicies`, special handling produces UnionType
  formatted strings, rather than allowing autodoc logic to run

For whatever reason, autodoc does not correctly process a union when
it gets the union type via the signature of `__init__`, and can't
resolve the type alias there in the same way that it does for methods.
To work around this for now, the docstring of the class is updated to
be a non-interpolated format-string, which is then converted at
runtime using `.format()` via a decorator.

This keeps the string definition of these unions local to the place
where they are defined and used.
Also fix a minor error in the class docstring for TransferClient
(missing newline before list).
These are not all publicly documented, but they will use sphinx
autodoc type hints if they are. Document them internally in consistent
style.
Paging classes documented the type of the argument tuple correctly,
but then provided an annotation for it as `list[Any]`.

Fix this by making it properly a tuple (which is what it was always
intended to be).
This constitutes a minor change at runtime from a list which is never
modified to a tuple, but most importantly fixes the incorrect type
annotations.
@sirosen sirosen added the no-news-is-good-news This change does not require a news file label Dec 20, 2023
Copy link
Member

@kurtmckee kurtmckee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work. Very, very nice work!

@sirosen sirosen merged commit 7c699ab into globus:main Dec 20, 2023
14 checks passed
@sirosen sirosen deleted the improve-sphinx-render branch December 20, 2023 14:09
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
no-news-is-good-news This change does not require a news file
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants