diff --git a/src/apify_client/_resource_clients/dataset_collection.py b/src/apify_client/_resource_clients/dataset_collection.py index 038b1d15..31c9c687 100644 --- a/src/apify_client/_resource_clients/dataset_collection.py +++ b/src/apify_client/_resource_clients/dataset_collection.py @@ -7,7 +7,7 @@ from apify_client._resource_clients._resource_client import ResourceClient, ResourceClientAsync if TYPE_CHECKING: - from apify_client._types import Timeout + from apify_client._types import StorageOwnership, Timeout @docs_group('Resource clients') @@ -36,6 +36,7 @@ def list( limit: int | None = None, offset: int | None = None, desc: bool | None = None, + ownership: StorageOwnership | None = None, timeout: Timeout = 'medium', ) -> ListOfDatasets: """List the available datasets. @@ -47,12 +48,16 @@ def list( limit: How many datasets to retrieve. offset: What dataset to include as first when retrieving the list. desc: Whether to sort the datasets in descending order based on their modification date. + ownership: Filter by ownership. 'ownedByMe' returns only user's own datasets, + 'sharedWithMe' returns only datasets shared with the user. timeout: Timeout for the API HTTP request. Returns: The list of available datasets matching the specified filters. """ - result = self._list(timeout=timeout, unnamed=unnamed, limit=limit, offset=offset, desc=desc) + result = self._list( + timeout=timeout, unnamed=unnamed, limit=limit, offset=offset, desc=desc, ownership=ownership + ) return ListOfDatasetsResponse.model_validate(result).data def get_or_create( @@ -104,6 +109,7 @@ async def list( limit: int | None = None, offset: int | None = None, desc: bool | None = None, + ownership: StorageOwnership | None = None, timeout: Timeout = 'medium', ) -> ListOfDatasets: """List the available datasets. @@ -115,12 +121,16 @@ async def list( limit: How many datasets to retrieve. offset: What dataset to include as first when retrieving the list. desc: Whether to sort the datasets in descending order based on their modification date. + ownership: Filter by ownership. 'ownedByMe' returns only user's own datasets, + 'sharedWithMe' returns only datasets shared with the user. timeout: Timeout for the API HTTP request. Returns: The list of available datasets matching the specified filters. """ - result = await self._list(timeout=timeout, unnamed=unnamed, limit=limit, offset=offset, desc=desc) + result = await self._list( + timeout=timeout, unnamed=unnamed, limit=limit, offset=offset, desc=desc, ownership=ownership + ) return ListOfDatasetsResponse.model_validate(result).data async def get_or_create( diff --git a/src/apify_client/_resource_clients/key_value_store_collection.py b/src/apify_client/_resource_clients/key_value_store_collection.py index 76609cc0..0f0e7e81 100644 --- a/src/apify_client/_resource_clients/key_value_store_collection.py +++ b/src/apify_client/_resource_clients/key_value_store_collection.py @@ -12,7 +12,7 @@ from apify_client._resource_clients._resource_client import ResourceClient, ResourceClientAsync if TYPE_CHECKING: - from apify_client._types import Timeout + from apify_client._types import StorageOwnership, Timeout @docs_group('Resource clients') @@ -41,6 +41,7 @@ def list( limit: int | None = None, offset: int | None = None, desc: bool | None = None, + ownership: StorageOwnership | None = None, timeout: Timeout = 'medium', ) -> ListOfKeyValueStores: """List the available key-value stores. @@ -52,12 +53,16 @@ def list( limit: How many key-value stores to retrieve. offset: What key-value store to include as first when retrieving the list. desc: Whether to sort the key-value stores in descending order based on their modification date. + ownership: Filter by ownership. 'ownedByMe' returns only user's own key-value stores, + 'sharedWithMe' returns only key-value stores shared with the user. timeout: Timeout for the API HTTP request. Returns: The list of available key-value stores matching the specified filters. """ - result = self._list(timeout=timeout, unnamed=unnamed, limit=limit, offset=offset, desc=desc) + result = self._list( + timeout=timeout, unnamed=unnamed, limit=limit, offset=offset, desc=desc, ownership=ownership + ) return ListOfKeyValueStoresResponse.model_validate(result).data def get_or_create( @@ -109,6 +114,7 @@ async def list( limit: int | None = None, offset: int | None = None, desc: bool | None = None, + ownership: StorageOwnership | None = None, timeout: Timeout = 'medium', ) -> ListOfKeyValueStores: """List the available key-value stores. @@ -120,12 +126,16 @@ async def list( limit: How many key-value stores to retrieve. offset: What key-value store to include as first when retrieving the list. desc: Whether to sort the key-value stores in descending order based on their modification date. + ownership: Filter by ownership. 'ownedByMe' returns only user's own key-value stores, + 'sharedWithMe' returns only key-value stores shared with the user. timeout: Timeout for the API HTTP request. Returns: The list of available key-value stores matching the specified filters. """ - result = await self._list(timeout=timeout, unnamed=unnamed, limit=limit, offset=offset, desc=desc) + result = await self._list( + timeout=timeout, unnamed=unnamed, limit=limit, offset=offset, desc=desc, ownership=ownership + ) return ListOfKeyValueStoresResponse.model_validate(result).data async def get_or_create( diff --git a/src/apify_client/_resource_clients/request_queue_collection.py b/src/apify_client/_resource_clients/request_queue_collection.py index b1fdf36b..c0ab28d0 100644 --- a/src/apify_client/_resource_clients/request_queue_collection.py +++ b/src/apify_client/_resource_clients/request_queue_collection.py @@ -12,7 +12,7 @@ from apify_client._resource_clients._resource_client import ResourceClient, ResourceClientAsync if TYPE_CHECKING: - from apify_client._types import Timeout + from apify_client._types import StorageOwnership, Timeout @docs_group('Resource clients') @@ -41,6 +41,7 @@ def list( limit: int | None = None, offset: int | None = None, desc: bool | None = None, + ownership: StorageOwnership | None = None, timeout: Timeout = 'medium', ) -> ListOfRequestQueues: """List the available request queues. @@ -51,13 +52,17 @@ def list( unnamed: Whether to include unnamed request queues in the list. limit: How many request queues to retrieve. offset: What request queue to include as first when retrieving the list. - desc: Whether to sort therequest queues in descending order based on their modification date. + desc: Whether to sort the request queues in descending order based on their modification date. + ownership: Filter by ownership. 'ownedByMe' returns only user's own request queues, + 'sharedWithMe' returns only request queues shared with the user. timeout: Timeout for the API HTTP request. Returns: The list of available request queues matching the specified filters. """ - result = self._list(timeout=timeout, unnamed=unnamed, limit=limit, offset=offset, desc=desc) + result = self._list( + timeout=timeout, unnamed=unnamed, limit=limit, offset=offset, desc=desc, ownership=ownership + ) return ListOfRequestQueuesResponse.model_validate(result).data def get_or_create( @@ -107,6 +112,7 @@ async def list( limit: int | None = None, offset: int | None = None, desc: bool | None = None, + ownership: StorageOwnership | None = None, timeout: Timeout = 'medium', ) -> ListOfRequestQueues: """List the available request queues. @@ -117,13 +123,17 @@ async def list( unnamed: Whether to include unnamed request queues in the list. limit: How many request queues to retrieve. offset: What request queue to include as first when retrieving the list. - desc: Whether to sort therequest queues in descending order based on their modification date. + desc: Whether to sort the request queues in descending order based on their modification date. + ownership: Filter by ownership. 'ownedByMe' returns only user's own request queues, + 'sharedWithMe' returns only request queues shared with the user. timeout: Timeout for the API HTTP request. Returns: The list of available request queues matching the specified filters. """ - result = await self._list(timeout=timeout, unnamed=unnamed, limit=limit, offset=offset, desc=desc) + result = await self._list( + timeout=timeout, unnamed=unnamed, limit=limit, offset=offset, desc=desc, ownership=ownership + ) return ListOfRequestQueuesResponse.model_validate(result).data async def get_or_create( diff --git a/src/apify_client/_types.py b/src/apify_client/_types.py index d3af93d0..18cd8595 100644 --- a/src/apify_client/_types.py +++ b/src/apify_client/_types.py @@ -9,6 +9,9 @@ from apify_client._models import ActorJobStatus, WebhookCreate # noqa: TC001 +StorageOwnership = Literal['ownedByMe', 'sharedWithMe'] +"""Filter for storage listing methods to return only storages owned by the user or shared with the user.""" + Timeout = timedelta | Literal['no_timeout', 'short', 'medium', 'long'] """Type for the `timeout` parameter on resource client methods. diff --git a/tests/unit/test_storage_collection_listing.py b/tests/unit/test_storage_collection_listing.py new file mode 100644 index 00000000..feaf483f --- /dev/null +++ b/tests/unit/test_storage_collection_listing.py @@ -0,0 +1,112 @@ +from __future__ import annotations + +import json +from typing import TYPE_CHECKING + +import pytest +from werkzeug.wrappers import Response + +from apify_client import ApifyClient, ApifyClientAsync + +if TYPE_CHECKING: + from collections.abc import Callable + + from pytest_httpserver import HTTPServer + from werkzeug.wrappers import Request + +_MOCK_LIST_RESPONSE = json.dumps( + { + 'data': { + 'items': [], + 'count': 0, + 'offset': 0, + 'limit': 100, + 'total': 0, + 'desc': False, + } + } +) + + +def _make_handler(captured: dict) -> Callable[[Request], Response]: + def handler(request: Request) -> Response: + captured['args'] = dict(request.args) + return Response(_MOCK_LIST_RESPONSE, content_type='application/json') + + return handler + + +@pytest.fixture +def client_urls(httpserver: HTTPServer) -> dict: + server_url = httpserver.url_for('/').removesuffix('/') + return {'api_url': server_url, 'api_public_url': server_url} + + +def test_dataset_collection_list_ownership_sync(httpserver: HTTPServer, client_urls: dict) -> None: + captured: dict = {} + httpserver.expect_oneshot_request('/v2/datasets', method='GET').respond_with_handler(_make_handler(captured)) + + client = ApifyClient(token='placeholder_token', **client_urls) + result = client.datasets().list(ownership='ownedByMe') + + assert result.total == 0 + assert captured['args']['ownership'] == 'ownedByMe' + + +async def test_dataset_collection_list_ownership_async(httpserver: HTTPServer, client_urls: dict) -> None: + captured: dict = {} + httpserver.expect_oneshot_request('/v2/datasets', method='GET').respond_with_handler(_make_handler(captured)) + + client = ApifyClientAsync(token='placeholder_token', **client_urls) + result = await client.datasets().list(ownership='sharedWithMe') + + assert result.total == 0 + assert captured['args']['ownership'] == 'sharedWithMe' + + +def test_key_value_store_collection_list_ownership_sync(httpserver: HTTPServer, client_urls: dict) -> None: + captured: dict = {} + httpserver.expect_oneshot_request('/v2/key-value-stores', method='GET').respond_with_handler( + _make_handler(captured) + ) + + client = ApifyClient(token='placeholder_token', **client_urls) + result = client.key_value_stores().list(ownership='ownedByMe') + + assert result.total == 0 + assert captured['args']['ownership'] == 'ownedByMe' + + +async def test_key_value_store_collection_list_ownership_async(httpserver: HTTPServer, client_urls: dict) -> None: + captured: dict = {} + httpserver.expect_oneshot_request('/v2/key-value-stores', method='GET').respond_with_handler( + _make_handler(captured) + ) + + client = ApifyClientAsync(token='placeholder_token', **client_urls) + result = await client.key_value_stores().list(ownership='sharedWithMe') + + assert result.total == 0 + assert captured['args']['ownership'] == 'sharedWithMe' + + +def test_request_queue_collection_list_ownership_sync(httpserver: HTTPServer, client_urls: dict) -> None: + captured: dict = {} + httpserver.expect_oneshot_request('/v2/request-queues', method='GET').respond_with_handler(_make_handler(captured)) + + client = ApifyClient(token='placeholder_token', **client_urls) + result = client.request_queues().list(ownership='ownedByMe') + + assert result.total == 0 + assert captured['args']['ownership'] == 'ownedByMe' + + +async def test_request_queue_collection_list_ownership_async(httpserver: HTTPServer, client_urls: dict) -> None: + captured: dict = {} + httpserver.expect_oneshot_request('/v2/request-queues', method='GET').respond_with_handler(_make_handler(captured)) + + client = ApifyClientAsync(token='placeholder_token', **client_urls) + result = await client.request_queues().list(ownership='sharedWithMe') + + assert result.total == 0 + assert captured['args']['ownership'] == 'sharedWithMe'