Skip to content

Commit

Permalink
Merge pull request #928 from sirosen/improve-sphinx-render
Browse files Browse the repository at this point in the history
Improve sphinx documentation rendering to use autodoc type hints for params and not in signatures
  • Loading branch information
sirosen authored Dec 20, 2023
2 parents 9dbb3b5 + c23d160 commit 7c699ab
Show file tree
Hide file tree
Showing 63 changed files with 134 additions and 1,086 deletions.
7 changes: 7 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@
"python": ("https://docs.python.org/3", None),
}

# pull signature docs from type hints, into body
# and keep the signatures concise
autodoc_typehints = "description"
# do not generate doc stubs for inherited parameters from a superclass,
# merely because they are type annotated
autodoc_typehints_description_target = "documented_params"


# sphinx extensions (minimally, we want autodoc and viewcode to build the site)
# plus, we have our own custom extension in the SDK to include
Expand Down
4 changes: 4 additions & 0 deletions docs/core/responses.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,7 @@ To customize client methods with additional detail, the SDK uses subclasses of
.. autoclass:: globus_sdk.response.IterableResponse
:members:
:show-inheritance:

.. autoclass:: globus_sdk.response.ArrayResponse
:members:
:show-inheritance:
20 changes: 20 additions & 0 deletions docs/core/utils.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,23 @@ payload datatypes to provide nicer interfaces for payload construction.
The objects are a type of ``UserDict`` with no special methods.

.. autoclass:: globus_sdk.utils.PayloadWrapper


MissingType and MISSING
-----------------------

The ``MISSING`` sentinel value is used as an alternative to ``None`` in APIs
which accept ``null`` as a valid value. Whenever ``MISSING`` is included in a
request, it will be removed before the request is sent to the service.

As a result, where ``MISSING`` is used as the default for a value, ``None`` can
be used to explicitly pass the value ``null``.

.. class:: globus_sdk.MissingType
:canonical: globus_sdk.utils.MissingType

This is the type of ``MISSING``.

.. py:data:: globus_sdk.MISSING
The ``MISSING`` sentinel value. It is a singleton.
28 changes: 28 additions & 0 deletions src/globus_sdk/_sphinxext.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,13 +310,41 @@ def gen_rst(self):
yield ":ref:`how to make paginated calls <making_paginated_calls>`."


def after_autodoc_signature_replace_MISSING_repr( # pylint: disable=missing-param-doc,missing-type-doc # noqa: E501
app, # pylint: disable=unused-argument
what, # pylint: disable=unused-argument
name, # pylint: disable=unused-argument
obj, # pylint: disable=unused-argument
options, # pylint: disable=unused-argument
signature: str,
return_annotation: str,
):
"""
convert <globus_sdk.MISSING> to MISSING in autodoc signatures
:param signature: the signature after autodoc parsing/rendering
:param return_annotation: the return type annotation, including the leading `->`,
after autodoc parsing/rendering
"""
if signature is not None:
signature = signature.replace("<globus_sdk.MISSING>", "MISSING")
if return_annotation is not None:
return_annotation = return_annotation.replace("<globus_sdk.MISSING>", "MISSING")
return signature, return_annotation


def setup(app):
app.add_directive("automethodlist", AutoMethodList)
app.add_directive("listknownscopes", ListKnownScopes)
app.add_directive("enumeratetestingfixtures", EnumerateTestingFixtures)
app.add_directive("expandtestfixture", ExpandTestingFixture)
app.add_directive("extdoclink", ExternalDocLink)
app.add_directive("paginatedusage", PaginatedUsage)

app.connect(
"autodoc-process-signature", after_autodoc_signature_replace_MISSING_repr
)

