Skip to content
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

Feature: Add method docstrings #33

Merged
merged 10 commits into from
Sep 30, 2024
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- All routes now return a stronger typed response than just an `httpx.Response` ([#23](https://github.com/stumpylog/gotenberg-client/pull/23))
- All public methods now include docstrings ([#33](https://github.com/stumpylog/gotenberg-client/pull/33))

### Changed

Expand Down
10 changes: 9 additions & 1 deletion src/gotenberg_client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,15 @@
from gotenberg_client._client import GotenbergClient
from gotenberg_client._errors import BaseClientError
from gotenberg_client._errors import CannotExtractHereError
from gotenberg_client._errors import MaxRetriesExceededError
from gotenberg_client.responses import SingleFileResponse
from gotenberg_client.responses import ZipFileResponse

__all__ = ["GotenbergClient", "SingleFileResponse", "ZipFileResponse", "BaseClientError", "CannotExtractHereError"]
__all__ = [
"GotenbergClient",
"SingleFileResponse",
"ZipFileResponse",
"BaseClientError",
"CannotExtractHereError",
"MaxRetriesExceededError",
]
68 changes: 63 additions & 5 deletions src/gotenberg_client/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
from httpx import Response
from httpx._types import RequestFiles

from gotenberg_client._errors import MaxRetriesExceededError
from gotenberg_client._errors import UnreachableCodeError
from gotenberg_client._types import Self
from gotenberg_client._types import WaitTimeType
from gotenberg_client._utils import guess_mime_type
Expand All @@ -26,10 +28,6 @@
logger = logging.getLogger(__name__)


class UnreachableCodeError(Exception):
pass


class PdfFormatMixin:
"""
https://gotenberg.dev/docs/routes#pdfa-chromium
Expand Down Expand Up @@ -156,7 +154,7 @@ def _base_run_with_retry(

# Don't do the extra waiting, return right away
if current_retry_count >= max_retry_count:
raise
raise MaxRetriesExceededError(response=e.response) from e

except Exception as e: # pragma: no cover
logger.warning(f"Unexpected error: {e}", stacklevel=1)
Expand Down Expand Up @@ -226,6 +224,17 @@ def output_name(self, filename: str) -> Self:

class BaseSingleFileResponseRoute(_BaseRoute):
def run(self) -> SingleFileResponse:
"""
Execute the API request to Gotenberg.

This method sends the configured request to the Gotenberg service and returns the response.

Returns:
SingleFileResponse: An object containing the response from the Gotenberg API

Raises:
httpx.Error: Any errors from httpx will be raised
"""
response = super()._base_run()

return SingleFileResponse(response.status_code, response.headers, response.content)
Expand All @@ -237,6 +246,25 @@ def run_with_retry(
initial_retry_wait: WaitTimeType = 5,
retry_scale: WaitTimeType = 2,
) -> SingleFileResponse:
"""
Execute the API request with a retry mechanism.

This method attempts to run the API request and automatically retries in case of failures.
It uses an exponential backoff strategy for retries.

Args:
max_retry_count (int, optional): The maximum number of retry attempts. Defaults to 5.
initial_retry_wait (WaitTimeType, optional): The initial wait time between retries in seconds.
Defaults to 5. Can be int or float.
retry_scale (WaitTimeType, optional): The scale factor for the exponential backoff.
Defaults to 2. Can be int or float.

Returns:
SingleFileResponse: The response object containing the result of the API call.

Raises:
MaxRetriesExceededError: If the maximum number of retries is exceeded without a successful response.
"""
response = super()._base_run_with_retry(
max_retry_count=max_retry_count,
initial_retry_wait=initial_retry_wait,
Expand All @@ -248,6 +276,17 @@ def run_with_retry(

class BaseZipFileResponseRoute(_BaseRoute):
def run(self) -> ZipFileResponse: # pragma: no cover
"""
Execute the API request to Gotenberg.

This method sends the configured request to the Gotenberg service and returns the response.

Returns:
ZipFileResponse: The zipped response with the files

Raises:
httpx.Error: Any errors from httpx will be raised
"""
response = super()._base_run()

return ZipFileResponse(response.status_code, response.headers, response.content)
Expand All @@ -259,6 +298,25 @@ def run_with_retry(
initial_retry_wait: WaitTimeType = 5,
retry_scale: WaitTimeType = 2,
) -> ZipFileResponse:
"""
Execute the API request with a retry mechanism.

This method attempts to run the API request and automatically retries in case of failures.
It uses an exponential backoff strategy for retries.

Args:
max_retry_count (int, optional): The maximum number of retry attempts. Defaults to 5.
initial_retry_wait (WaitTimeType, optional): The initial wait time between retries in seconds.
Defaults to 5. Can be int or float.
retry_scale (WaitTimeType, optional): The scale factor for the exponential backoff.
Defaults to 2. Can be int or float.

Returns:
ZipFileResponse: The zipped response with the files

Raises:
MaxRetriesExceededError: If the maximum number of retries is exceeded without a successful response.
"""
response = super()._base_run_with_retry(
max_retry_count=max_retry_count,
initial_retry_wait=initial_retry_wait,
Expand Down
71 changes: 64 additions & 7 deletions src/gotenberg_client/_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,18 @@

class GotenbergClient:
"""
The user's primary interface to the Gotenberg instance
The user's primary interface to the Gotenberg instance.

This class provides methods to configure and interact with a Gotenberg service,
including setting up API endpoints for various Gotenberg features and managing
webhook configurations.

Attributes:
chromium (ChromiumApi): Interface for Chromium-related operations.
libre_office (LibreOfficeApi): Interface for LibreOffice-related operations.
pdf_a (PdfAApi): Interface for PDF/A-related operations.
merge (MergeApi): Interface for PDF merging operations.
health (HealthCheckApi): Interface for health check operations.
"""

def __init__(
Expand All @@ -31,6 +42,15 @@ def __init__(
log_level: int = logging.ERROR,
http2: bool = True,
):
"""
Initialize a new GotenbergClient instance.

Args:
host (str): The base URL of the Gotenberg service.
timeout (float, optional): The timeout for API requests in seconds. Defaults to 30.0.
log_level (int, optional): The logging level for httpx and httpcore. Defaults to logging.ERROR.
http2 (bool, optional): Whether to use HTTP/2. Defaults to True.
"""
# Configure the client
self._client = Client(base_url=host, timeout=timeout, http2=http2)

Expand All @@ -47,46 +67,73 @@ def __init__(

def add_headers(self, header: Dict[str, str]) -> None:
"""
Updates the httpx Client headers with the given values
Update the httpx Client headers with the given values.

Args:
header (Dict[str, str]): A dictionary of header names and values to add.
"""
self._client.headers.update(header)

def add_webhook_url(self, url: str) -> None:
"""
Adds the webhook URL to the headers
Add the webhook URL to the headers.

Args:
url (str): The URL to be used as the webhook endpoint.
"""
self.add_headers({"Gotenberg-Webhook-Url": url})

def add_error_webhook_url(self, url: str) -> None:
"""
Adds the webhook error URL to the headers
Add the webhook error URL to the headers.

Args:
url (str): The URL to be used as the error webhook endpoint.
"""
self.add_headers({"Gotenberg-Webhook-Error-Url": url})

def set_webhook_http_method(self, method: HttpMethodsType = "PUT") -> None:
"""
Sets the HTTP method Gotenberg will use to call the hooks
Set the HTTP method Gotenberg will use to call the webhooks.

Args:
method (HttpMethodsType, optional): The HTTP method to use. Defaults to "PUT".
"""
self.add_headers({"Gotenberg-Webhook-Method": method})

def set_error_webhook_http_method(self, method: HttpMethodsType = "PUT") -> None:
"""
Sets the HTTP method Gotenberg will use to call the hooks
Set the HTTP method Gotenberg will use to call the error webhooks.

Args:
method (HttpMethodsType, optional): The HTTP method to use. Defaults to "PUT".
"""
self.add_headers({"Gotenberg-Webhook-Error-Method": method})

def set_webhook_extra_headers(self, extra_headers: Dict[str, str]) -> None:
"""
Sets the HTTP method Gotenberg will use to call the hooks
Set additional HTTP headers for Gotenberg to use when calling webhooks.

Args:
extra_headers (Dict[str, str]): A dictionary of additional headers to include in webhook calls.
"""
from json import dumps

self.add_headers({"Gotenberg-Webhook-Extra-Http-Headers": dumps(extra_headers)})

def __enter__(self) -> Self:
"""
Enter the runtime context related to this object.

Returns:
Self: The instance itself.
"""
return self

def close(self) -> None:
"""
Close the underlying HTTP client connection.
"""
self._client.close()

def __exit__(
Expand All @@ -95,4 +142,14 @@ def __exit__(
exc_val: Optional[BaseException],
exc_tb: Optional[TracebackType],
) -> None:
"""
Exit the runtime context related to this object.

This method ensures that the client connection is closed when exiting a context manager.

Args:
exc_type: The type of the exception that caused the context to be exited, if any.
exc_val: The instance of the exception that caused the context to be exited, if any.
exc_tb: A traceback object encoding the stack trace, if an exception occurred.
"""
self.close()
Loading