Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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: 2 additions & 2 deletions src/apify_client/_http_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
import httpx
from apify_shared.utils import ignore_docs, is_content_type_json, is_content_type_text, is_content_type_xml

from apify_client._errors import ApifyApiError, InvalidResponseBodyError, is_retryable_error
from apify_client._logging import log_context, logger_name
from apify_client._statistics import Statistics
from apify_client._utils import retry_with_exp_backoff, retry_with_exp_backoff_async
from apify_client._utils import is_retryable_error, retry_with_exp_backoff, retry_with_exp_backoff_async
from apify_client.errors import ApifyApiError, InvalidResponseBodyError

if TYPE_CHECKING:
from collections.abc import Callable
Expand Down
18 changes: 17 additions & 1 deletion src/apify_client/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@
from http import HTTPStatus
from typing import TYPE_CHECKING, Any, TypeVar, cast

import httpx
from apify_shared.utils import is_file_or_bytes, maybe_extract_enum_member_value

from apify_client.errors import InvalidResponseBodyError

if TYPE_CHECKING:
from collections.abc import Awaitable

from apify_client._errors import ApifyApiError
from apify_client.errors import ApifyApiError

PARSE_DATE_FIELDS_MAX_DEPTH = 3
PARSE_DATE_FIELDS_KEY_SUFFIX = 'At'
Expand Down Expand Up @@ -149,3 +152,16 @@ def encode_key_value_store_record_value(value: Any, content_type: str | None = N
value = json.dumps(value, ensure_ascii=False, indent=2, allow_nan=False, default=str).encode('utf-8')

return (value, content_type)


def is_retryable_error(exc: Exception) -> bool:
"""Check if the given error is retryable."""
return isinstance(
exc,
(
InvalidResponseBodyError,
httpx.NetworkError,
httpx.TimeoutException,
httpx.RemoteProtocolError,
),
)
2 changes: 1 addition & 1 deletion src/apify_client/clients/base/actor_job_base_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
from apify_shared.consts import ActorJobStatus
from apify_shared.utils import ignore_docs, parse_date_fields

from apify_client._errors import ApifyApiError
from apify_client._utils import catch_not_found_or_throw, pluck_data
from apify_client.clients.base.resource_client import ResourceClient, ResourceClientAsync
from apify_client.errors import ApifyApiError

DEFAULT_WAIT_FOR_FINISH_SEC = 999999

Expand Down
2 changes: 1 addition & 1 deletion src/apify_client/clients/base/resource_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

from apify_shared.utils import ignore_docs, parse_date_fields

from apify_client._errors import ApifyApiError
from apify_client._utils import catch_not_found_or_throw, pluck_data
from apify_client.clients.base.base_client import BaseClient, BaseClientAsync
from apify_client.errors import ApifyApiError


@ignore_docs
Expand Down
2 changes: 1 addition & 1 deletion src/apify_client/clients/resource_clients/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
from apify_shared.models import ListPage
from apify_shared.utils import filter_out_none_values_recursively, ignore_docs

from apify_client._errors import ApifyApiError
from apify_client._utils import catch_not_found_or_throw, pluck_data
from apify_client.clients.base import ResourceClient, ResourceClientAsync
from apify_client.errors import ApifyApiError

if TYPE_CHECKING:
from collections.abc import AsyncIterator, Iterator
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@

from apify_shared.utils import filter_out_none_values_recursively, ignore_docs, parse_date_fields

from apify_client._errors import ApifyApiError
from apify_client._utils import catch_not_found_or_throw, encode_key_value_store_record_value, pluck_data
from apify_client.clients.base import ResourceClient, ResourceClientAsync
from apify_client.errors import ApifyApiError

if TYPE_CHECKING:
from collections.abc import AsyncIterator, Iterator
Expand Down
2 changes: 1 addition & 1 deletion src/apify_client/clients/resource_clients/log.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@

from apify_shared.utils import ignore_docs

from apify_client._errors import ApifyApiError
from apify_client._utils import catch_not_found_or_throw
from apify_client.clients.base import ResourceClient, ResourceClientAsync
from apify_client.errors import ApifyApiError

if TYPE_CHECKING:
from collections.abc import AsyncIterator, Iterator
Expand Down
2 changes: 1 addition & 1 deletion src/apify_client/clients/resource_clients/request_queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
from apify_shared.utils import filter_out_none_values_recursively, ignore_docs, parse_date_fields
from more_itertools import constrained_batches

from apify_client._errors import ApifyApiError
from apify_client._utils import catch_not_found_or_throw, pluck_data
from apify_client.clients.base import ResourceClient, ResourceClientAsync
from apify_client.errors import ApifyApiError

if TYPE_CHECKING:
from datetime import timedelta
Expand Down
2 changes: 1 addition & 1 deletion src/apify_client/clients/resource_clients/schedule.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

from apify_shared.utils import filter_out_none_values_recursively, ignore_docs

from apify_client._errors import ApifyApiError
from apify_client._utils import catch_not_found_or_throw, pluck_data_as_list
from apify_client.clients.base import ResourceClient, ResourceClientAsync
from apify_client.errors import ApifyApiError


def _get_schedule_representation(
Expand Down
2 changes: 1 addition & 1 deletion src/apify_client/clients/resource_clients/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
parse_date_fields,
)

from apify_client._errors import ApifyApiError
from apify_client._utils import catch_not_found_or_throw, encode_webhook_list_to_base64, pluck_data
from apify_client.clients.base import ResourceClient, ResourceClientAsync
from apify_client.clients.resource_clients.run import RunClient, RunClientAsync
Expand All @@ -18,6 +17,7 @@
WebhookCollectionClient,
WebhookCollectionClientAsync,
)
from apify_client.errors import ApifyApiError