return {
"parallel_read_safe": True,
"parallel_write_safe": True,
Expand Down
9 changes: 0 additions & 9 deletions src/globus_sdk/_testing/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ def get_last_request(
Get the last request which was received, or None if there were no requests.
:param requests_mock: A non-default ``RequestsMock`` object to use.
:type requests_mock: responses.RequestsMock
"""
calls = requests_mock.calls if requests_mock is not None else responses.calls
try:
Expand Down Expand Up @@ -74,21 +73,13 @@ def construct_error(
:param error_class: The class of the error to construct. Defaults to
GlobusAPIError.
:type error_class: type[GlobusAPIError]
:param http_status: The HTTP status code to use in the response.
:type http_status: int
:param body: The body of the response. If a dict, will be JSON-encoded.
:type body: bytes | str | dict
:param method: The HTTP method to set on the underlying request.
:type method: str, optional
:param response_headers: The headers of the response.
:type response_headers: dict, optional
:param request_headers: The headers of the request.
:type request_headers: dict, optional
:param response_encoding: The encoding to use for the response body.
:type response_encoding: str, optional
:param url: The URL to set on the underlying request.
:type url: str, optional
"""
raw_response = requests.Response()
raw_response.status_code = http_status
Expand Down
2 changes: 0 additions & 2 deletions src/globus_sdk/_testing/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ def add(
:param requests_mock: The mocked requests object to use. Defaults to the default
provided by the ``responses`` library
:type requests_mock: responses.RequestsMock, optional
"""
return self._add_or_replace("add", requests_mock=requests_mock)

Expand All @@ -133,7 +132,6 @@ def replace(
:param requests_mock: The mocked requests object to use. Defaults to the default
provided by the ``responses`` library
:type requests_mock: responses.RequestsMock, optional
"""
return self._add_or_replace("replace", requests_mock=requests_mock)

Expand Down
9 changes: 0 additions & 9 deletions src/globus_sdk/_testing/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,9 @@ def register_response_set(
The response set may be specified as a dict or a ResponseSet object.
:param set_id: The ID used to retrieve the response set later
:type set_id: any
:param rset: The response set to register
:type rset: dict or ResponseSet
:param metadata: Metadata dict to assign to the response set when it is specified
as a dict. If the response set is an object, this argument is ignored.
:type metadata: dict, optional
"""
if isinstance(rset, dict):
rset = ResponseSet.from_dict(rset, metadata=metadata)
Expand Down Expand Up @@ -66,7 +63,6 @@ def get_response_set(set_id: t.Any) -> ResponseSet:
:param set_id: The ID used to retrieve the response set. Typically a string, but
could be any key used to register a response set.
:type set_id: any
"""
# first priority: check the explicit registry
if set_id in _RESPONSE_SET_REGISTRY:
Expand Down Expand Up @@ -106,10 +102,8 @@ def load_response_set(
:param set_id: The ID used to retrieve the response set. Typically a string, but
could be any key used to register a response set.
:type set_id: any
:param requests_mock: A ``responses`` library mock to use for response mocking,
defaults to the ``responses`` default
:type requests_mock: ``responses.RequestsMock``, optional
"""
if isinstance(set_id, ResponseSet):
return set_id.activate_all(requests_mock=requests_mock)
Expand All @@ -132,13 +126,10 @@ def load_response(
:param set_id: The ID used to retrieve the response set. Typically a string, but
could be any key used to register a response set.
:type set_id: any
:param case: The name of a case within the response set to load, ignoring all other
registered mocks in the response set
:type case: str, optional
:param requests_mock: A ``responses`` library mock to use for response mocking,
defaults to the ``responses`` default
:type requests_mock: ``responses.RequestsMock``, optional
"""
if isinstance(set_id, RegisteredResponse):
return set_id.add(requests_mock=requests_mock)
Expand Down
10 changes: 4 additions & 6 deletions src/globus_sdk/_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
import typing as t
import uuid

from globus_sdk.scopes import MutableScope

if sys.version_info < (3, 8):
from typing_extensions import Protocol
else:
from typing import Protocol

if t.TYPE_CHECKING:
from globus_sdk.scopes import MutableScope

# these types are aliases meant for internal use
IntLike = t.Union[int, str]
Expand All @@ -20,10 +20,8 @@

ScopeCollectionType = t.Union[
str,
"MutableScope",
t.Iterable[str],
t.Iterable["MutableScope"],
t.Iterable[t.Union[str, "MutableScope"]],
MutableScope,
t.Iterable[t.Union[str, MutableScope]],
]


Expand Down
1 change: 0 additions & 1 deletion src/globus_sdk/authorizers/access_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ class AccessTokenAuthorizer(StaticGlobusAuthorizer):
unadorned.
:param access_token: An access token for Globus Auth
:type access_token: str
"""

def __init__(self, access_token: str):
Expand Down
2 changes: 0 additions & 2 deletions src/globus_sdk/authorizers/basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@ class BasicAuthorizer(StaticGlobusAuthorizer):
header.
:param username: Username component for Basic Auth
:type username: str
:param password: Password component for Basic Auth
:type password: str
"""

def __init__(self, username: str, password: str) -> None:
Expand Down
6 changes: 0 additions & 6 deletions src/globus_sdk/authorizers/client_credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,15 @@ class ClientCredentialsAuthorizer(RenewingAuthorizer):
the client itself.
:param confidential_client: client object with a valid id and client secret
:type confidential_client: :class:`ConfidentialAppAuthClient\
<globus_sdk.ConfidentialAppAuthClient>`
:param scopes: A string of space-separated scope names being requested for the
access tokens that will be used for the Authorization header. These scopes must
all be for the same resource server, or else the token response will have
multiple access tokens.
:type scopes: str, MutableScope, or iterable of str or MutableScope
:param access_token: Initial Access Token to use, only used if ``expires_at`` is
also set. Must be requested with the same set of scopes passed to this
authorizer.
:type access_token: str
:param expires_at: Expiration time for the starting ``access_token`` expressed as a
POSIX timestamp (i.e. seconds since the epoch)
:type expires_at: int, optional
:param on_refresh: A callback which is triggered any time this authorizer fetches a
new access_token. The ``on_refresh`` callable is invoked on the
:class:`OAuthTokenResponse <globus_sdk.OAuthTokenResponse>`
Expand All @@ -58,7 +53,6 @@ class ClientCredentialsAuthorizer(RenewingAuthorizer):
This is useful for implementing storage for Access Tokens, as the
``on_refresh`` callback can be used to update the Access Tokens and
their expiration times.
:type on_refresh: callable, optional
"""

def __init__(
Expand Down
5 changes: 0 additions & 5 deletions src/globus_sdk/authorizers/refresh_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,11 @@ class RefreshTokenAuthorizer(RenewingAuthorizer):
will automatically support usage of the ``RefreshTokenAuthorizer``.
:param refresh_token: Refresh Token for Globus Auth
:type refresh_token: str
:param auth_client: ``AuthClient`` capable of using the ``refresh_token``
:type auth_client: :class:`AuthClient <globus_sdk.AuthClient>`
:param access_token: Initial Access Token to use, only used if ``expires_at`` is
also set
:type access_token: str, optional
:param expires_at: Expiration time for the starting ``access_token`` expressed as a
POSIX timestamp (i.e. seconds since the epoch)
:type expires_at: int, optional
:param on_refresh: A callback which is triggered any time this authorizer fetches a
new access_token. The ``on_refresh`` callable is invoked on the
:class:`OAuthTokenResponse <globus_sdk.OAuthTokenResponse>`
Expand All @@ -49,7 +45,6 @@ class RefreshTokenAuthorizer(RenewingAuthorizer):
This is useful for implementing storage for Access Tokens, as the
``on_refresh`` callback can be used to update the Access Tokens and
their expiration times.
:type on_refresh: callable, optional
""" # noqa: E501

def __init__(
Expand Down
3 changes: 0 additions & 3 deletions src/globus_sdk/authorizers/renewing.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,8 @@ class RenewingAuthorizer(GlobusAuthorizer, metaclass=abc.ABCMeta):
:param access_token: Initial Access Token to use, only used if ``expires_at`` is
also set
:type access_token: str, optional
:param expires_at: Expiration time for the starting ``access_token`` expressed as a
POSIX timestamp (i.e. seconds since the epoch)
:type expires_at: int, optional
:param on_refresh: A callback which is triggered any time this authorizer fetches a
new access_token. The ``on_refresh`` callable is invoked on the
:class:`OAuthTokenResponse <globus_sdk.OAuthTokenResponse>`
Expand All @@ -47,7 +45,6 @@ class RenewingAuthorizer(GlobusAuthorizer, metaclass=abc.ABCMeta):
This is useful for implementing storage for Access Tokens, as the
``on_refresh`` callback can be used to update the Access Tokens and
their expiration times.
:type on_refresh: callable, optional
"""

def __init__(
Expand Down
31 changes: 0 additions & 31 deletions src/globus_sdk/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,13 @@ class BaseClient:
Abstract base class for clients with error handling for Globus APIs.
:param authorizer: A ``GlobusAuthorizer`` which will generate Authorization headers
:type authorizer: :class:`GlobusAuthorizer\
<globus_sdk.authorizers.base.GlobusAuthorizer>`
:param app_name: Optional "nice name" for the application. Has no bearing on the
semantics of client actions. It is just passed as part of the User-Agent
string, and may be useful when debugging issues with the Globus Team
:type app_name: str
:param base_url: The URL for the service. Most client types initialize this value
intelligently by default. Set it when inheriting from BaseClient or
communicating through a proxy.
:type base_url: str
:param transport_params: Options to pass to the transport for this client
:type transport_params: dict
All other parameters are for internal use and should be ignored.
"""
Expand Down Expand Up @@ -138,9 +133,6 @@ def get( # pylint: disable=missing-param-doc
Make a GET request to the specified path.
See :py:meth:`~.BaseClient.request` for details on the various parameters.
:return: :class:`GlobusHTTPResponse \
<globus_sdk.response.GlobusHTTPResponse>` object
"""
log.debug(f"GET to {path} with query_params {query_params}")
return self.request("GET", path, query_params=query_params, headers=headers)
Expand All @@ -158,9 +150,6 @@ def post( # pylint: disable=missing-param-doc
Make a POST request to the specified path.
See :py:meth:`~.BaseClient.request` for details on the various parameters.
:return: :class:`GlobusHTTPResponse \
<globus_sdk.response.GlobusHTTPResponse>` object
"""
log.debug(f"POST to {path} with query_params {query_params}")
return self.request(
Expand All @@ -183,9 +172,6 @@ def delete( # pylint: disable=missing-param-doc
Make a DELETE request to the specified path.
See :py:meth:`~.BaseClient.request` for details on the various parameters.
:return: :class:`GlobusHTTPResponse \
<globus_sdk.response.GlobusHTTPResponse>` object
"""
log.debug(f"DELETE to {path} with query_params {query_params}")
return self.request("DELETE", path, query_params=query_params, headers=headers)
Expand All @@ -203,9 +189,6 @@ def put( # pylint: disable=missing-param-doc
Make a PUT request to the specified path.
See :py:meth:`~.BaseClient.request` for details on the various parameters.
:return: :class:`GlobusHTTPResponse \
<globus_sdk.response.GlobusHTTPResponse>` object
"""
log.debug(f"PUT to {path} with query_params {query_params}")
return self.request(
Expand All @@ -230,9 +213,6 @@ def patch( # pylint: disable=missing-param-doc
Make a PATCH request to the specified path.
See :py:meth:`~.BaseClient.request` for details on the various parameters.
:return: :class:`GlobusHTTPResponse \
<globus_sdk.response.GlobusHTTPResponse>` object
"""
log.debug(f"PATCH to {path} with query_params {query_params}")
return self.request(
Expand Down Expand Up @@ -260,29 +240,18 @@ def request(
Send an HTTP request
:param method: HTTP request method, as an all caps string
:type method: str
:param path: Path for the request, with or without leading slash
:type path: str
:param query_params: Parameters to be encoded as a query string
:type query_params: dict, optional
:param headers: HTTP headers to add to the request
:type headers: dict
:param data: Data to send as the request body. May pass through encoding.
:type data: dict or str
:param encoding: A way to encode request data. "json", "form", and "text"
are all valid values. Custom encodings can be used only if they are
registered with the transport. By default, strings get "text" behavior and
all other objects get "json".
:type encoding: str
:param allow_redirects: Follow Location headers on redirect response
automatically. Defaults to ``True``
:type allow_redirects: bool
:param stream: Do not immediately download the response content. Defaults to
``False``
:type stream: bool
:return: :class:`GlobusHTTPResponse \
<globus_sdk.response.GlobusHTTPResponse>` object
:raises GlobusAPIError: a `GlobusAPIError` will be raised if the response to the
request is received and has a status code in the 4xx or 5xx categories
Expand Down
Loading

0 comments on commit 7c699ab

Please # to comment.