Skip to content

Commit 3aaa056

Browse files
authored
feat: add started_before and started_after to run list (#513)
This PR adds new options to `RunCollectionClient.list()`: `started_before` and `started_after`. Same PR in JS: apify/apify-client-js#763
1 parent 4754f61 commit 3aaa056

File tree

3 files changed

+41
-0
lines changed

3 files changed

+41
-0
lines changed

src/apify_client/_http_client.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import logging
66
import os
77
import sys
8+
from datetime import datetime, timezone
89
from http import HTTPStatus
910
from importlib import metadata
1011
from typing import TYPE_CHECKING, Any
@@ -76,6 +77,13 @@ def _parse_params(params: dict | None) -> dict | None:
7677
# Our API needs lists passed as comma-separated strings
7778
elif isinstance(value, list):
7879
parsed_params[key] = ','.join(value)
80+
elif isinstance(value, datetime):
81+
utc_aware_dt = value.astimezone(timezone.utc)
82+
83+
# Convert to ISO 8601 string in Zulu format
84+
zulu_date_str = utc_aware_dt.strftime('%Y-%m-%dT%H:%M:%SZ')
85+
86+
parsed_params[key] = zulu_date_str
7987
elif value is not None:
8088
parsed_params[key] = value
8189

src/apify_client/clients/resource_clients/run_collection.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
from apify_client.clients.base import ResourceCollectionClient, ResourceCollectionClientAsync
77

88
if TYPE_CHECKING:
9+
from datetime import datetime
10+
911
from apify_shared.consts import ActorJobStatus
1012

1113
from apify_client.clients.base.resource_collection_client import ListPage
@@ -25,6 +27,8 @@ def list(
2527
offset: int | None = None,
2628
desc: bool | None = None,
2729
status: ActorJobStatus | list[ActorJobStatus] | None = None,
30+
started_before: str | datetime | None = None,
31+
started_after: str | datetime | None = None,
2832
) -> ListPage[dict]:
2933
"""List all Actor runs.
3034
@@ -39,6 +43,8 @@ def list(
3943
offset: What run to include as first when retrieving the list.
4044
desc: Whether to sort the runs in descending order based on their start date.
4145
status: Retrieve only runs with the provided statuses.
46+
started_before: Only return runs started before this date (inclusive).
47+
started_after: Only return runs started after this date (inclusive).
4248
4349
Returns:
4450
The retrieved Actor runs.
@@ -53,6 +59,8 @@ def list(
5359
offset=offset,
5460
desc=desc,
5561
status=status_param,
62+
startedBefore=started_before,
63+
startedAfter=started_after,
5664
)
5765

5866

@@ -70,6 +78,8 @@ async def list(
7078
offset: int | None = None,
7179
desc: bool | None = None,
7280
status: ActorJobStatus | list[ActorJobStatus] | None = None,
81+
started_before: str | datetime | None = None,
82+
started_after: str | datetime | None = None,
7383
) -> ListPage[dict]:
7484
"""List all Actor runs.
7585
@@ -84,6 +94,8 @@ async def list(
8494
offset: What run to include as first when retrieving the list.
8595
desc: Whether to sort the runs in descending order based on their start date.
8696
status: Retrieve only runs with the provided statuses.
97+
started_before: Only return runs started before this date (inclusive).
98+
started_after: Only return runs started after this date (inclusive).
8799
88100
Returns:
89101
The retrieved Actor runs.
@@ -98,4 +110,6 @@ async def list(
98110
offset=offset,
99111
desc=desc,
100112
status=status_param,
113+
startedBefore=started_before,
114+
startedAfter=started_after,
101115
)

tests/integration/test_run_collection.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import annotations
22

3+
from datetime import datetime, timezone
34
from typing import TYPE_CHECKING
45

56
import pytest
@@ -54,3 +55,21 @@ async def test_run_collection_list_multiple_statuses(self, apify_client: ApifyCl
5455
assert all(run.get('status') == ActorJobStatus.SUCCEEDED for run in single_status_runs.items)
5556

5657
self.teadown_runs(apify_client)
58+
59+
# Here we test that date fields can be passed both as datetime objects and as ISO 8601 strings
60+
async def test_run_collection_list_accept_date_range(self, apify_client: ApifyClient) -> None:
61+
self.setup_runs(apify_client)
62+
63+
run_collection = apify_client.runs()
64+
65+
date_obj = datetime(2100, 1, 1, 0, 0, 0, tzinfo=timezone.utc)
66+
iso_date_str = date_obj.strftime('%Y-%m-%dT%H:%M:%SZ')
67+
68+
# Here we test that date fields can be passed both as datetime objects and as ISO 8601 strings
69+
runs_in_range_date_format = run_collection.list(started_before=date_obj, started_after=date_obj)
70+
runs_in_range_string_format = run_collection.list(started_before=iso_date_str, started_after=iso_date_str)
71+
72+
assert hasattr(runs_in_range_date_format, 'items')
73+
assert hasattr(runs_in_range_string_format, 'items')
74+
75+
self.teadown_runs(apify_client)

0 commit comments

Comments
 (0)