Skip to content
Merged
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
4 changes: 1 addition & 3 deletions examples/backend-requests/backend-requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@
def _map_error(e: Exception):
"""Return a standardized error response.

Args:
e: The exception that occurred
demo: The demo/endpoint name for this error
:arg e: The exception that occurred
"""
return {
"error": repr(e),
Expand Down
24 changes: 12 additions & 12 deletions fastly_compute/config_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ def __init__(self, store: wit_config_store.Store):
def open(cls, name: str) -> Self:
"""Open a config store by name.

:param name: The name of the config store
:arg name: The name of the config store
:return: ConfigStore instance
:raises ~fastly_compute.exceptions.types.open_error.NotFound: If the config store doesn't exist
:raises ~fastly_compute.exceptions.types.open_error.InvalidSyntax: If the name is invalid
:raises ~fastly_compute.exceptions.types.open_error.NameTooLong: If the name is too long
:raise ~fastly_compute.exceptions.types.open_error.NotFound: If the config store doesn't exist
:raise ~fastly_compute.exceptions.types.open_error.InvalidSyntax: If the name is invalid
:raise ~fastly_compute.exceptions.types.open_error.NameTooLong: If the name is too long

Example::

Expand All @@ -57,10 +57,10 @@ def open(cls, name: str) -> Self:
def get(self, key: str, default: str | None = None) -> str | None:
"""Get a configuration value.

:param key: The configuration key
:param default: Default value if key not found
:arg key: The configuration key
:arg default: Default value if key not found
:return: Configuration value or default if not found
:raises ~fastly_compute.exceptions.types.error.InvalidArgument: If the key is invalid
:raise ~fastly_compute.exceptions.types.error.InvalidArgument: If the key is invalid

Example::

Expand All @@ -76,10 +76,10 @@ def get(self, key: str, default: str | None = None) -> str | None:
def __contains__(self, key: str) -> bool:
"""Check if a key exists in the config store.

:param key: The configuration key
:arg key: The configuration key
:return: True if the key exists, False otherwise
:raises ~fastly_compute.exceptions.types.error.InvalidArgument: If the key is invalid
:raises KeyError: If the key is not a str
:raise ~fastly_compute.exceptions.types.error.InvalidArgument: If the key is invalid
:raise KeyError: If the key is not a str

Example::

Expand All @@ -98,8 +98,8 @@ def close(self) -> None:
manager. If not called explicitly, resources will eventually be freed
by the garbage collector.

Note: Attempting to use the config store after it is closed will result
in a trap.
.. note:: Attempting to use the config store after it is closed will result
in a trap.
"""
self._store.__exit__(None, None, None)

Expand Down
22 changes: 11 additions & 11 deletions fastly_compute/log.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,11 @@ def open(cls, name: str) -> Self:
- It must not contain newlines (\n) or colons (:).
- It must not be `stdout` or `stderr`, which are reserved for debugging.

:param name: The name of the logging endpoint
:arg name: The name of the logging endpoint
:return: LogEndpoint instance
:raises ~fastly_compute.exceptions.types.open_error.NotFound: If the endpoint doesn't exist or can't be created.
:raises ~fastly_compute.exceptions.types.open_error.NameTooLong: If the name is too long.
:raises ~fastly_compute.exceptions.types.open_error.InvalidSyntax: If the name is invalid.
:raise ~fastly_compute.exceptions.types.open_error.NotFound: If the endpoint doesn't exist or can't be created.
:raise ~fastly_compute.exceptions.types.open_error.NameTooLong: If the name is too long.
:raise ~fastly_compute.exceptions.types.open_error.InvalidSyntax: If the name is invalid.

Example::

Expand All @@ -78,7 +78,7 @@ def write(self, msg: bytes | str) -> None:

Each call to write() with a non-empty message produces a single log event.

:param msg: The message to write (bytes or string). Strings are UTF-8 encoded.
:arg msg: The message to write (bytes or string). Strings are UTF-8 encoded.

Example::

Expand Down Expand Up @@ -169,11 +169,11 @@ def __init__(
):
"""Initialize the handler.

:param default_endpoint: The default endpoint name (used when no mapper provided)
:param endpoint_mapper: Optional callable that maps logger name to endpoint name.
:arg default_endpoint: The default endpoint name (used when no mapper provided)
:arg endpoint_mapper: Optional callable that maps logger name to endpoint name.
Signature: (logger_name: str) -> endpoint_name: str
:param level: Minimum logging level to handle (default: NOTSET)
:raises ValueError: If neither default_endpoint nor endpoint_mapper is provided
:arg level: Minimum logging level to handle (default: NOTSET)
:raise ValueError: If neither default_endpoint nor endpoint_mapper is provided

Example::

Expand Down Expand Up @@ -205,7 +205,7 @@ def __init__(
def _get_endpoint(self, logger_name: str) -> LogEndpoint:
"""Get or create an endpoint for the given logger name.

:param logger_name: Name of the logger
:arg logger_name: Name of the logger
:return: LogEndpoint instance
"""
# Determine which endpoint to use
Expand Down Expand Up @@ -242,7 +242,7 @@ def emit(self, record: logging.LogRecord):
The endpoint is determined by calling endpoint_mapper with the
logger name, or using the default_endpoint.

:param record: The log record to emit
:arg record: The log record to emit
"""
try:
endpoint = self._get_endpoint(record.name)
Expand Down
84 changes: 38 additions & 46 deletions fastly_compute/requests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,27 +100,23 @@ def get(
) -> FastlyResponse:
"""Send a GET request.

Args:
url: URL for the request. Can be a path (for static backends) or full URL (for dynamic)
params: Query parameters to append to the URL
headers: HTTP headers to send with the request
fastly_backend: Static backend name (optional, will use dynamic backend if not provided)
timeout: Request timeout in seconds (requests-compatible). Can be:
- float: Single timeout for all phases
- (connect, read): Tuple for connect and read timeouts
fastly_timeout: **Fastly-only** Advanced timeout configuration with granular control
over connect_timeout, first_byte_timeout, and between_bytes_timeout
**kwargs: Additional arguments (for requests compatibility, ignored)

Note:
The fastly_timeout parameter is Fastly-specific and will cause a TypeError
if used with the standard requests library. Use timeout for cross-platform compatibility.

Raises:
RequestException: For general request errors
ConnectionError: For connection-related errors
Timeout: For timeout errors
ValueError: If both timeout and fastly_timeout are specified
:arg url: URL for the request. Can be a path (for static backends) or full URL (for dynamic)
:arg params: Query parameters to append to the URL
:arg headers: HTTP headers to send with the request
:arg fastly_backend: Static backend name (optional, will use dynamic backend if not provided)
:arg timeout: Request timeout in seconds (requests-compatible). Can be:
- ``float``: Single timeout for all phases
- ``(connect, read)``: Tuple for connect and read timeouts
:arg fastly_timeout: **Fastly-only** Advanced timeout configuration with granular control
over connect_timeout, first_byte_timeout, and between_bytes_timeout

.. note:: The fastly_timeout parameter is Fastly-specific and will cause a TypeError
if used with the standard requests library. Use ``timeout`` for cross-platform compatibility.
:arg kwargs: Additional arguments (for requests compatibility, ignored)
:raise RequestException: For general request errors
:raise ConnectionError: For connection-related errors
:raise Timeout: For timeout errors
:raise ValueError: If both timeout and fastly_timeout are specified
"""
return request("GET", url, **kwargs)

Expand All @@ -131,16 +127,15 @@ def post(
) -> FastlyResponse:
"""Send a POST request.

Args:
url: URL for the request
data: Form data to send in the body
json: JSON data to send in the body (mutually exclusive with data)
params: Query parameters to append to the URL
headers: HTTP headers to send with the request
fastly_backend: Static backend name (optional)
timeout: Request timeout in seconds (requests-compatible)
fastly_timeout: **Fastly-only** Advanced timeout configuration
**kwargs: Additional arguments (for requests compatibility, ignored)
:arg url: URL for the request
:arg data: Form data to send in the body
:arg json: JSON data to send in the body (mutually exclusive with data)
:arg params: Query parameters to append to the URL
:arg headers: HTTP headers to send with the request
:arg fastly_backend: Static backend name (optional)
:arg timeout: Request timeout in seconds (requests-compatible)
:arg fastly_timeout: **Fastly-only** Advanced timeout configuration
:arg kwargs: Additional arguments (for requests compatibility, ignored)
"""
return request("POST", url, **kwargs)

Expand Down Expand Up @@ -193,21 +188,18 @@ def request(
) -> FastlyResponse:
"""Send an HTTP request.

Args:
method: HTTP method (GET, POST, PUT, DELETE, etc.)
url: URL for the request
params: Query parameters
data: Form data for the request body
json: JSON data for the request body (mutually exclusive with data)
headers: HTTP headers
fastly_backend: Static backend name (if not provided, will use dynamic backend)
timeout: Request timeout in seconds (requests-compatible)
fastly_timeout: **Fastly-only** Advanced timeout configuration
**kwargs: Additional arguments (for requests compatibility, ignored)

Raises:
RequestException: For general request errors
ValueError: For invalid arguments
:arg method: HTTP method (GET, POST, PUT, DELETE, etc.)
:arg url: URL for the request
:arg params: Query parameters
:arg data: Form data for the request body
:arg json: JSON data for the request body (mutually exclusive with data)
:arg headers: HTTP headers
:arg fastly_backend: Static backend name (if not provided, will use dynamic backend)
:arg timeout: Request timeout in seconds (requests-compatible)
:arg fastly_timeout: **Fastly-only** Advanced timeout configuration
:arg kwargs: Additional arguments (for requests compatibility, ignored)
:raise RequestException: For general request errors
:raise ValueError: For invalid arguments
"""
# Validate arguments
if data is not None and json is not None:
Expand Down
17 changes: 6 additions & 11 deletions fastly_compute/requests/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,12 @@ def resolve_backend(
Static backends must already be configured in the Fastly service.
Dynamic backends are automatically registered on first use and cached for reuse.

Args:
url: The URL to request (must be full with scheme and netloc for dynamic backends)
fastly_backend: Optional static backend name
timeout_config: Optional timeout configuration for dynamic backends

Returns:
ResolutionResult containing backend and updated parsed url

Raises:
RequestException: If backend resolution fails
MissingSchema: If URL is missing scheme (subclass of RequestException)
:arg url: The URL to request (must be full with scheme and netloc for dynamic backends)
:arg fastly_backend: Optional static backend name
:arg timeout_config: Optional timeout configuration for dynamic backends
:return: ResolutionResult containing backend and updated parsed url
:raise RequestException: If backend resolution fails
:raise MissingSchema: If URL is missing scheme (subclass of RequestException)
"""
parsed = urllib.parse.urlparse(url)
backend_obj: wit_backend.Backend
Expand Down
38 changes: 14 additions & 24 deletions fastly_compute/requests/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,11 @@ def _map_error_to_exception(
) -> RequestException:
"""Map WIT error to appropriate RequestException subclass.

Args:
error: The WIT error object to map
mapping: Mapping from error types to exception classes
operation: Description of operation that failed
fallback_cls: Exception class to use if no mapping found

Returns:
Appropriate RequestException subclass instance
:arg error: The WIT error object to map
:arg mapping: Mapping from error types to exception classes
:arg operation: Description of operation that failed
:arg fallback_cls: Exception class to use if no mapping found
:return: Appropriate RequestException subclass instance
"""
error_type = type(error)
exc_cls = mapping.get(error_type, fallback_cls)
Expand All @@ -58,10 +55,9 @@ def __init__(
) -> None:
"""Initialize RequestException.

Args:
message: Error message
response: Optional response object that caused the error
request: Optional request object that caused the error
:arg message: Error message
:arg response: Optional response object that caused the error
:arg request: Optional request object that caused the error
"""
super().__init__(message)
self.response: FastlyResponse | None = response
Expand All @@ -73,12 +69,9 @@ def from_detailed_error(
) -> RequestException:
"""Create a ``requests`` exception from an ErrorWithDetail.

Args:
err: The error to map from
operation: Description of what operation failed

Returns:
Appropriate RequestException subclass instance
:arg err: The error to map from
:arg operation: Description of what operation failed
:return: Appropriate RequestException subclass instance
"""
error_with_detail = err.args[0]

Expand All @@ -104,12 +97,9 @@ def from_detailed_error(
def from_fastly_error(cls, err: FastlyError, operation: str) -> RequestException:
"""Create a ``requests`` exception from a FastlyError or subclass.

Args:
err: The error to map from
operation: Description of what operation failed

Returns:
Appropriate RequestException subclass instance
:arg err: The error to map from
:arg operation: Description of what operation failed
:return: Appropriate RequestException subclass instance
"""
return _map_error_to_exception(
err,
Expand Down
21 changes: 7 additions & 14 deletions fastly_compute/requests/response.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,9 @@ def __init__(
):
"""Initialize FastlyResponse.

Args:
wit_response: The WIT response object
response_body: The WIT response body
url: The final URL that was requested
:arg wit_response: The WIT response object
:arg response_body: The WIT response body
:arg url: The final URL that was requested
"""
self._wit_response: http_resp.Response = wit_response
self._response_body: async_io.Pollable = response_body
Expand Down Expand Up @@ -109,14 +108,9 @@ def text(self) -> str:
def json(self, **kwargs: Any) -> Any:
"""Parse response body as JSON.

Args:
**kwargs: Additional arguments passed to json.loads()

Returns:
Parsed JSON data

Raises:
json.JSONDecodeError: If response is not valid JSON
:arg kwargs: Additional arguments passed to json.loads()
:return: Parsed JSON data
:raise json.JSONDecodeError: If response is not valid JSON
"""
if self._json_data is None:
self._json_data = json.loads(self.text, **kwargs)
Expand All @@ -140,8 +134,7 @@ def is_permanent_redirect(self) -> bool:
def raise_for_status(self) -> None:
"""Raise an HTTPError for bad responses.

Raises:
HTTPError: If response status indicates an error
:raise HTTPError: If response status indicates an error
"""
if not self.ok:
raise HTTPError(
Expand Down
24 changes: 9 additions & 15 deletions fastly_compute/requests/timeout.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,9 @@ def __init__(
):
"""Initialize timeout configuration.

Args:
connect: Connection timeout in seconds (default: 30.0)
first_byte: First byte timeout in seconds (default: 60.0)
between_bytes: Between bytes timeout in seconds (default: 10.0)
:arg connect: Connection timeout in seconds (default: 30.0)
:arg first_byte: First byte timeout in seconds (default: 60.0)
:arg between_bytes: Between bytes timeout in seconds (default: 10.0)
"""
self.connect: float = connect
self.first_byte: float = first_byte
Expand All @@ -55,17 +54,12 @@ def between_bytes_ms(self) -> int:
def from_requests_timeout(cls, timeout: None | float | tuple[float, float]) -> Self:
"""Create TimeoutConfig from requests-compatible timeout parameter.

Args:
timeout: Timeout specification in requests-compatible formats:
- None: Use default timeouts
- float: Single timeout applied to all phases
- (connect, read): Tuple with separate connect and read timeouts

Returns:
TimeoutConfig object with appropriate timeout values

Raises:
ValueError: If timeout format is invalid
:arg timeout: Timeout specification in requests-compatible formats:
- ``None``: Use default timeouts
- ``float``: Single timeout applied to all phases
- ``(connect, read)``: Tuple with separate connect and read timeouts
:return: TimeoutConfig object with appropriate timeout values
:raise ValueError: If timeout format is invalid
"""
if timeout is None:
return cls()
Expand Down
Loading
Loading