if TYPE_CHECKING:
from apify_shared.consts import ActorJobStatus, MetaOrigin
Expand Down
2 changes: 1 addition & 1 deletion src/apify_client/clients/resource_clients/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

from apify_shared.utils import filter_out_none_values_recursively, ignore_docs, parse_date_fields

from apify_client._errors import ApifyApiError
from apify_client._utils import catch_not_found_or_throw, pluck_data
from apify_client.clients.base import ResourceClient, ResourceClientAsync
from apify_client.errors import ApifyApiError


class UserClient(ResourceClient):
Expand Down
2 changes: 1 addition & 1 deletion src/apify_client/clients/resource_clients/webhook.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
parse_date_fields,
)

from apify_client._errors import ApifyApiError
from apify_client._utils import catch_not_found_or_throw, pluck_data
from apify_client.clients.base import ResourceClient, ResourceClientAsync
from apify_client.clients.resource_clients.webhook_dispatch_collection import (
WebhookDispatchCollectionClient,
WebhookDispatchCollectionClientAsync,
)
from apify_client.errors import ApifyApiError

if TYPE_CHECKING:
from apify_shared.consts import WebhookEventType
Expand Down
19 changes: 5 additions & 14 deletions src/apify_client/_errors.py → src/apify_client/errors.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
from __future__ import annotations

import httpx
from typing import TYPE_CHECKING

from apify_shared.utils import ignore_docs

if TYPE_CHECKING:
import httpx


class ApifyClientError(Exception):
"""Base class for errors specific to the Apify API Client."""
Expand Down Expand Up @@ -72,16 +76,3 @@ def __init__(self, response: httpx.Response) -> None:
self.name = 'InvalidResponseBodyError'
self.code = 'invalid-response-body'
self.response = response


def is_retryable_error(exc: Exception) -> bool:
"""Check if the given error is retryable."""
return isinstance(
exc,
(
InvalidResponseBodyError,
httpx.NetworkError,
httpx.TimeoutException,
httpx.RemoteProtocolError,
),
)
2 changes: 1 addition & 1 deletion tests/unit/test_client_errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
import pytest
from werkzeug import Response

from apify_client._errors import ApifyApiError
from apify_client._http_client import HTTPClient, HTTPClientAsync
from apify_client.errors import ApifyApiError

if TYPE_CHECKING:
from collections.abc import Iterator
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/test_client_request_queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ async def test_batch_not_processed_raises_exception_async(httpserver: HTTPServer
]
rq_client = client.request_queue(request_queue_id='whatever')

with pytest.raises(apify_client._errors.ApifyApiError):
with pytest.raises(apify_client.errors.ApifyApiError):
await rq_client.batch_add_requests(requests=requests)


Expand Down Expand Up @@ -77,7 +77,7 @@ def test_batch_not_processed_raises_exception_sync(httpserver: HTTPServer) -> No
]
rq_client = client.request_queue(request_queue_id='whatever')

with pytest.raises(apify_client._errors.ApifyApiError):
with pytest.raises(apify_client.errors.ApifyApiError):
rq_client.batch_add_requests(requests=requests)


Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading