diff --git a/.github/workflows/check_docs.yaml b/.github/workflows/check_docs.yaml index 0a9d2ef5..d7464ff8 100644 --- a/.github/workflows/check_docs.yaml +++ b/.github/workflows/check_docs.yaml @@ -10,7 +10,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 diff --git a/.github/workflows/integration_tests.yaml b/.github/workflows/integration_tests.yaml index 446f2c7f..847346b7 100644 --- a/.github/workflows/integration_tests.yaml +++ b/.github/workflows/integration_tests.yaml @@ -21,7 +21,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 diff --git a/.github/workflows/lint_and_type_checks.yaml b/.github/workflows/lint_and_type_checks.yaml index 26b6aed9..c2cc2e1f 100644 --- a/.github/workflows/lint_and_type_checks.yaml +++ b/.github/workflows/lint_and_type_checks.yaml @@ -13,7 +13,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 719af4b2..ebaa1351 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -54,7 +54,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 diff --git a/.github/workflows/unit_tests.yaml b/.github/workflows/unit_tests.yaml index fa7be76f..016b5242 100644 --- a/.github/workflows/unit_tests.yaml +++ b/.github/workflows/unit_tests.yaml @@ -14,7 +14,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 diff --git a/CHANGELOG.md b/CHANGELOG.md index 65cfb963..f5226551 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ Changelog ### Added +- Add StoreCollectionClient for listing Actors in Apify store - support for specifying the `max_items` parameter for pay-per result Actors and their runs ### Internal changes diff --git a/docs/docs.md b/docs/docs.md index 7fd84f11..dde343fe 100644 --- a/docs/docs.md +++ b/docs/docs.md @@ -239,6 +239,7 @@ The Apify API client. * [task()](#apifyclient-task) * [tasks()](#apifyclient-tasks) * [user()](#apifyclient-user) +* [store()](#apifyclient-store) *** @@ -531,6 +532,16 @@ Retrieve the sub-client for querying users. *** +#### [](#apifyclient-store) `ApifyClient.store()` + +Retrieve the sub-client for Apify store. + +* **Return type** + + [`StoreCollectionClient`](#storecollectionclient) + +*** + ### [](#apifyclientasync) ApifyClientAsync The asynchronous version of the Apify API client. @@ -558,6 +569,7 @@ The asynchronous version of the Apify API client. * [task()](#apifyclientasync-task) * [tasks()](#apifyclientasync-tasks) * [user()](#apifyclientasync-user) +* [store()](#apifyclientasync-store) *** @@ -850,6 +862,16 @@ Retrieve the sub-client for querying users. *** +#### [](#apifyclientasync-store) `ApifyClientAsync.store()` + +Retrieve the sub-client for Apify store. + +* **Return type** + + `StoreCollectionClientAsync` + +*** + ### [](#actorclient) ActorClient Sub-client for manipulating a single actor. @@ -6237,3 +6259,83 @@ List all webhook dispatches of a user. * **Return type** [`ListPage`](#listpage) + +*** + +### [](#storecollectionclient) StoreCollectionClient + +Sub-client for Apify store. + +* [list()](#storecollectionclient-list) + +*** + +#### [](#storecollectionclient-list) `StoreCollectionClient.list(*, limit=None, offset=None, search=None, sort_by=None, category=None, username=None, pricing_model=None)` + +List Actors in Apify store. + +[https://docs.apify.com/api/v2/#/reference/store/store-actors-collection/get-list-of-actors-in-store](https://docs.apify.com/api/v2/#/reference/store/store-actors-collection/get-list-of-actors-in-store) + +* **Parameters** + + * **limit** (`int`, *optional*) – How many Actors to list + + * **offset** (`int`, *optional*) – What Actor to include as first when retrieving the list + + * **search** (`str`, *optional*) – String to search by. The search runs on the following fields: title, name, description, username, readme. + + * **sort_by** (`str`, *optional*) – Specifies the field by which to sort the results. + + * **category** (`str`, *optional*) – Filter by this category + + * **username** (`str`, *optional*) – Filter by this username + + * **pricing_model** (`str`, *optional*) – Filter by this pricing model + +* **Returns** + + The list of available tasks matching the specified filters. + +* **Return type** + + [`ListPage`](#listpage) + +*** + +### [](#storecollectionclientasync) StoreCollectionClientAsync + +Async sub-client for Apify store. + +* [async list()](#storecollectionclientasync-list) + +*** + +#### [](#storecollectionclientasync-list) `async StoreCollectionClientAsync.list(*, limit=None, offset=None, search=None, sort_by=None, category=None, username=None, pricing_model=None)` + +List Actors in Apify store. + +[https://docs.apify.com/api/v2/#/reference/store/store-actors-collection/get-list-of-actors-in-store](https://docs.apify.com/api/v2/#/reference/store/store-actors-collection/get-list-of-actors-in-store) + +* **Parameters** + + * **limit** (`int`, *optional*) – How many Actors to list + + * **offset** (`int`, *optional*) – What Actor to include as first when retrieving the list + + * **search** (`str`, *optional*) – String to search by. The search runs on the following fields: title, name, description, username, readme. + + * **sort_by** (`str`, *optional*) – Specifies the field by which to sort the results. + + * **category** (`str`, *optional*) – Filter by this category + + * **username** (`str`, *optional*) – Filter by this username + + * **pricing_model** (`str`, *optional*) – Filter by this pricing model + +* **Returns** + + The list of available tasks matching the specified filters. + +* **Return type** + + [`ListPage`](#listpage) diff --git a/src/apify_client/client.py b/src/apify_client/client.py index f3f83b26..edd80da8 100644 --- a/src/apify_client/client.py +++ b/src/apify_client/client.py @@ -34,6 +34,8 @@ ScheduleClientAsync, ScheduleCollectionClient, ScheduleCollectionClientAsync, + StoreCollectionClient, + StoreCollectionClientAsync, TaskClient, TaskClientAsync, TaskCollectionClient, @@ -268,6 +270,10 @@ def user(self, user_id: Optional[str] = None) -> UserClient: """ return UserClient(resource_id=user_id, **self._options()) + def store(self) -> StoreCollectionClient: + """Retrieve the sub-client for Apify store.""" + return StoreCollectionClient(**self._options()) + class ApifyClientAsync(_BaseApifyClient): """The asynchronous version of the Apify API client.""" @@ -444,3 +450,7 @@ def user(self, user_id: Optional[str] = None) -> UserClientAsync: user_id (str, optional): 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()) + + def store(self) -> StoreCollectionClientAsync: + """Retrieve the sub-client for Apify store.""" + return StoreCollectionClientAsync(**self._options()) diff --git a/src/apify_client/clients/__init__.py b/src/apify_client/clients/__init__.py index 577c345c..a6fc92d5 100644 --- a/src/apify_client/clients/__init__.py +++ b/src/apify_client/clients/__init__.py @@ -43,6 +43,8 @@ ScheduleClientAsync, ScheduleCollectionClient, ScheduleCollectionClientAsync, + StoreCollectionClient, + StoreCollectionClientAsync, TaskClient, TaskClientAsync, TaskCollectionClient, @@ -88,4 +90,5 @@ 'WebhookCollectionClient', 'WebhookCollectionClientAsync', 'WebhookDispatchClient', 'WebhookDispatchClientAsync', 'WebhookDispatchCollectionClient', 'WebhookDispatchCollectionClientAsync', + 'StoreCollectionClient', 'StoreCollectionClientAsync', ] diff --git a/src/apify_client/clients/resource_clients/__init__.py b/src/apify_client/clients/resource_clients/__init__.py index c6d8e17a..4938b703 100644 --- a/src/apify_client/clients/resource_clients/__init__.py +++ b/src/apify_client/clients/resource_clients/__init__.py @@ -15,6 +15,7 @@ from .run_collection import RunCollectionClient, RunCollectionClientAsync from .schedule import ScheduleClient, ScheduleClientAsync from .schedule_collection import ScheduleCollectionClient, ScheduleCollectionClientAsync +from .store_collection import StoreCollectionClient, StoreCollectionClientAsync from .task import TaskClient, TaskClientAsync from .task_collection import TaskCollectionClient, TaskCollectionClientAsync from .user import UserClient, UserClientAsync @@ -48,4 +49,5 @@ 'ScheduleClient', 'WebhookCollectionClientAsync', 'ScheduleCollectionClient', 'WebhookDispatchClientAsync', 'UserClient', 'WebhookDispatchCollectionClientAsync', + 'StoreCollectionClient', 'StoreCollectionClientAsync', ] diff --git a/src/apify_client/clients/resource_clients/store_collection.py b/src/apify_client/clients/resource_clients/store_collection.py new file mode 100644 index 00000000..e5a8d0fb --- /dev/null +++ b/src/apify_client/clients/resource_clients/store_collection.py @@ -0,0 +1,100 @@ +from typing import Any, Dict, Optional + +from apify_shared.models import ListPage +from apify_shared.utils import ignore_docs + +from ..base import ResourceCollectionClient, ResourceCollectionClientAsync + + +class StoreCollectionClient(ResourceCollectionClient): + """Sub-client for Apify store.""" + + @ignore_docs + def __init__(self, *args: Any, **kwargs: Any) -> None: + """Initialize the StoreCollectionClient.""" + resource_path = kwargs.pop('resource_path', 'store') + super().__init__(*args, resource_path=resource_path, **kwargs) + + def list( + self, + *, + limit: Optional[int] = None, + offset: Optional[int] = None, + search: Optional[str] = None, + sort_by: Optional[str] = None, + category: Optional[str] = None, + username: Optional[str] = None, + pricing_model: Optional[str] = None, + ) -> ListPage[Dict]: + """List Actors in Apify store. + + https://docs.apify.com/api/v2/#/reference/store/store-actors-collection/get-list-of-actors-in-store + + Args: + limit (int, optional): How many Actors to list + offset (int, optional): What Actor to include as first when retrieving the list + search (str, optional): String to search by. The search runs on the following fields: title, name, description, username, readme. + sort_by (str, optional): Specifies the field by which to sort the results. + category (str, optional): Filter by this category + username (str, optional): Filter by this username + pricing_model (str, optional): Filter by this pricing model + + Returns: + ListPage: The list of available tasks matching the specified filters. + """ + return self._list( + limit=limit, + offset=offset, + search=search, + sortBy=sort_by, + category=category, + username=username, + pricingModel=pricing_model, + ) + + +class StoreCollectionClientAsync(ResourceCollectionClientAsync): + """Async sub-client for Apify store.""" + + @ignore_docs + def __init__(self, *args: Any, **kwargs: Any) -> None: + """Initialize the StoreCollectionClientAsync.""" + resource_path = kwargs.pop('resource_path', 'store') + super().__init__(*args, resource_path=resource_path, **kwargs) + + async def list( + self, + *, + limit: Optional[int] = None, + offset: Optional[int] = None, + search: Optional[str] = None, + sort_by: Optional[str] = None, + category: Optional[str] = None, + username: Optional[str] = None, + pricing_model: Optional[str] = None, + ) -> ListPage[Dict]: + """List Actors in Apify store. + + https://docs.apify.com/api/v2/#/reference/store/store-actors-collection/get-list-of-actors-in-store + + Args: + limit (int, optional): How many Actors to list + offset (int, optional): What Actor to include as first when retrieving the list + search (str, optional): String to search by. The search runs on the following fields: title, name, description, username, readme. + sort_by (str, optional): Specifies the field by which to sort the results. + category (str, optional): Filter by this category + username (str, optional): Filter by this username + pricing_model (str, optional): Filter by this pricing model + + Returns: + ListPage: The list of available tasks matching the specified filters. + """ + return await self._list( + limit=limit, + offset=offset, + search=search, + sortBy=sort_by, + category=category, + username=username, + pricingModel=pricing_model, + ) diff --git a/tests/integration/test_store.py b/tests/integration/test_store.py new file mode 100644 index 00000000..4bdc79c1 --- /dev/null +++ b/tests/integration/test_store.py @@ -0,0 +1,15 @@ +from apify_client import ApifyClient, ApifyClientAsync + + +class TestStoreCollectionSync: + def test_list(self, apify_client: ApifyClient) -> None: + actors_list = apify_client.store().list() + assert actors_list is not None + assert len(actors_list.items) != 0 + + +class TestStoreCollectionAsync: + async def test_list(self, apify_client_async: ApifyClientAsync) -> None: + actors_list = await apify_client_async.store().list() + assert actors_list is not None + assert len(actors_list.items) != 0