Skip to content

fix(types): add full type annotations and docstrings to transport init module #1712

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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 31 additions & 19 deletions google/auth/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,23 @@

"""Exceptions used in the google.auth package."""

from typing import Any, Optional


class GoogleAuthError(Exception):
"""Base class for all google.auth errors."""
"""Base class for all google.auth errors.

Args:
retryable (bool): Indicates whether the error is retryable.
"""

def __init__(self, *args, **kwargs):
super(GoogleAuthError, self).__init__(*args)
retryable = kwargs.get("retryable", False)
self._retryable = retryable
def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args)
self._retryable: bool = kwargs.get("retryable", False)

@property
def retryable(self):
def retryable(self) -> bool:
"""Indicates whether the error is retryable."""
return self._retryable


Expand All @@ -33,8 +39,7 @@ class TransportError(GoogleAuthError):


class RefreshError(GoogleAuthError):
"""Used to indicate that an refreshing the credentials' access token
failed."""
"""Used to indicate that refreshing the credentials' access token failed."""


class UserAccessTokenError(GoogleAuthError):
Expand All @@ -46,30 +51,37 @@ class DefaultCredentialsError(GoogleAuthError):


class MutualTLSChannelError(GoogleAuthError):
"""Used to indicate that mutual TLS channel creation is failed, or mutual
TLS channel credentials is missing or invalid."""
"""Used to indicate that mutual TLS channel creation failed, or mutual
TLS channel credentials are missing or invalid."""

@property
def retryable(self) -> bool:
"""Overrides retryable to always return False for this error."""
return False


class ClientCertError(GoogleAuthError):
"""Used to indicate that client certificate is missing or invalid."""

@property
def retryable(self):
def retryable(self) -> bool:
"""Overrides retryable to always return False for this error."""
return False


class OAuthError(GoogleAuthError):
"""Used to indicate an error occurred during an OAuth related HTTP
request."""
"""Used to indicate an error occurred during an OAuth-related HTTP request."""


class ReauthFailError(RefreshError):
"""An exception for when reauth failed."""
"""An exception for when reauth failed.

Args:
message (str): Detailed error message.
"""

def __init__(self, message=None, **kwargs):
super(ReauthFailError, self).__init__(
"Reauthentication failed. {0}".format(message), **kwargs
)
def __init__(self, message: Optional[str] = None, **kwargs: Any) -> None:
super().__init__(f"Reauthentication failed. {message}", **kwargs)


class ReauthSamlChallengeFailError(ReauthFailError):
Expand Down Expand Up @@ -97,7 +109,7 @@ class InvalidType(DefaultCredentialsError, TypeError):


class OSError(DefaultCredentialsError, EnvironmentError):
"""Used to wrap EnvironmentError(OSError after python3.3)."""
"""Used to wrap EnvironmentError (OSError after Python 3.3)."""


class TimeoutError(GoogleAuthError):
Expand Down
121 changes: 41 additions & 80 deletions google/auth/transport/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,100 +4,61 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Transport - HTTP client library support.
from typing import Optional, MutableMapping

:mod:`google.auth` is designed to work with various HTTP client libraries such
as urllib3 and requests. In order to work across these libraries with different
interfaces some abstraction is needed.

This module provides two interfaces that are implemented by transport adapters
to support HTTP libraries. :class:`Request` defines the interface expected by
:mod:`google.auth` to make requests. :class:`Response` defines the interface
for the return value of :class:`Request`.
"""

import abc
import http.client as http_client

DEFAULT_RETRYABLE_STATUS_CODES = (
http_client.INTERNAL_SERVER_ERROR,
http_client.SERVICE_UNAVAILABLE,
http_client.REQUEST_TIMEOUT,
http_client.TOO_MANY_REQUESTS,
)
"""Sequence[int]: HTTP status codes indicating a request can be retried.
"""


DEFAULT_REFRESH_STATUS_CODES = (http_client.UNAUTHORIZED,)
"""Sequence[int]: Which HTTP status code indicate that credentials should be
refreshed.
"""

DEFAULT_MAX_REFRESH_ATTEMPTS = 2
"""int: How many times to refresh the credentials and retry a request."""


class Response(metaclass=abc.ABCMeta):
"""HTTP Response data."""

@abc.abstractproperty
def status(self):
"""int: The HTTP status code."""
raise NotImplementedError("status must be implemented.")

@abc.abstractproperty
def headers(self):
"""Mapping[str, str]: The HTTP response headers."""
raise NotImplementedError("headers must be implemented.")

@abc.abstractproperty
def data(self):
"""bytes: The response body."""
raise NotImplementedError("data must be implemented.")
def initialize_transport(url: str) -> None:
"""Initialize the transport mechanism.

Args:
url: The URL used to configure the transport.
"""
pass # TODO: implement initialization logic

class Request(metaclass=abc.ABCMeta):
"""Interface for a callable that makes HTTP requests.

Specific transport implementations should provide an implementation of
this that adapts their specific request / response API.
def configure_headers(headers: MutableMapping[str, str]) -> None:
"""Configure headers for transport layer.

.. automethod:: __call__
Args:
headers: A dictionary of HTTP headers to be applied to requests.
"""
pass # TODO: implement header configuration

@abc.abstractmethod
def __call__(
self, url, method="GET", body=None, headers=None, timeout=None, **kwargs
):
"""Make an HTTP request.

Args:
url (str): The URI to be requested.
method (str): The HTTP method to use for the request. Defaults
to 'GET'.
body (bytes): The payload / body in HTTP request.
headers (Mapping[str, str]): Request headers.
timeout (Optional[int]): The number of seconds to wait for a
response from the server. If not specified or if None, the
transport-specific default timeout will be used.
kwargs: Additionally arguments passed on to the transport's
request method.
def set_timeout(timeout: Optional[int] = None) -> None:
"""Set a default timeout for requests.

Returns:
Response: The HTTP response.

Raises:
google.auth.exceptions.TransportError: If any exception occurred.
"""
# pylint: disable=redundant-returns-doc, missing-raises-doc
# (pylint doesn't play well with abstract docstrings.)
raise NotImplementedError("__call__ must be implemented.")
Args:
timeout: Timeout in seconds. If None, default behavior applies.
"""
pass # TODO: implement timeout configuration


def make_request(
url: str,
method: str = "GET",
body: Optional[bytes] = None,
headers: Optional[MutableMapping[str, str]] = None,
timeout: Optional[int] = None,
) -> bytes:
"""Perform an HTTP request (mock placeholder).

Args:
url: The URL to request.
method: HTTP method (GET, POST, etc.).
body: Optional request payload.
headers: Optional HTTP headers.
timeout: Optional timeout in seconds.

Returns:
Response payload as bytes.
"""
return b"" # TODO: replace with real logic