diff --git a/docs/04_upgrading/upgrading_to_v3.mdx b/docs/04_upgrading/upgrading_to_v3.mdx
index 65edb441..f1fb1a5a 100644
--- a/docs/04_upgrading/upgrading_to_v3.mdx
+++ b/docs/04_upgrading/upgrading_to_v3.mdx
@@ -249,6 +249,44 @@ except NotFoundError:
Direct `.get()` also now swallows every 404 regardless of the `error.type` string in the response body (previously only `record-not-found` and `record-or-token-not-found` types were swallowed). If your code needs to distinguish between "resource missing" and "404 with an unexpected type", inspect `.type` on a caught `NotFoundError` from a non-`.get()` call path.
+## Keyword-only arguments for secondary parameters
+
+Several methods and utility functions had additional `*` separators inserted into their signatures, so optional/secondary parameters can no longer be passed positionally. The "subject" arguments (e.g. `key` on KVS record methods, `event_name` on `charge()`) remain positional; only the parameters that follow them are affected.
+
+### Affected APIs
+
+`KeyValueStoreClient` / `KeyValueStoreClientAsync`:
+
+- `get_record(key, *, signature=None, timeout='long')`
+- `get_record_as_bytes(key, *, signature=None, timeout='long')`
+- `stream_record(key, *, signature=None, timeout='long')`
+- `set_record(key, value, *, content_type=None, timeout='long')`
+
+`RunClient` / `RunClientAsync`:
+
+- `charge(event_name, *, count=1, idempotency_key=None, timeout='short')`
+- `get_status_message_watcher(*, to_logger=None, check_period=..., timeout='long')`
+
+`ApifyApiError` constructor:
+
+- `ApifyApiError(response, attempt, *, method='GET')`
+
+### Migration
+
+Before (v2):
+
+```python
+client.key_value_store('my-store').set_record('my-key', {'data': 1}, 'application/json')
+client.run('my-run').charge('my-event', 5, 'my-idempotency-key')
+```
+
+After (v3):
+
+```python
+client.key_value_store('my-store').set_record('my-key', {'data': 1}, content_type='application/json')
+client.run('my-run').charge('my-event', count=5, idempotency_key='my-idempotency-key')
+```
+
## Snake_case `sort_by` values on `actors().list()`
The `sort_by` parameter of `ActorCollectionClient.list()` and `ActorCollectionClientAsync.list()` now accepts pythonic snake_case values instead of the raw camelCase values used by the API.
diff --git a/src/apify_client/_http_clients/_base.py b/src/apify_client/_http_clients/_base.py
index 7683fdfb..2abe8ab5 100644
--- a/src/apify_client/_http_clients/_base.py
+++ b/src/apify_client/_http_clients/_base.py
@@ -167,7 +167,7 @@ def _parse_params(params: dict[str, Any] | None) -> dict[str, Any] | None:
return parsed_params
- def _compute_timeout(self, timeout: Timeout, attempt: int) -> int | float | None:
+ def _compute_timeout(self, timeout: Timeout, *, attempt: int) -> int | float | None:
"""Resolve a timeout tier and compute the timeout for a request attempt with exponential increase.
For `no_timeout`, returns `None` to indicate no timeout. For tier literals and explicit `timedelta` values,
@@ -197,6 +197,7 @@ def _compute_timeout(self, timeout: Timeout, attempt: int) -> int | float | None
def _prepare_request_call(
self,
+ *,
headers: dict[str, str] | None = None,
params: dict[str, Any] | None = None,
data: str | bytes | bytearray | None = None,
@@ -221,7 +222,7 @@ def _prepare_request_call(
return (headers, self._parse_params(params), data)
- def _build_url_with_params(self, url: str, params: dict[str, Any] | None = None) -> str:
+ def _build_url_with_params(self, url: str, *, params: dict[str, Any] | None = None) -> str:
"""Build a URL with query parameters appended. List values are expanded into multiple key=value pairs."""
if not params:
return url
diff --git a/src/apify_client/_http_clients/_impit.py b/src/apify_client/_http_clients/_impit.py
index f56e72c2..0701ad5c 100644
--- a/src/apify_client/_http_clients/_impit.py
+++ b/src/apify_client/_http_clients/_impit.py
@@ -142,7 +142,12 @@ def call(
self._statistics.calls += 1
- prepared_headers, prepared_params, content = self._prepare_request_call(headers, params, data, json)
+ prepared_headers, prepared_params, content = self._prepare_request_call(
+ headers=headers,
+ params=params,
+ data=data,
+ json=json,
+ )
return self._retry_with_exp_backoff(
lambda stop_retrying, attempt: self._make_request(
@@ -198,12 +203,12 @@ def _make_request(
self._statistics.requests += 1
try:
- url_with_params = self._build_url_with_params(url, params)
+ url_with_params = self._build_url_with_params(url, params=params)
# Impit treats timeout=None as "use client default (30s)", not "no timeout".
# Use a large value (24 hours) to effectively disable the timeout.
# This can be removed once impit updates its behaviour: https://github.com/apify/impit/issues/401
- computed_timeout = self._compute_timeout(timeout, attempt)
+ computed_timeout = self._compute_timeout(timeout, attempt=attempt)
impit_timeout = 86_400 if computed_timeout is None else computed_timeout
response = self._impit_client.request(
@@ -384,7 +389,12 @@ async def call(
self._statistics.calls += 1
- prepared_headers, prepared_params, content = self._prepare_request_call(headers, params, data, json)
+ prepared_headers, prepared_params, content = self._prepare_request_call(
+ headers=headers,
+ params=params,
+ data=data,
+ json=json,
+ )
return await self._retry_with_exp_backoff(
lambda stop_retrying, attempt: self._make_request(
@@ -440,12 +450,12 @@ async def _make_request(
self._statistics.requests += 1
try:
- url_with_params = self._build_url_with_params(url, params)
+ url_with_params = self._build_url_with_params(url, params=params)
# Impit treats timeout=None as "use client default (30s)", not "no timeout".
# Use a large value (24 hours) to effectively disable the timeout.
# This can be removed once impit updates its behaviour: https://github.com/apify/impit/issues/401
- computed_timeout = self._compute_timeout(timeout, attempt)
+ computed_timeout = self._compute_timeout(timeout, attempt=attempt)
impit_timeout = 86_400 if computed_timeout is None else computed_timeout
response = await self._impit_async_client.request(
diff --git a/src/apify_client/_resource_clients/actor.py b/src/apify_client/_resource_clients/actor.py
index c4463427..cceed900 100644
--- a/src/apify_client/_resource_clients/actor.py
+++ b/src/apify_client/_resource_clients/actor.py
@@ -266,7 +266,7 @@ def start(
Returns:
The run object.
"""
- run_input, content_type = encode_key_value_store_record_value(run_input, content_type)
+ run_input, content_type = encode_key_value_store_record_value(run_input, content_type=content_type)
request_params = self._build_params(
build=build,
@@ -543,7 +543,7 @@ def validate_input(
Returns:
True if the input is valid, else raise an exception with validation error details.
"""
- run_input, content_type = encode_key_value_store_record_value(run_input, content_type)
+ run_input, content_type = encode_key_value_store_record_value(run_input, content_type=content_type)
self._http_client.call(
url=self._build_url('validate-input'),
@@ -762,7 +762,7 @@ async def start(
Returns:
The run object.
"""
- run_input, content_type = encode_key_value_store_record_value(run_input, content_type)
+ run_input, content_type = encode_key_value_store_record_value(run_input, content_type=content_type)
request_params = self._build_params(
build=build,
@@ -1043,7 +1043,7 @@ async def validate_input(
Returns:
True if the input is valid, else raise an exception with validation error details.
"""
- run_input, content_type = encode_key_value_store_record_value(run_input, content_type)
+ run_input, content_type = encode_key_value_store_record_value(run_input, content_type=content_type)
await self._http_client.call(
url=self._build_url('validate-input'),
diff --git a/src/apify_client/_resource_clients/dataset.py b/src/apify_client/_resource_clients/dataset.py
index 1ae7e945..850f32d5 100644
--- a/src/apify_client/_resource_clients/dataset.py
+++ b/src/apify_client/_resource_clients/dataset.py
@@ -714,8 +714,8 @@ def create_items_public_url(
if dataset and dataset.url_signing_secret_key:
signature = create_storage_content_signature(
- resource_id=dataset.id,
- url_signing_secret_key=dataset.url_signing_secret_key,
+ dataset.id,
+ dataset.url_signing_secret_key,
expires_in=expires_in,
)
request_params['signature'] = signature
@@ -1292,8 +1292,8 @@ async def create_items_public_url(
if dataset and dataset.url_signing_secret_key:
signature = create_storage_content_signature(
- resource_id=dataset.id,
- url_signing_secret_key=dataset.url_signing_secret_key,
+ dataset.id,
+ dataset.url_signing_secret_key,
expires_in=expires_in,
)
request_params['signature'] = signature
diff --git a/src/apify_client/_resource_clients/key_value_store.py b/src/apify_client/_resource_clients/key_value_store.py
index 6c388b49..247073c4 100644
--- a/src/apify_client/_resource_clients/key_value_store.py
+++ b/src/apify_client/_resource_clients/key_value_store.py
@@ -231,7 +231,7 @@ def iterate_keys(
exclusive_start_key = current_keys_page.next_exclusive_start_key
- def get_record(self, key: str, signature: str | None = None, *, timeout: Timeout = 'long') -> dict | None:
+ def get_record(self, key: str, *, signature: str | None = None, timeout: Timeout = 'long') -> dict | None:
"""Retrieve the given record from the key-value store.
https://docs.apify.com/api/v2#/reference/key-value-stores/record/get-record
@@ -290,7 +290,7 @@ def record_exists(self, key: str, *, timeout: Timeout = 'long') -> bool:
return response.status_code == HTTPStatus.OK
- def get_record_as_bytes(self, key: str, signature: str | None = None, *, timeout: Timeout = 'long') -> dict | None:
+ def get_record_as_bytes(self, key: str, *, signature: str | None = None, timeout: Timeout = 'long') -> dict | None:
"""Retrieve the given record from the key-value store, without parsing it.
https://docs.apify.com/api/v2#/reference/key-value-stores/record/get-record
@@ -324,7 +324,7 @@ def get_record_as_bytes(self, key: str, signature: str | None = None, *, timeout
@contextmanager
def stream_record(
- self, key: str, signature: str | None = None, *, timeout: Timeout = 'long'
+ self, key: str, *, signature: str | None = None, timeout: Timeout = 'long'
) -> Iterator[dict | None]:
"""Retrieve the given record from the key-value store, as a stream.
@@ -365,8 +365,8 @@ def set_record(
self,
key: str,
value: Any,
- content_type: str | None = None,
*,
+ content_type: str | None = None,
timeout: Timeout = 'long',
) -> None:
"""Set a value to the given record in the key-value store.
@@ -379,7 +379,7 @@ def set_record(
content_type: The content type of the saved value.
timeout: Timeout for the API HTTP request.
"""
- value, content_type = encode_key_value_store_record_value(value, content_type)
+ value, content_type = encode_key_value_store_record_value(value, content_type=content_type)
headers = {'content-type': content_type}
@@ -482,8 +482,8 @@ def create_keys_public_url(
if metadata and metadata.url_signing_secret_key:
signature = create_storage_content_signature(
- resource_id=metadata.id,
- url_signing_secret_key=metadata.url_signing_secret_key,
+ metadata.id,
+ metadata.url_signing_secret_key,
expires_in=expires_in,
)
request_params['signature'] = signature
@@ -662,7 +662,7 @@ async def iterate_keys(
exclusive_start_key = current_keys_page.next_exclusive_start_key
- async def get_record(self, key: str, signature: str | None = None, *, timeout: Timeout = 'long') -> dict | None:
+ async def get_record(self, key: str, *, signature: str | None = None, timeout: Timeout = 'long') -> dict | None:
"""Retrieve the given record from the key-value store.
https://docs.apify.com/api/v2#/reference/key-value-stores/record/get-record
@@ -722,7 +722,7 @@ async def record_exists(self, key: str, *, timeout: Timeout = 'long') -> bool:
return response.status_code == HTTPStatus.OK
async def get_record_as_bytes(
- self, key: str, signature: str | None = None, *, timeout: Timeout = 'long'
+ self, key: str, *, signature: str | None = None, timeout: Timeout = 'long'
) -> dict | None:
"""Retrieve the given record from the key-value store, without parsing it.
@@ -757,7 +757,7 @@ async def get_record_as_bytes(
@asynccontextmanager
async def stream_record(
- self, key: str, signature: str | None = None, *, timeout: Timeout = 'long'
+ self, key: str, *, signature: str | None = None, timeout: Timeout = 'long'
) -> AsyncIterator[dict | None]:
"""Retrieve the given record from the key-value store, as a stream.
@@ -798,8 +798,8 @@ async def set_record(
self,
key: str,
value: Any,
- content_type: str | None = None,
*,
+ content_type: str | None = None,
timeout: Timeout = 'long',
) -> None:
"""Set a value to the given record in the key-value store.
@@ -812,7 +812,7 @@ async def set_record(
content_type: The content type of the saved value.
timeout: Timeout for the API HTTP request.
"""
- value, content_type = encode_key_value_store_record_value(value, content_type)
+ value, content_type = encode_key_value_store_record_value(value, content_type=content_type)
headers = {'content-type': content_type}
@@ -915,8 +915,8 @@ async def create_keys_public_url(
if metadata and metadata.url_signing_secret_key:
signature = create_storage_content_signature(
- resource_id=metadata.id,
- url_signing_secret_key=metadata.url_signing_secret_key,
+ metadata.id,
+ metadata.url_signing_secret_key,
expires_in=expires_in,
)
request_params['signature'] = signature
diff --git a/src/apify_client/_resource_clients/request_queue.py b/src/apify_client/_resource_clients/request_queue.py
index 90aa746d..cd00a1cd 100644
--- a/src/apify_client/_resource_clients/request_queue.py
+++ b/src/apify_client/_resource_clients/request_queue.py
@@ -876,6 +876,7 @@ async def delete_request_lock(
async def _batch_add_requests_worker(
self,
+ *,
queue: asyncio.Queue[Iterable[dict]],
request_params: dict,
timeout: Timeout,
@@ -992,7 +993,9 @@ async def batch_add_requests(
async with asyncio.TaskGroup() as tg:
workers = [
tg.create_task(
- self._batch_add_requests_worker(asyncio_queue, request_params, timeout),
+ self._batch_add_requests_worker(
+ queue=asyncio_queue, request_params=request_params, timeout=timeout
+ ),
name=f'batch_add_requests_worker_{i}',
)
for i in range(max_parallel)
diff --git a/src/apify_client/_resource_clients/run.py b/src/apify_client/_resource_clients/run.py
index ca7f4e06..0789dd43 100644
--- a/src/apify_client/_resource_clients/run.py
+++ b/src/apify_client/_resource_clients/run.py
@@ -185,7 +185,7 @@ def metamorph(
Returns:
The Actor run data.
"""
- run_input, content_type = encode_key_value_store_record_value(run_input, content_type)
+ run_input, content_type = encode_key_value_store_record_value(run_input, content_type=content_type)
safe_target_actor_id = to_safe_id(target_actor_id)
@@ -375,6 +375,7 @@ def get_streamed_log(
def charge(
self,
event_name: str,
+ *,
count: int = 1,
idempotency_key: str | None = None,
timeout: Timeout = 'short',
@@ -419,9 +420,9 @@ def charge(
def get_status_message_watcher(
self,
+ *,
to_logger: logging.Logger | None = None,
check_period: timedelta = timedelta(seconds=1),
- *,
timeout: Timeout = 'long',
) -> StatusMessageWatcher:
"""Get `StatusMessageWatcher` instance that can be used to redirect status and status messages to logs.
@@ -608,7 +609,7 @@ async def metamorph(
Returns:
The Actor run data.
"""
- run_input, content_type = encode_key_value_store_record_value(run_input, content_type)
+ run_input, content_type = encode_key_value_store_record_value(run_input, content_type=content_type)
safe_target_actor_id = to_safe_id(target_actor_id)
@@ -801,6 +802,7 @@ async def get_streamed_log(
async def charge(
self,
event_name: str,
+ *,
count: int = 1,
idempotency_key: str | None = None,
timeout: Timeout = 'short',
@@ -845,9 +847,9 @@ async def charge(
async def get_status_message_watcher(
self,
+ *,
to_logger: logging.Logger | None = None,
check_period: timedelta = timedelta(seconds=1),
- *,
timeout: Timeout = 'long',
) -> StatusMessageWatcherAsync:
"""Get `StatusMessageWatcher` instance that can be used to redirect status and status messages to logs.
diff --git a/src/apify_client/_utils.py b/src/apify_client/_utils.py
index d65ec93d..27210ba2 100644
--- a/src/apify_client/_utils.py
+++ b/src/apify_client/_utils.py
@@ -78,7 +78,7 @@ def catch_not_found_for_resource_or_throw(exc: ApifyApiError, resource_id: str |
catch_not_found_or_throw(exc)
-def encode_key_value_store_record_value(value: Any, content_type: str | None = None) -> tuple[Any, str]:
+def encode_key_value_store_record_value(value: Any, *, content_type: str | None = None) -> tuple[Any, str]:
"""Encode a value for storage in a key-value store record.
Args:
@@ -227,6 +227,7 @@ def create_hmac_signature(secret_key: str, message: str) -> str:
def create_storage_content_signature(
resource_id: str,
url_signing_secret_key: str,
+ *,
expires_in: timedelta | None = None,
version: int = 0,
) -> str:
diff --git a/src/apify_client/errors.py b/src/apify_client/errors.py
index b67ad4e3..84c5423d 100644
--- a/src/apify_client/errors.py
+++ b/src/apify_client/errors.py
@@ -36,10 +36,10 @@ class ApifyApiError(ApifyClientError):
data: Additional error data from the API response.
"""
- # Subclasses in `_STATUS_TO_CLASS` must keep the `(response, attempt, method='GET')` constructor signature —
+ # Subclasses in `_STATUS_TO_CLASS` must keep the `(response, attempt, *, method='GET')` constructor signature —
# `__new__` forwards those arguments verbatim.
- def __new__(cls, response: HttpResponse, attempt: int, method: str = 'GET') -> Self: # noqa: ARG004
+ def __new__(cls, response: HttpResponse, attempt: int, *, method: str = 'GET') -> Self: # noqa: ARG004
"""Dispatch to the subclass matching the response's HTTP status code, if any."""
target_cls: type[ApifyApiError] = cls
if cls is ApifyApiError:
@@ -51,7 +51,7 @@ def __new__(cls, response: HttpResponse, attempt: int, method: str = 'GET') -> S
target_cls = mapped
return super().__new__(target_cls)
- def __init__(self, response: HttpResponse, attempt: int, method: str = 'GET') -> None:
+ def __init__(self, response: HttpResponse, attempt: int, *, method: str = 'GET') -> None:
"""Initialize the API error from a failed response.
Args:
diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py
index dfa8386d..f6bd2053 100644
--- a/tests/integration/conftest.py
+++ b/tests/integration/conftest.py
@@ -61,8 +61,8 @@ def test_dataset_of_another_user(api_token_2: str) -> Generator[DatasetFixture]:
# Generate signature for authenticated access
assert dataset.url_signing_secret_key is not None
signature = create_storage_content_signature(
- resource_id=dataset.id,
- url_signing_secret_key=dataset.url_signing_secret_key,
+ dataset.id,
+ dataset.url_signing_secret_key,
)
yield DatasetFixture(
@@ -90,8 +90,8 @@ def test_kvs_of_another_user(api_token_2: str) -> Generator[KvsFixture]:
# Generate signatures for authenticated access
signature = create_storage_content_signature(
- resource_id=kvs.id,
- url_signing_secret_key=kvs.url_signing_secret_key or '',
+ kvs.id,
+ kvs.url_signing_secret_key or '',
)
yield KvsFixture(
diff --git a/tests/integration/test_key_value_store.py b/tests/integration/test_key_value_store.py
index 952fc0cf..ecc9d709 100644
--- a/tests/integration/test_key_value_store.py
+++ b/tests/integration/test_key_value_store.py
@@ -143,10 +143,10 @@ async def test_get_record_signature(
match=r"Insufficient permissions for the key-value store. Make sure you're passing a correct"
r' API token and that it has the required permissions.',
):
- await maybe_await(kvs.get_record(key=key))
+ await maybe_await(kvs.get_record(key))
# Kvs content retrieved with correct signature
- result = await maybe_await(kvs.get_record(key=key, signature=test_kvs_of_another_user.keys_signature[key]))
+ result = await maybe_await(kvs.get_record(key, signature=test_kvs_of_another_user.keys_signature[key]))
record = cast('dict', result)
assert record
assert test_kvs_of_another_user.expected_content[key] == record['value']
@@ -164,10 +164,10 @@ async def test_get_record_as_bytes_signature(
match=r"Insufficient permissions for the key-value store. Make sure you're passing a correct"
r' API token and that it has the required permissions.',
):
- await maybe_await(kvs.get_record_as_bytes(key=key))
+ await maybe_await(kvs.get_record_as_bytes(key))
# Kvs content retrieved with correct signature
- result = await maybe_await(kvs.get_record_as_bytes(key=key, signature=test_kvs_of_another_user.keys_signature[key]))
+ result = await maybe_await(kvs.get_record_as_bytes(key, signature=test_kvs_of_another_user.keys_signature[key]))
item = cast('dict', result)
assert item
assert test_kvs_of_another_user.expected_content[key] == json.loads(item['value'].decode('utf-8'))
@@ -188,16 +188,16 @@ async def test_stream_record_signature(
# We'll test the error condition separately based on client type
if is_async:
with pytest.raises(ApifyApiError):
- async with kvs.stream_record(key=key) as stream: # ty: ignore[invalid-context-manager]
+ async with kvs.stream_record(key) as stream: # ty: ignore[invalid-context-manager]
pass
else:
- with pytest.raises(ApifyApiError), kvs.stream_record(key=key) as stream: # ty: ignore[invalid-context-manager]
+ with pytest.raises(ApifyApiError), kvs.stream_record(key) as stream: # ty: ignore[invalid-context-manager]
pass
# Kvs content retrieved with correct signature
if is_async:
async with kvs.stream_record(
- key=key,
+ key,
signature=test_kvs_of_another_user.keys_signature[key],
) as stream: # ty: ignore[invalid-context-manager]
assert stream
@@ -205,7 +205,7 @@ async def test_stream_record_signature(
value = json.loads(stream_dict['value'].content.decode('utf-8'))
else:
with kvs.stream_record(
- key=key,
+ key,
signature=test_kvs_of_another_user.keys_signature[key],
) as stream: # ty: ignore[invalid-context-manager]
assert stream
diff --git a/tests/integration/test_run.py b/tests/integration/test_run.py
index 3416fe85..8c79e566 100644
--- a/tests/integration/test_run.py
+++ b/tests/integration/test_run.py
@@ -405,7 +405,7 @@ async def test_run_charge(client: ApifyClient | ApifyClientAsync) -> None:
try:
# Try to charge - this will fail for non-PPE actors but tests the API call
try:
- await maybe_await(run_client.charge(event_name='test-event', count=1))
+ await maybe_await(run_client.charge('test-event', count=1))
# If it succeeds, the actor supports PPE
except ApifyApiError as exc:
# Expected error for non-PPE actors - re-raise if unexpected.
diff --git a/tests/unit/test_client_timeouts.py b/tests/unit/test_client_timeouts.py
index 534a06ca..7c961f50 100644
--- a/tests/unit/test_client_timeouts.py
+++ b/tests/unit/test_client_timeouts.py
@@ -128,25 +128,25 @@ def test_compute_timeout_with_timedelta() -> None:
"""Test _compute_timeout with a concrete timedelta doubles per attempt, capped at max."""
client = ImpitHttpClient(timeout_max=timedelta(seconds=600))
- assert client._compute_timeout(timedelta(seconds=5), 1) == 5.0
- assert client._compute_timeout(timedelta(seconds=5), 2) == 10.0
- assert client._compute_timeout(timedelta(seconds=5), 3) == 20.0
- assert client._compute_timeout(timedelta(seconds=5), 4) == 40.0
+ assert client._compute_timeout(timedelta(seconds=5), attempt=1) == 5.0
+ assert client._compute_timeout(timedelta(seconds=5), attempt=2) == 10.0
+ assert client._compute_timeout(timedelta(seconds=5), attempt=3) == 20.0
+ assert client._compute_timeout(timedelta(seconds=5), attempt=4) == 40.0
def test_compute_timeout_caps_at_max() -> None:
"""Test _compute_timeout caps at timeout_max."""
client = ImpitHttpClient(timeout_max=timedelta(seconds=10))
- assert client._compute_timeout(timedelta(seconds=5), 1) == 5.0
- assert client._compute_timeout(timedelta(seconds=5), 2) == 10.0
- assert client._compute_timeout(timedelta(seconds=5), 3) == 10.0 # capped
+ assert client._compute_timeout(timedelta(seconds=5), attempt=1) == 5.0
+ assert client._compute_timeout(timedelta(seconds=5), attempt=2) == 10.0
+ assert client._compute_timeout(timedelta(seconds=5), attempt=3) == 10.0 # capped
def test_compute_timeout_no_timeout_returns_none() -> None:
"""Test _compute_timeout with 'no_timeout' returns None."""
client = ImpitHttpClient()
- assert client._compute_timeout('no_timeout', 1) is None
+ assert client._compute_timeout('no_timeout', attempt=1) is None
async def test_dynamic_timeout_async_client(monkeypatch: pytest.MonkeyPatch) -> None:
diff --git a/tests/unit/test_http_clients.py b/tests/unit/test_http_clients.py
index b18fb762..50d9f54c 100644
--- a/tests/unit/test_http_clients.py
+++ b/tests/unit/test_http_clients.py
@@ -425,7 +425,7 @@ def test_build_url_with_params_simple() -> None:
"""Test _build_url_with_params with simple params."""
client = _ConcreteHttpClient()
- url = client._build_url_with_params('https://api.test.com/endpoint', {'key': 'value', 'limit': 10})
+ url = client._build_url_with_params('https://api.test.com/endpoint', params={'key': 'value', 'limit': 10})
assert 'key=value' in url
assert 'limit=10' in url
assert url.startswith('https://api.test.com/endpoint?')
@@ -435,7 +435,7 @@ def test_build_url_with_params_list() -> None:
"""Test _build_url_with_params with list values."""
client = _ConcreteHttpClient()
- url = client._build_url_with_params('https://api.test.com/endpoint', {'tags': ['tag1', 'tag2', 'tag3']})
+ url = client._build_url_with_params('https://api.test.com/endpoint', params={'tags': ['tag1', 'tag2', 'tag3']})
assert 'tags=tag1' in url
assert 'tags=tag2' in url
assert 'tags=tag3' in url
@@ -446,7 +446,7 @@ def test_build_url_with_params_mixed() -> None:
client = _ConcreteHttpClient()
url = client._build_url_with_params(
- 'https://api.test.com/endpoint', {'limit': 10, 'tags': ['a', 'b'], 'name': 'test'}
+ 'https://api.test.com/endpoint', params={'limit': 10, 'tags': ['a', 'b'], 'name': 'test'}
)
assert 'limit=10' in url
assert 'tags=a' in url
diff --git a/tests/unit/test_pluggable_http_client.py b/tests/unit/test_pluggable_http_client.py
index 04711f85..e601e3c5 100644
--- a/tests/unit/test_pluggable_http_client.py
+++ b/tests/unit/test_pluggable_http_client.py
@@ -334,7 +334,7 @@ def call(self, *, method: str, **_kwargs: Any) -> FakeResponse:
text='{"error": {"message": "Actor not found", "type": "record-not-found"}}',
_json={'error': {'message': 'Actor not found', 'type': 'record-not-found'}},
)
- raise ApifyApiError(error_response, attempt=1, method=method)
+ raise ApifyApiError(error_response, 1, method=method)
def test_custom_http_client_error_handling() -> None:
@@ -356,7 +356,7 @@ async def call(self, *, method: str, **_kwargs: Any) -> FakeResponse:
text='{"error": {"message": "Actor not found", "type": "record-not-found"}}',
_json={'error': {'message': 'Actor not found', 'type': 'record-not-found'}},
)
- raise ApifyApiError(error_response, attempt=1, method=method)
+ raise ApifyApiError(error_response, 1, method=method)
async def test_custom_http_client_async_error_handling() -> None:
diff --git a/tests/unit/test_run_charge.py b/tests/unit/test_run_charge.py
index 9fd8ea3f..6b030651 100644
--- a/tests/unit/test_run_charge.py
+++ b/tests/unit/test_run_charge.py
@@ -43,7 +43,7 @@ def capture_request(request: Request) -> Response:
api_url = httpserver.url_for('/').removesuffix('/')
client = ApifyClient(token='test_token', api_url=api_url)
- client.run(_MOCKED_RUN_ID).charge(event_name='test-event', count=count)
+ client.run(_MOCKED_RUN_ID).charge('test-event', count=count)
assert len(captured_requests) == 1
body = _decode_body(captured_requests[0])
@@ -70,7 +70,7 @@ def capture_request(request: Request) -> Response:
api_url = httpserver.url_for('/').removesuffix('/')
client = ApifyClientAsync(token='test_token', api_url=api_url)
- await client.run(_MOCKED_RUN_ID).charge(event_name='test-event', count=count)
+ await client.run(_MOCKED_RUN_ID).charge('test-event', count=count)
assert len(captured_requests) == 1
body = _decode_body(captured_requests[0])
diff --git a/tests/unit/test_url_generation.py b/tests/unit/test_url_generation.py
index 0f142678..a1a2aec6 100644
--- a/tests/unit/test_url_generation.py
+++ b/tests/unit/test_url_generation.py
@@ -144,9 +144,7 @@ def test_kvs_public_url_sync(api_url: str, api_public_url: str | None, signing_k
public_url = kvs.create_keys_public_url()
if signing_key:
- signature_value = create_storage_content_signature(
- resource_id=MOCKED_KVS_ID, url_signing_secret_key=signing_key
- )
+ signature_value = create_storage_content_signature(MOCKED_KVS_ID, signing_key)
expected_signature = f'?signature={signature_value}'
else:
expected_signature = ''
@@ -172,10 +170,7 @@ async def test_kvs_public_url_async(api_url: str, api_public_url: str | None, si
public_url = await kvs.create_keys_public_url()
if signing_key:
- signature_value = create_storage_content_signature(
- resource_id=MOCKED_KVS_ID,
- url_signing_secret_key=signing_key,
- )
+ signature_value = create_storage_content_signature(MOCKED_KVS_ID, signing_key)
expected_signature = f'?signature={signature_value}'
else:
expected_signature = ''
diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py
index ecb41699..4b7d5c30 100644
--- a/tests/unit/test_utils.py
+++ b/tests/unit/test_utils.py
@@ -188,7 +188,7 @@ def test_encode_key_value_store_record_value(
) -> None:
"""Test encoding of key-value store record values."""
if input_content_type is not None:
- value, content_type = encode_key_value_store_record_value(input_value, input_content_type)
+ value, content_type = encode_key_value_store_record_value(input_value, content_type=input_content_type)
else:
value, content_type = encode_key_value_store_record_value(input_value)
assert value == expected_value