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
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ ruff = "~0.8.0"
setuptools = "~75.6.0" # setuptools are used by pytest but not explicitly required

[tool.ruff]
line-length = 150
line-length = 120

[tool.ruff.lint]
select = ["ALL"]
Expand Down
4 changes: 3 additions & 1 deletion scripts/check_async_docstrings.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@
print(f'Missing docstring for "{async_class.name}.{async_method.name}"!')
found_issues = True
elif expected_docstring != async_docstring:
print(f'Docstring for "{async_class.name}.{async_method.name}" is out of sync with "{sync_class.name}.{sync_method.name}"!')
print(
f'Docstring for "{async_class.name}.{async_method.name}" is out of sync with "{sync_class.name}.{sync_method.name}"!' # noqa: E501
)
found_issues = True

if found_issues:
Expand Down
3 changes: 2 additions & 1 deletion scripts/fix_async_docstrings.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@
if async_docstring == correct_async_docstring:
continue

# Work around a bug in Red Baron, which indents docstrings too much when you insert them, so we have to un-indent it one level first
# Work around a bug in Red Baron, which indents docstrings too much when you insert them,
# so we have to un-indent it one level first.
correct_async_docstring = re.sub('^ ', '', correct_async_docstring, flags=re.MULTILINE)

if not isinstance(async_docstring, str):
Expand Down
23 changes: 11 additions & 12 deletions src/apify_client/_errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,18 @@ class ApifyClientError(Exception):
class ApifyApiError(ApifyClientError):
"""Error specific to requests to the Apify API.

An `ApifyApiError` is thrown for successful HTTP requests that reach the API,
but the API responds with an error response. Typically, those are rate limit
errors and internal errors, which are automatically retried, or validation
errors, which are thrown immediately, because a correction by the user is needed.
An `ApifyApiError` is thrown for successful HTTP requests that reach the API, but the API responds with
an error response. Typically, those are rate limit errors and internal errors, which are automatically retried,
or validation errors, which are thrown immediately, because a correction by the user is needed.
"""

@ignore_docs
def __init__(self, response: httpx.Response, attempt: int) -> None:
"""Create the ApifyApiError instance.
"""A default constructor.

Args:
response (httpx.Response): The response to the failed API call
attempt (int): Which attempt was the request that failed
response: The response to the failed API call.
attempt: Which attempt was the request that failed.
"""
self.message: str | None = None
self.type: str | None = None
Expand Down Expand Up @@ -53,17 +52,17 @@ def __init__(self, response: httpx.Response, attempt: int) -> None:
class InvalidResponseBodyError(ApifyClientError):
"""Error caused by the response body failing to be parsed.

This error exists for the quite common situation, where only a partial JSON response is received and
an attempt to parse the JSON throws an error. In most cases this can be resolved by retrying the
request. We do that by identifying this error in the HTTPClient.
This error exists for the quite common situation, where only a partial JSON response is received and an attempt
to parse the JSON throws an error. In most cases this can be resolved by retrying the request. We do that by
identifying this error in the HTTPClient.
"""

@ignore_docs
def __init__(self, response: httpx.Response) -> None:
"""Create the InvalidResponseBodyError instance.
"""A default constructor.

Args:
response: The response which failed to be parsed
response: The response which failed to be parsed.
"""
super().__init__('Response body could not be parsed')

Expand Down
8 changes: 6 additions & 2 deletions src/apify_client/_http_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,9 @@ def _make_request(stop_retrying: Callable, attempt: int) -> httpx.Response:
if response.status_code < 300: # noqa: PLR2004
logger.debug('Request successful', extra={'status_code': response.status_code})
if not stream:
_maybe_parsed_body = self._maybe_parse_response(response) if parse_response else response.content
_maybe_parsed_body = (
self._maybe_parse_response(response) if parse_response else response.content
)
setattr(response, '_maybe_parsed_body', _maybe_parsed_body) # noqa: B010

return response
Expand Down Expand Up @@ -242,7 +244,9 @@ async def _make_request(stop_retrying: Callable, attempt: int) -> httpx.Response
if response.status_code < 300: # noqa: PLR2004
logger.debug('Request successful', extra={'status_code': response.status_code})
if not stream:
_maybe_parsed_body = self._maybe_parse_response(response) if parse_response else response.content
_maybe_parsed_body = (
self._maybe_parse_response(response) if parse_response else response.content
)
setattr(response, '_maybe_parsed_body', _maybe_parsed_body) # noqa: B010

return response
Expand Down
94 changes: 47 additions & 47 deletions src/apify_client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,15 @@ def __init__(
min_delay_between_retries_millis: int | None = 500,
timeout_secs: int | None = 360,
) -> None:
"""Initialize the Apify API Client.
"""A default constructor.

Args:
token (str, optional): The Apify API token
api_url (str, optional): The URL of the Apify API server to which to connect to. Defaults to https://api.apify.com
max_retries (int, optional): How many times to retry a failed request at most
min_delay_between_retries_millis (int, optional): How long will the client wait between retrying requests
(increases exponentially from this value)
timeout_secs (int, optional): The socket timeout of the HTTP requests sent to the Apify API
token: The Apify API token.
api_url: The URL of the Apify API server to which to connect to. Defaults to https://api.apify.com.
max_retries: How many times to retry a failed request at most.
min_delay_between_retries_millis: How long will the client wait between retrying requests
(increases exponentially from this value).
timeout_secs: The socket timeout of the HTTP requests sent to the Apify API.
"""
self.token = token
api_url = (api_url or DEFAULT_API_URL).rstrip('/')
Expand Down Expand Up @@ -108,15 +108,15 @@ def __init__(
min_delay_between_retries_millis: int | None = 500,
timeout_secs: int | None = 360,
) -> None:
"""Initialize the ApifyClient.
"""A default constructor.

Args:
token (str, optional): The Apify API token
api_url (str, optional): The URL of the Apify API server to which to connect to. Defaults to https://api.apify.com
max_retries (int, optional): How many times to retry a failed request at most
min_delay_between_retries_millis (int, optional): How long will the client wait between retrying requests
(increases exponentially from this value)
timeout_secs (int, optional): The socket timeout of the HTTP requests sent to the Apify API
token: The Apify API token.
api_url: The URL of the Apify API server to which to connect to. Defaults to https://api.apify.com.
max_retries: How many times to retry a failed request at most.
min_delay_between_retries_millis: How long will the client wait between retrying requests
(increases exponentially from this value).
timeout_secs: The socket timeout of the HTTP requests sent to the Apify API.
"""
super().__init__(
token,
Expand All @@ -137,7 +137,7 @@ def actor(self, actor_id: str) -> ActorClient:
"""Retrieve the sub-client for manipulating a single Actor.

Args:
actor_id (str): ID of the Actor to be manipulated
actor_id: ID of the Actor to be manipulated.
"""
return ActorClient(resource_id=actor_id, **self._options())

Expand All @@ -149,7 +149,7 @@ def build(self, build_id: str) -> BuildClient:
"""Retrieve the sub-client for manipulating a single Actor build.

Args:
build_id (str): ID of the Actor build to be manipulated
build_id: ID of the Actor build to be manipulated.
"""
return BuildClient(resource_id=build_id, **self._options())

Expand All @@ -161,7 +161,7 @@ def run(self, run_id: str) -> RunClient:
"""Retrieve the sub-client for manipulating a single Actor run.

Args:
run_id (str): ID of the Actor run to be manipulated
run_id: ID of the Actor run to be manipulated.
"""
return RunClient(resource_id=run_id, **self._options())

Expand All @@ -173,7 +173,7 @@ def dataset(self, dataset_id: str) -> DatasetClient:
"""Retrieve the sub-client for manipulating a single dataset.

Args:
dataset_id (str): ID of the dataset to be manipulated
dataset_id: ID of the dataset to be manipulated.
"""
return DatasetClient(resource_id=dataset_id, **self._options())

Expand All @@ -185,7 +185,7 @@ def key_value_store(self, key_value_store_id: str) -> KeyValueStoreClient:
"""Retrieve the sub-client for manipulating a single key-value store.

Args:
key_value_store_id (str): ID of the key-value store to be manipulated
key_value_store_id: ID of the key-value store to be manipulated.
"""
return KeyValueStoreClient(resource_id=key_value_store_id, **self._options())

Expand All @@ -197,8 +197,8 @@ def request_queue(self, request_queue_id: str, *, client_key: str | None = None)
"""Retrieve the sub-client for manipulating a single request queue.

Args:
request_queue_id (str): ID of the request queue to be manipulated
client_key (str): A unique identifier of the client accessing the request queue
request_queue_id: ID of the request queue to be manipulated.
client_key: A unique identifier of the client accessing the request queue.
"""
return RequestQueueClient(resource_id=request_queue_id, client_key=client_key, **self._options())

Expand All @@ -210,7 +210,7 @@ def webhook(self, webhook_id: str) -> WebhookClient:
"""Retrieve the sub-client for manipulating a single webhook.

Args:
webhook_id (str): ID of the webhook to be manipulated
webhook_id: ID of the webhook to be manipulated.
"""
return WebhookClient(resource_id=webhook_id, **self._options())

Expand All @@ -222,7 +222,7 @@ def webhook_dispatch(self, webhook_dispatch_id: str) -> WebhookDispatchClient:
"""Retrieve the sub-client for accessing a single webhook dispatch.

Args:
webhook_dispatch_id (str): ID of the webhook dispatch to access
webhook_dispatch_id: ID of the webhook dispatch to access.
"""
return WebhookDispatchClient(resource_id=webhook_dispatch_id, **self._options())

Expand All @@ -234,7 +234,7 @@ def schedule(self, schedule_id: str) -> ScheduleClient:
"""Retrieve the sub-client for manipulating a single schedule.

Args:
schedule_id (str): ID of the schedule to be manipulated
schedule_id: ID of the schedule to be manipulated.
"""
return ScheduleClient(resource_id=schedule_id, **self._options())

Expand All @@ -246,15 +246,15 @@ def log(self, build_or_run_id: str) -> LogClient:
"""Retrieve the sub-client for retrieving logs.

Args:
build_or_run_id (str): ID of the Actor build or run for which to access the log
build_or_run_id: ID of the Actor build or run for which to access the log.
"""
return LogClient(resource_id=build_or_run_id, **self._options())

def task(self, task_id: str) -> TaskClient:
"""Retrieve the sub-client for manipulating a single task.

Args:
task_id (str): ID of the task to be manipulated
task_id: ID of the task to be manipulated.
"""
return TaskClient(resource_id=task_id, **self._options())

Expand All @@ -266,7 +266,7 @@ def user(self, user_id: str | None = None) -> UserClient:
"""Retrieve the sub-client for querying users.

Args:
user_id (str, optional): ID of user to be queried. If None, queries the user belonging to the token supplied to the client
user_id: ID of user to be queried. If None, queries the user belonging to the token supplied to the client.
"""
return UserClient(resource_id=user_id, **self._options())

Expand All @@ -289,15 +289,15 @@ def __init__(
min_delay_between_retries_millis: int | None = 500,
timeout_secs: int | None = 360,
) -> None:
"""Initialize the ApifyClientAsync.
"""A default constructor.

Args:
token (str, optional): The Apify API token
api_url (str, optional): The URL of the Apify API server to which to connect to. Defaults to https://api.apify.com
max_retries (int, optional): How many times to retry a failed request at most
min_delay_between_retries_millis (int, optional): How long will the client wait between retrying requests
(increases exponentially from this value)
timeout_secs (int, optional): The socket timeout of the HTTP requests sent to the Apify API
token: The Apify API token.
api_url: The URL of the Apify API server to which to connect to. Defaults to https://api.apify.com.
max_retries: How many times to retry a failed request at most.
min_delay_between_retries_millis: How long will the client wait between retrying requests
(increases exponentially from this value).
timeout_secs: The socket timeout of the HTTP requests sent to the Apify API.
"""
super().__init__(
token,
Expand All @@ -318,7 +318,7 @@ def actor(self, actor_id: str) -> ActorClientAsync:
"""Retrieve the sub-client for manipulating a single Actor.

Args:
actor_id (str): ID of the Actor to be manipulated
actor_id: ID of the Actor to be manipulated.
"""
return ActorClientAsync(resource_id=actor_id, **self._options())

Expand All @@ -330,7 +330,7 @@ def build(self, build_id: str) -> BuildClientAsync:
"""Retrieve the sub-client for manipulating a single Actor build.

Args:
build_id (str): ID of the Actor build to be manipulated
build_id: ID of the Actor build to be manipulated.
"""
return BuildClientAsync(resource_id=build_id, **self._options())

Expand All @@ -342,7 +342,7 @@ def run(self, run_id: str) -> RunClientAsync:
"""Retrieve the sub-client for manipulating a single Actor run.

Args:
run_id (str): ID of the Actor run to be manipulated
run_id: ID of the Actor run to be manipulated.
"""
return RunClientAsync(resource_id=run_id, **self._options())

Expand All @@ -354,7 +354,7 @@ def dataset(self, dataset_id: str) -> DatasetClientAsync:
"""Retrieve the sub-client for manipulating a single dataset.

Args:
dataset_id (str): ID of the dataset to be manipulated
dataset_id: ID of the dataset to be manipulated.
"""
return DatasetClientAsync(resource_id=dataset_id, **self._options())

Expand All @@ -366,7 +366,7 @@ def key_value_store(self, key_value_store_id: str) -> KeyValueStoreClientAsync:
"""Retrieve the sub-client for manipulating a single key-value store.

Args:
key_value_store_id (str): ID of the key-value store to be manipulated
key_value_store_id: ID of the key-value store to be manipulated.
"""
return KeyValueStoreClientAsync(resource_id=key_value_store_id, **self._options())

Expand All @@ -378,8 +378,8 @@ def request_queue(self, request_queue_id: str, *, client_key: str | None = None)
"""Retrieve the sub-client for manipulating a single request queue.

Args:
request_queue_id (str): ID of the request queue to be manipulated
client_key (str): A unique identifier of the client accessing the request queue
request_queue_id: ID of the request queue to be manipulated.
client_key: A unique identifier of the client accessing the request queue.
"""
return RequestQueueClientAsync(resource_id=request_queue_id, client_key=client_key, **self._options())

Expand All @@ -391,7 +391,7 @@ def webhook(self, webhook_id: str) -> WebhookClientAsync:
"""Retrieve the sub-client for manipulating a single webhook.

Args:
webhook_id (str): ID of the webhook to be manipulated
webhook_id: ID of the webhook to be manipulated.
"""
return WebhookClientAsync(resource_id=webhook_id, **self._options())

Expand All @@ -403,7 +403,7 @@ def webhook_dispatch(self, webhook_dispatch_id: str) -> WebhookDispatchClientAsy
"""Retrieve the sub-client for accessing a single webhook dispatch.

Args:
webhook_dispatch_id (str): ID of the webhook dispatch to access
webhook_dispatch_id: ID of the webhook dispatch to access.
"""
return WebhookDispatchClientAsync(resource_id=webhook_dispatch_id, **self._options())

Expand All @@ -415,7 +415,7 @@ def schedule(self, schedule_id: str) -> ScheduleClientAsync:
"""Retrieve the sub-client for manipulating a single schedule.

Args:
schedule_id (str): ID of the schedule to be manipulated
schedule_id: ID of the schedule to be manipulated.
"""
return ScheduleClientAsync(resource_id=schedule_id, **self._options())

Expand All @@ -427,15 +427,15 @@ def log(self, build_or_run_id: str) -> LogClientAsync:
"""Retrieve the sub-client for retrieving logs.

Args:
build_or_run_id (str): ID of the Actor build or run for which to access the log
build_or_run_id: ID of the Actor build or run for which to access the log.
"""
return LogClientAsync(resource_id=build_or_run_id, **self._options())

def task(self, task_id: str) -> TaskClientAsync:
"""Retrieve the sub-client for manipulating a single task.

Args:
task_id (str): ID of the task to be manipulated
task_id: ID of the task to be manipulated.
"""
return TaskClientAsync(resource_id=task_id, **self._options())

Expand All @@ -447,7 +447,7 @@ def user(self, user_id: str | None = None) -> UserClientAsync:
"""Retrieve the sub-client for querying users.

Args:
user_id (str, optional): ID of user to be queried. If None, queries the user belonging to the token supplied to the client
user_id: ID of user to be queried. If None, queries the user belonging to the token supplied to the client.
"""
return UserClientAsync(resource_id=user_id, **self._options())

Expand Down
Loading
Loading