From c678f75c6b75d18c33f61cfe48bc85d904a919fe Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 9 Dec 2024 02:30:54 +0000 Subject: [PATCH] feat(dex): add commands support --- .stats.yml | 2 +- api.md | 31 ++ .../resources/zero_trust/dex/__init__.py | 14 + .../zero_trust/dex/commands/__init__.py | 47 ++ .../zero_trust/dex/commands/commands.py | 417 ++++++++++++++++++ .../zero_trust/dex/commands/downloads.py | 190 ++++++++ .../zero_trust/dex/commands/quota.py | 176 ++++++++ .../resources/zero_trust/dex/dex.py | 33 ++ .../types/zero_trust/dex/__init__.py | 4 + .../zero_trust/dex/command_create_params.py | 57 +++ .../zero_trust/dex/command_create_response.py | 30 ++ .../zero_trust/dex/command_list_params.py | 39 ++ .../zero_trust/dex/command_list_response.py | 30 ++ .../types/zero_trust/dex/commands/__init__.py | 5 + .../dex/commands/quota_get_response.py | 18 + .../zero_trust/dex/commands/__init__.py | 1 + .../zero_trust/dex/commands/test_downloads.py | 184 ++++++++ .../zero_trust/dex/commands/test_quota.py | 98 ++++ .../zero_trust/dex/test_commands.py | 281 ++++++++++++ 19 files changed, 1656 insertions(+), 1 deletion(-) create mode 100644 src/cloudflare/resources/zero_trust/dex/commands/__init__.py create mode 100644 src/cloudflare/resources/zero_trust/dex/commands/commands.py create mode 100644 src/cloudflare/resources/zero_trust/dex/commands/downloads.py create mode 100644 src/cloudflare/resources/zero_trust/dex/commands/quota.py create mode 100644 src/cloudflare/types/zero_trust/dex/command_create_params.py create mode 100644 src/cloudflare/types/zero_trust/dex/command_create_response.py create mode 100644 src/cloudflare/types/zero_trust/dex/command_list_params.py create mode 100644 src/cloudflare/types/zero_trust/dex/command_list_response.py create mode 100644 src/cloudflare/types/zero_trust/dex/commands/__init__.py create mode 100644 src/cloudflare/types/zero_trust/dex/commands/quota_get_response.py create mode 100644 tests/api_resources/zero_trust/dex/commands/__init__.py create mode 100644 tests/api_resources/zero_trust/dex/commands/test_downloads.py create mode 100644 tests/api_resources/zero_trust/dex/commands/test_quota.py create mode 100644 tests/api_resources/zero_trust/dex/test_commands.py diff --git a/.stats.yml b/.stats.yml index 1406c7030c2..ab5ab2be2f8 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ -configured_endpoints: 1450 +configured_endpoints: 1454 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-24f32ff8cc230aecb28b850e99ed99f6f66fba898e64194d21052c4c2b869a24.yml diff --git a/api.md b/api.md index 3e782d77fbd..4cc36654e66 100644 --- a/api.md +++ b/api.md @@ -5591,6 +5591,37 @@ from cloudflare.types.zero_trust import ( ) ``` +### Commands + +Types: + +```python +from cloudflare.types.zero_trust.dex import CommandCreateResponse, CommandListResponse +``` + +Methods: + +- client.zero_trust.dex.commands.create(\*, account_id, \*\*params) -> Optional[CommandCreateResponse] +- client.zero_trust.dex.commands.list(\*, account_id, \*\*params) -> SyncV4PagePagination[Optional[CommandListResponse]] + +#### Downloads + +Methods: + +- client.zero_trust.dex.commands.downloads.get(filename, \*, account_id, command_id) -> BinaryAPIResponse + +#### Quota + +Types: + +```python +from cloudflare.types.zero_trust.dex.commands import QuotaGetResponse +``` + +Methods: + +- client.zero_trust.dex.commands.quota.get(\*, account_id) -> Optional[QuotaGetResponse] + ### Colos Types: diff --git a/src/cloudflare/resources/zero_trust/dex/__init__.py b/src/cloudflare/resources/zero_trust/dex/__init__.py index b79e8e9ec69..defe96da107 100644 --- a/src/cloudflare/resources/zero_trust/dex/__init__.py +++ b/src/cloudflare/resources/zero_trust/dex/__init__.py @@ -24,6 +24,14 @@ TestsResourceWithStreamingResponse, AsyncTestsResourceWithStreamingResponse, ) +from .commands import ( + CommandsResource, + AsyncCommandsResource, + CommandsResourceWithRawResponse, + AsyncCommandsResourceWithRawResponse, + CommandsResourceWithStreamingResponse, + AsyncCommandsResourceWithStreamingResponse, +) from .http_tests import ( HTTPTestsResource, AsyncHTTPTestsResource, @@ -58,6 +66,12 @@ ) __all__ = [ + "CommandsResource", + "AsyncCommandsResource", + "CommandsResourceWithRawResponse", + "AsyncCommandsResourceWithRawResponse", + "CommandsResourceWithStreamingResponse", + "AsyncCommandsResourceWithStreamingResponse", "ColosResource", "AsyncColosResource", "ColosResourceWithRawResponse", diff --git a/src/cloudflare/resources/zero_trust/dex/commands/__init__.py b/src/cloudflare/resources/zero_trust/dex/commands/__init__.py new file mode 100644 index 00000000000..4566edefe96 --- /dev/null +++ b/src/cloudflare/resources/zero_trust/dex/commands/__init__.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .quota import ( + QuotaResource, + AsyncQuotaResource, + QuotaResourceWithRawResponse, + AsyncQuotaResourceWithRawResponse, + QuotaResourceWithStreamingResponse, + AsyncQuotaResourceWithStreamingResponse, +) +from .commands import ( + CommandsResource, + AsyncCommandsResource, + CommandsResourceWithRawResponse, + AsyncCommandsResourceWithRawResponse, + CommandsResourceWithStreamingResponse, + AsyncCommandsResourceWithStreamingResponse, +) +from .downloads import ( + DownloadsResource, + AsyncDownloadsResource, + DownloadsResourceWithRawResponse, + AsyncDownloadsResourceWithRawResponse, + DownloadsResourceWithStreamingResponse, + AsyncDownloadsResourceWithStreamingResponse, +) + +__all__ = [ + "DownloadsResource", + "AsyncDownloadsResource", + "DownloadsResourceWithRawResponse", + "AsyncDownloadsResourceWithRawResponse", + "DownloadsResourceWithStreamingResponse", + "AsyncDownloadsResourceWithStreamingResponse", + "QuotaResource", + "AsyncQuotaResource", + "QuotaResourceWithRawResponse", + "AsyncQuotaResourceWithRawResponse", + "QuotaResourceWithStreamingResponse", + "AsyncQuotaResourceWithStreamingResponse", + "CommandsResource", + "AsyncCommandsResource", + "CommandsResourceWithRawResponse", + "AsyncCommandsResourceWithRawResponse", + "CommandsResourceWithStreamingResponse", + "AsyncCommandsResourceWithStreamingResponse", +] diff --git a/src/cloudflare/resources/zero_trust/dex/commands/commands.py b/src/cloudflare/resources/zero_trust/dex/commands/commands.py new file mode 100644 index 00000000000..f59aadf5646 --- /dev/null +++ b/src/cloudflare/resources/zero_trust/dex/commands/commands.py @@ -0,0 +1,417 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Type, Union, Iterable, Optional, cast +from datetime import datetime +from typing_extensions import Literal + +import httpx + +from .quota import ( + QuotaResource, + AsyncQuotaResource, + QuotaResourceWithRawResponse, + AsyncQuotaResourceWithRawResponse, + QuotaResourceWithStreamingResponse, + AsyncQuotaResourceWithStreamingResponse, +) +from .downloads import ( + DownloadsResource, + AsyncDownloadsResource, + DownloadsResourceWithRawResponse, + AsyncDownloadsResourceWithRawResponse, + DownloadsResourceWithStreamingResponse, + AsyncDownloadsResourceWithStreamingResponse, +) +from ....._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ....._utils import ( + maybe_transform, + async_maybe_transform, +) +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....._wrappers import ResultWrapper +from .....pagination import SyncV4PagePagination, AsyncV4PagePagination +from ....._base_client import AsyncPaginator, make_request_options +from .....types.zero_trust.dex import command_list_params, command_create_params +from .....types.zero_trust.dex.command_list_response import CommandListResponse +from .....types.zero_trust.dex.command_create_response import CommandCreateResponse + +__all__ = ["CommandsResource", "AsyncCommandsResource"] + + +class CommandsResource(SyncAPIResource): + @cached_property + def downloads(self) -> DownloadsResource: + return DownloadsResource(self._client) + + @cached_property + def quota(self) -> QuotaResource: + return QuotaResource(self._client) + + @cached_property + def with_raw_response(self) -> CommandsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/cloudflare/cloudflare-python#accessing-raw-response-data-eg-headers + """ + return CommandsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> CommandsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/cloudflare/cloudflare-python#with_streaming_response + """ + return CommandsResourceWithStreamingResponse(self) + + def create( + self, + *, + account_id: str, + commands: Iterable[command_create_params.Command], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Optional[CommandCreateResponse]: + """ + Initiate commands for up to 10 devices per account + + Args: + commands: List of device-level commands to execute + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not account_id: + raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + return self._post( + f"/accounts/{account_id}/commands", + body=maybe_transform({"commands": commands}, command_create_params.CommandCreateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[Optional[CommandCreateResponse]]._unwrapper, + ), + cast_to=cast(Type[Optional[CommandCreateResponse]], ResultWrapper[CommandCreateResponse]), + ) + + def list( + self, + *, + account_id: str, + page: float, + per_page: float, + command_type: str | NotGiven = NOT_GIVEN, + device_id: str | NotGiven = NOT_GIVEN, + from_: Union[str, datetime] | NotGiven = NOT_GIVEN, + status: Literal["PENDING_EXEC", "PENDING_UPLOAD", "SUCCESS", "FAILED"] | NotGiven = NOT_GIVEN, + to: Union[str, datetime] | NotGiven = NOT_GIVEN, + user_email: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> SyncV4PagePagination[Optional[CommandListResponse]]: + """ + Retrieves a paginated list of commands issued to devices under the specified + account, optionally filtered by time range, device, or other parameters + + Args: + page: Page number for pagination + + per_page: Number of results per page + + command_type: Optionally filter executed commands by command type + + device_id: Unique identifier for a device + + from_: Start time for the query in ISO (RFC3339 - ISO 8601) format + + status: Optionally filter executed commands by status + + to: End time for the query in ISO (RFC3339 - ISO 8601) format + + user_email: Email tied to the device + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not account_id: + raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + return self._get_api_list( + f"/accounts/{account_id}/commands", + page=SyncV4PagePagination[Optional[CommandListResponse]], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "page": page, + "per_page": per_page, + "command_type": command_type, + "device_id": device_id, + "from_": from_, + "status": status, + "to": to, + "user_email": user_email, + }, + command_list_params.CommandListParams, + ), + ), + model=CommandListResponse, + ) + + +class AsyncCommandsResource(AsyncAPIResource): + @cached_property + def downloads(self) -> AsyncDownloadsResource: + return AsyncDownloadsResource(self._client) + + @cached_property + def quota(self) -> AsyncQuotaResource: + return AsyncQuotaResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncCommandsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/cloudflare/cloudflare-python#accessing-raw-response-data-eg-headers + """ + return AsyncCommandsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncCommandsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/cloudflare/cloudflare-python#with_streaming_response + """ + return AsyncCommandsResourceWithStreamingResponse(self) + + async def create( + self, + *, + account_id: str, + commands: Iterable[command_create_params.Command], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Optional[CommandCreateResponse]: + """ + Initiate commands for up to 10 devices per account + + Args: + commands: List of device-level commands to execute + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not account_id: + raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + return await self._post( + f"/accounts/{account_id}/commands", + body=await async_maybe_transform({"commands": commands}, command_create_params.CommandCreateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[Optional[CommandCreateResponse]]._unwrapper, + ), + cast_to=cast(Type[Optional[CommandCreateResponse]], ResultWrapper[CommandCreateResponse]), + ) + + def list( + self, + *, + account_id: str, + page: float, + per_page: float, + command_type: str | NotGiven = NOT_GIVEN, + device_id: str | NotGiven = NOT_GIVEN, + from_: Union[str, datetime] | NotGiven = NOT_GIVEN, + status: Literal["PENDING_EXEC", "PENDING_UPLOAD", "SUCCESS", "FAILED"] | NotGiven = NOT_GIVEN, + to: Union[str, datetime] | NotGiven = NOT_GIVEN, + user_email: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> AsyncPaginator[Optional[CommandListResponse], AsyncV4PagePagination[Optional[CommandListResponse]]]: + """ + Retrieves a paginated list of commands issued to devices under the specified + account, optionally filtered by time range, device, or other parameters + + Args: + page: Page number for pagination + + per_page: Number of results per page + + command_type: Optionally filter executed commands by command type + + device_id: Unique identifier for a device + + from_: Start time for the query in ISO (RFC3339 - ISO 8601) format + + status: Optionally filter executed commands by status + + to: End time for the query in ISO (RFC3339 - ISO 8601) format + + user_email: Email tied to the device + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not account_id: + raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + return self._get_api_list( + f"/accounts/{account_id}/commands", + page=AsyncV4PagePagination[Optional[CommandListResponse]], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "page": page, + "per_page": per_page, + "command_type": command_type, + "device_id": device_id, + "from_": from_, + "status": status, + "to": to, + "user_email": user_email, + }, + command_list_params.CommandListParams, + ), + ), + model=CommandListResponse, + ) + + +class CommandsResourceWithRawResponse: + def __init__(self, commands: CommandsResource) -> None: + self._commands = commands + + self.create = to_raw_response_wrapper( + commands.create, + ) + self.list = to_raw_response_wrapper( + commands.list, + ) + + @cached_property + def downloads(self) -> DownloadsResourceWithRawResponse: + return DownloadsResourceWithRawResponse(self._commands.downloads) + + @cached_property + def quota(self) -> QuotaResourceWithRawResponse: + return QuotaResourceWithRawResponse(self._commands.quota) + + +class AsyncCommandsResourceWithRawResponse: + def __init__(self, commands: AsyncCommandsResource) -> None: + self._commands = commands + + self.create = async_to_raw_response_wrapper( + commands.create, + ) + self.list = async_to_raw_response_wrapper( + commands.list, + ) + + @cached_property + def downloads(self) -> AsyncDownloadsResourceWithRawResponse: + return AsyncDownloadsResourceWithRawResponse(self._commands.downloads) + + @cached_property + def quota(self) -> AsyncQuotaResourceWithRawResponse: + return AsyncQuotaResourceWithRawResponse(self._commands.quota) + + +class CommandsResourceWithStreamingResponse: + def __init__(self, commands: CommandsResource) -> None: + self._commands = commands + + self.create = to_streamed_response_wrapper( + commands.create, + ) + self.list = to_streamed_response_wrapper( + commands.list, + ) + + @cached_property + def downloads(self) -> DownloadsResourceWithStreamingResponse: + return DownloadsResourceWithStreamingResponse(self._commands.downloads) + + @cached_property + def quota(self) -> QuotaResourceWithStreamingResponse: + return QuotaResourceWithStreamingResponse(self._commands.quota) + + +class AsyncCommandsResourceWithStreamingResponse: + def __init__(self, commands: AsyncCommandsResource) -> None: + self._commands = commands + + self.create = async_to_streamed_response_wrapper( + commands.create, + ) + self.list = async_to_streamed_response_wrapper( + commands.list, + ) + + @cached_property + def downloads(self) -> AsyncDownloadsResourceWithStreamingResponse: + return AsyncDownloadsResourceWithStreamingResponse(self._commands.downloads) + + @cached_property + def quota(self) -> AsyncQuotaResourceWithStreamingResponse: + return AsyncQuotaResourceWithStreamingResponse(self._commands.quota) diff --git a/src/cloudflare/resources/zero_trust/dex/commands/downloads.py b/src/cloudflare/resources/zero_trust/dex/commands/downloads.py new file mode 100644 index 00000000000..4baa6e25922 --- /dev/null +++ b/src/cloudflare/resources/zero_trust/dex/commands/downloads.py @@ -0,0 +1,190 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ....._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import ( + BinaryAPIResponse, + AsyncBinaryAPIResponse, + StreamedBinaryAPIResponse, + AsyncStreamedBinaryAPIResponse, + to_custom_raw_response_wrapper, + to_custom_streamed_response_wrapper, + async_to_custom_raw_response_wrapper, + async_to_custom_streamed_response_wrapper, +) +from ....._base_client import make_request_options + +__all__ = ["DownloadsResource", "AsyncDownloadsResource"] + + +class DownloadsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> DownloadsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/cloudflare/cloudflare-python#accessing-raw-response-data-eg-headers + """ + return DownloadsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> DownloadsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/cloudflare/cloudflare-python#with_streaming_response + """ + return DownloadsResourceWithStreamingResponse(self) + + def get( + self, + filename: str, + *, + account_id: str, + command_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> BinaryAPIResponse: + """Downloads artifacts for an executed command. + + Bulk downloads are not supported + + Args: + command_id: Unique identifier for a command + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not account_id: + raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + if not command_id: + raise ValueError(f"Expected a non-empty value for `command_id` but received {command_id!r}") + if not filename: + raise ValueError(f"Expected a non-empty value for `filename` but received {filename!r}") + extra_headers = {"Accept": "application/zip", **(extra_headers or {})} + return self._get( + f"/accounts/{account_id}/commands/{command_id}/downloads/{filename}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=BinaryAPIResponse, + ) + + +class AsyncDownloadsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncDownloadsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/cloudflare/cloudflare-python#accessing-raw-response-data-eg-headers + """ + return AsyncDownloadsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncDownloadsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/cloudflare/cloudflare-python#with_streaming_response + """ + return AsyncDownloadsResourceWithStreamingResponse(self) + + async def get( + self, + filename: str, + *, + account_id: str, + command_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> AsyncBinaryAPIResponse: + """Downloads artifacts for an executed command. + + Bulk downloads are not supported + + Args: + command_id: Unique identifier for a command + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not account_id: + raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + if not command_id: + raise ValueError(f"Expected a non-empty value for `command_id` but received {command_id!r}") + if not filename: + raise ValueError(f"Expected a non-empty value for `filename` but received {filename!r}") + extra_headers = {"Accept": "application/zip", **(extra_headers or {})} + return await self._get( + f"/accounts/{account_id}/commands/{command_id}/downloads/{filename}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AsyncBinaryAPIResponse, + ) + + +class DownloadsResourceWithRawResponse: + def __init__(self, downloads: DownloadsResource) -> None: + self._downloads = downloads + + self.get = to_custom_raw_response_wrapper( + downloads.get, + BinaryAPIResponse, + ) + + +class AsyncDownloadsResourceWithRawResponse: + def __init__(self, downloads: AsyncDownloadsResource) -> None: + self._downloads = downloads + + self.get = async_to_custom_raw_response_wrapper( + downloads.get, + AsyncBinaryAPIResponse, + ) + + +class DownloadsResourceWithStreamingResponse: + def __init__(self, downloads: DownloadsResource) -> None: + self._downloads = downloads + + self.get = to_custom_streamed_response_wrapper( + downloads.get, + StreamedBinaryAPIResponse, + ) + + +class AsyncDownloadsResourceWithStreamingResponse: + def __init__(self, downloads: AsyncDownloadsResource) -> None: + self._downloads = downloads + + self.get = async_to_custom_streamed_response_wrapper( + downloads.get, + AsyncStreamedBinaryAPIResponse, + ) diff --git a/src/cloudflare/resources/zero_trust/dex/commands/quota.py b/src/cloudflare/resources/zero_trust/dex/commands/quota.py new file mode 100644 index 00000000000..f16c78b78ce --- /dev/null +++ b/src/cloudflare/resources/zero_trust/dex/commands/quota.py @@ -0,0 +1,176 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Type, Optional, cast + +import httpx + +from ....._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ....._compat import cached_property +from ....._resource import SyncAPIResource, AsyncAPIResource +from ....._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....._wrappers import ResultWrapper +from ....._base_client import make_request_options +from .....types.zero_trust.dex.commands.quota_get_response import QuotaGetResponse + +__all__ = ["QuotaResource", "AsyncQuotaResource"] + + +class QuotaResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> QuotaResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/cloudflare/cloudflare-python#accessing-raw-response-data-eg-headers + """ + return QuotaResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> QuotaResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/cloudflare/cloudflare-python#with_streaming_response + """ + return QuotaResourceWithStreamingResponse(self) + + def get( + self, + *, + account_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Optional[QuotaGetResponse]: + """ + Retrieves the current quota usage and limits for device commands within a + specific account, including the time when the quota will reset + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not account_id: + raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + return self._get( + f"/accounts/{account_id}/commands/quota", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[Optional[QuotaGetResponse]]._unwrapper, + ), + cast_to=cast(Type[Optional[QuotaGetResponse]], ResultWrapper[QuotaGetResponse]), + ) + + +class AsyncQuotaResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncQuotaResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/cloudflare/cloudflare-python#accessing-raw-response-data-eg-headers + """ + return AsyncQuotaResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncQuotaResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/cloudflare/cloudflare-python#with_streaming_response + """ + return AsyncQuotaResourceWithStreamingResponse(self) + + async def get( + self, + *, + account_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Optional[QuotaGetResponse]: + """ + Retrieves the current quota usage and limits for device commands within a + specific account, including the time when the quota will reset + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not account_id: + raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + return await self._get( + f"/accounts/{account_id}/commands/quota", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[Optional[QuotaGetResponse]]._unwrapper, + ), + cast_to=cast(Type[Optional[QuotaGetResponse]], ResultWrapper[QuotaGetResponse]), + ) + + +class QuotaResourceWithRawResponse: + def __init__(self, quota: QuotaResource) -> None: + self._quota = quota + + self.get = to_raw_response_wrapper( + quota.get, + ) + + +class AsyncQuotaResourceWithRawResponse: + def __init__(self, quota: AsyncQuotaResource) -> None: + self._quota = quota + + self.get = async_to_raw_response_wrapper( + quota.get, + ) + + +class QuotaResourceWithStreamingResponse: + def __init__(self, quota: QuotaResource) -> None: + self._quota = quota + + self.get = to_streamed_response_wrapper( + quota.get, + ) + + +class AsyncQuotaResourceWithStreamingResponse: + def __init__(self, quota: AsyncQuotaResource) -> None: + self._quota = quota + + self.get = async_to_streamed_response_wrapper( + quota.get, + ) diff --git a/src/cloudflare/resources/zero_trust/dex/dex.py b/src/cloudflare/resources/zero_trust/dex/dex.py index 654a940a2a3..c8f838301e9 100644 --- a/src/cloudflare/resources/zero_trust/dex/dex.py +++ b/src/cloudflare/resources/zero_trust/dex/dex.py @@ -18,6 +18,14 @@ TestsResourceWithStreamingResponse, AsyncTestsResourceWithStreamingResponse, ) +from .commands import ( + CommandsResource, + AsyncCommandsResource, + CommandsResourceWithRawResponse, + AsyncCommandsResourceWithRawResponse, + CommandsResourceWithStreamingResponse, + AsyncCommandsResourceWithStreamingResponse, +) from ...._compat import cached_property from .http_tests import ( HTTPTestsResource, @@ -45,6 +53,7 @@ TracerouteTestsResourceWithStreamingResponse, AsyncTracerouteTestsResourceWithStreamingResponse, ) +from .commands.commands import CommandsResource, AsyncCommandsResource from .http_tests.http_tests import HTTPTestsResource, AsyncHTTPTestsResource from .traceroute_test_results import ( TracerouteTestResultsResource, @@ -64,6 +73,10 @@ class DEXResource(SyncAPIResource): + @cached_property + def commands(self) -> CommandsResource: + return CommandsResource(self._client) + @cached_property def colos(self) -> ColosResource: return ColosResource(self._client) @@ -109,6 +122,10 @@ def with_streaming_response(self) -> DEXResourceWithStreamingResponse: class AsyncDEXResource(AsyncAPIResource): + @cached_property + def commands(self) -> AsyncCommandsResource: + return AsyncCommandsResource(self._client) + @cached_property def colos(self) -> AsyncColosResource: return AsyncColosResource(self._client) @@ -157,6 +174,10 @@ class DEXResourceWithRawResponse: def __init__(self, dex: DEXResource) -> None: self._dex = dex + @cached_property + def commands(self) -> CommandsResourceWithRawResponse: + return CommandsResourceWithRawResponse(self._dex.commands) + @cached_property def colos(self) -> ColosResourceWithRawResponse: return ColosResourceWithRawResponse(self._dex.colos) @@ -186,6 +207,10 @@ class AsyncDEXResourceWithRawResponse: def __init__(self, dex: AsyncDEXResource) -> None: self._dex = dex + @cached_property + def commands(self) -> AsyncCommandsResourceWithRawResponse: + return AsyncCommandsResourceWithRawResponse(self._dex.commands) + @cached_property def colos(self) -> AsyncColosResourceWithRawResponse: return AsyncColosResourceWithRawResponse(self._dex.colos) @@ -215,6 +240,10 @@ class DEXResourceWithStreamingResponse: def __init__(self, dex: DEXResource) -> None: self._dex = dex + @cached_property + def commands(self) -> CommandsResourceWithStreamingResponse: + return CommandsResourceWithStreamingResponse(self._dex.commands) + @cached_property def colos(self) -> ColosResourceWithStreamingResponse: return ColosResourceWithStreamingResponse(self._dex.colos) @@ -244,6 +273,10 @@ class AsyncDEXResourceWithStreamingResponse: def __init__(self, dex: AsyncDEXResource) -> None: self._dex = dex + @cached_property + def commands(self) -> AsyncCommandsResourceWithStreamingResponse: + return AsyncCommandsResourceWithStreamingResponse(self._dex.commands) + @cached_property def colos(self) -> AsyncColosResourceWithStreamingResponse: return AsyncColosResourceWithStreamingResponse(self._dex.colos) diff --git a/src/cloudflare/types/zero_trust/dex/__init__.py b/src/cloudflare/types/zero_trust/dex/__init__.py index d891e1d3a9d..cd977b0b14c 100644 --- a/src/cloudflare/types/zero_trust/dex/__init__.py +++ b/src/cloudflare/types/zero_trust/dex/__init__.py @@ -8,8 +8,12 @@ from .http_details import HTTPDetails as HTTPDetails from .colo_list_params import ColoListParams as ColoListParams from .test_list_params import TestListParams as TestListParams +from .command_list_params import CommandListParams as CommandListParams from .http_test_get_params import HTTPTestGetParams as HTTPTestGetParams from .aggregate_time_period import AggregateTimePeriod as AggregateTimePeriod +from .command_create_params import CommandCreateParams as CommandCreateParams +from .command_list_response import CommandListResponse as CommandListResponse +from .command_create_response import CommandCreateResponse as CommandCreateResponse from .fleet_status_live_params import FleetStatusLiveParams as FleetStatusLiveParams from .fleet_status_live_response import FleetStatusLiveResponse as FleetStatusLiveResponse from .traceroute_test_get_params import TracerouteTestGetParams as TracerouteTestGetParams diff --git a/src/cloudflare/types/zero_trust/dex/command_create_params.py b/src/cloudflare/types/zero_trust/dex/command_create_params.py new file mode 100644 index 00000000000..cbab76ab1c1 --- /dev/null +++ b/src/cloudflare/types/zero_trust/dex/command_create_params.py @@ -0,0 +1,57 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Iterable +from typing_extensions import Literal, Required, Annotated, TypedDict + +from ...._utils import PropertyInfo + +__all__ = ["CommandCreateParams", "Command", "CommandCommandArgs"] + + +class CommandCreateParams(TypedDict, total=False): + account_id: Required[str] + + commands: Required[Iterable[Command]] + """List of device-level commands to execute""" + + +class CommandCommandArgs(TypedDict, total=False): + interfaces: List[Literal["default", "tunnel"]] + """List of interfaces to capture packets on""" + + max_file_size_mb: Annotated[float, PropertyInfo(alias="max-file-size-mb")] + """Maximum file size (in MB) for the capture file. + + Specifies the maximum file size of the warp-diag zip artifact that can be + uploaded. If the zip artifact exceeds the specified max file size, it will NOT + be uploaded + """ + + packet_size_bytes: Annotated[float, PropertyInfo(alias="packet-size-bytes")] + """Maximum number of bytes to save for each packet""" + + test_all_routes: Annotated[bool, PropertyInfo(alias="test-all-routes")] + """Test an IP address from all included or excluded ranges. + + Tests an IP address from all included or excluded ranges. Essentially the same + as running 'route get '' and collecting the results. This option may + increase the time taken to collect the warp-diag + """ + + time_limit_min: Annotated[float, PropertyInfo(alias="time-limit-min")] + """Limit on capture duration (in minutes)""" + + +class Command(TypedDict, total=False): + command_type: Required[Literal["pcap", "warp-diag"]] + """Type of command to execute on the device""" + + device_id: Required[str] + """Unique identifier for the device""" + + user_email: Required[str] + """Email tied to the device""" + + command_args: CommandCommandArgs diff --git a/src/cloudflare/types/zero_trust/dex/command_create_response.py b/src/cloudflare/types/zero_trust/dex/command_create_response.py new file mode 100644 index 00000000000..e3a1e432678 --- /dev/null +++ b/src/cloudflare/types/zero_trust/dex/command_create_response.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["CommandCreateResponse", "Command"] + + +class Command(BaseModel): + id: Optional[str] = None + """Unique identifier for the command""" + + args: Optional[Dict[str, str]] = None + """Command arguments""" + + device_id: Optional[str] = None + """Identifier for the device associated with the command""" + + status: Optional[Literal["PENDING_EXEC", "PENDING_UPLOAD", "SUCCESS", "FAILED"]] = None + """Current status of the command""" + + type: Optional[str] = None + """Type of the command (e.g., "pcap" or "warp-diag")""" + + +class CommandCreateResponse(BaseModel): + commands: Optional[List[Command]] = None + """List of created commands""" diff --git a/src/cloudflare/types/zero_trust/dex/command_list_params.py b/src/cloudflare/types/zero_trust/dex/command_list_params.py new file mode 100644 index 00000000000..cbe58116f27 --- /dev/null +++ b/src/cloudflare/types/zero_trust/dex/command_list_params.py @@ -0,0 +1,39 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from datetime import datetime +from typing_extensions import Literal, Required, Annotated, TypedDict + +from ...._utils import PropertyInfo + +__all__ = ["CommandListParams"] + + +class CommandListParams(TypedDict, total=False): + account_id: Required[str] + + page: Required[float] + """Page number for pagination""" + + per_page: Required[float] + """Number of results per page""" + + command_type: str + """Optionally filter executed commands by command type""" + + device_id: str + """Unique identifier for a device""" + + from_: Annotated[Union[str, datetime], PropertyInfo(alias="from", format="iso8601")] + """Start time for the query in ISO (RFC3339 - ISO 8601) format""" + + status: Literal["PENDING_EXEC", "PENDING_UPLOAD", "SUCCESS", "FAILED"] + """Optionally filter executed commands by status""" + + to: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] + """End time for the query in ISO (RFC3339 - ISO 8601) format""" + + user_email: str + """Email tied to the device""" diff --git a/src/cloudflare/types/zero_trust/dex/command_list_response.py b/src/cloudflare/types/zero_trust/dex/command_list_response.py new file mode 100644 index 00000000000..601cef906ce --- /dev/null +++ b/src/cloudflare/types/zero_trust/dex/command_list_response.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime + +from ...._models import BaseModel + +__all__ = ["CommandListResponse", "Command"] + + +class Command(BaseModel): + id: Optional[str] = None + + completed_date: Optional[datetime] = None + + created_date: Optional[datetime] = None + + device_id: Optional[str] = None + + filename: Optional[str] = None + + status: Optional[str] = None + + type: Optional[str] = None + + user_email: Optional[str] = None + + +class CommandListResponse(BaseModel): + commands: Optional[List[Command]] = None diff --git a/src/cloudflare/types/zero_trust/dex/commands/__init__.py b/src/cloudflare/types/zero_trust/dex/commands/__init__.py new file mode 100644 index 00000000000..83304891f5e --- /dev/null +++ b/src/cloudflare/types/zero_trust/dex/commands/__init__.py @@ -0,0 +1,5 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .quota_get_response import QuotaGetResponse as QuotaGetResponse diff --git a/src/cloudflare/types/zero_trust/dex/commands/quota_get_response.py b/src/cloudflare/types/zero_trust/dex/commands/quota_get_response.py new file mode 100644 index 00000000000..df1cc7d0596 --- /dev/null +++ b/src/cloudflare/types/zero_trust/dex/commands/quota_get_response.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from datetime import datetime + +from ....._models import BaseModel + +__all__ = ["QuotaGetResponse"] + + +class QuotaGetResponse(BaseModel): + quota: float + """The remaining number of commands that can be initiated for an account""" + + quota_usage: float + """The number of commands that have been initiated for an account""" + + reset_time: datetime + """The time when the quota resets""" diff --git a/tests/api_resources/zero_trust/dex/commands/__init__.py b/tests/api_resources/zero_trust/dex/commands/__init__.py new file mode 100644 index 00000000000..fd8019a9a1a --- /dev/null +++ b/tests/api_resources/zero_trust/dex/commands/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/zero_trust/dex/commands/test_downloads.py b/tests/api_resources/zero_trust/dex/commands/test_downloads.py new file mode 100644 index 00000000000..b2a9133f988 --- /dev/null +++ b/tests/api_resources/zero_trust/dex/commands/test_downloads.py @@ -0,0 +1,184 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import httpx +import pytest +from respx import MockRouter + +from cloudflare import Cloudflare, AsyncCloudflare +from cloudflare._response import ( + BinaryAPIResponse, + AsyncBinaryAPIResponse, + StreamedBinaryAPIResponse, + AsyncStreamedBinaryAPIResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestDownloads: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_method_get(self, client: Cloudflare, respx_mock: MockRouter) -> None: + respx_mock.get( + "/accounts/01a7362d577a6c3019a474fd6f485823/commands/5758fefe-ae7e-4538-a39b-1fef6abcb909/downloads/filename" + ).mock(return_value=httpx.Response(200, json={"foo": "bar"})) + download = client.zero_trust.dex.commands.downloads.get( + filename="filename", + account_id="01a7362d577a6c3019a474fd6f485823", + command_id="5758fefe-ae7e-4538-a39b-1fef6abcb909", + ) + assert download.is_closed + assert download.json() == {"foo": "bar"} + assert cast(Any, download.is_closed) is True + assert isinstance(download, BinaryAPIResponse) + + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_raw_response_get(self, client: Cloudflare, respx_mock: MockRouter) -> None: + respx_mock.get( + "/accounts/01a7362d577a6c3019a474fd6f485823/commands/5758fefe-ae7e-4538-a39b-1fef6abcb909/downloads/filename" + ).mock(return_value=httpx.Response(200, json={"foo": "bar"})) + + download = client.zero_trust.dex.commands.downloads.with_raw_response.get( + filename="filename", + account_id="01a7362d577a6c3019a474fd6f485823", + command_id="5758fefe-ae7e-4538-a39b-1fef6abcb909", + ) + + assert download.is_closed is True + assert download.http_request.headers.get("X-Stainless-Lang") == "python" + assert download.json() == {"foo": "bar"} + assert isinstance(download, BinaryAPIResponse) + + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_streaming_response_get(self, client: Cloudflare, respx_mock: MockRouter) -> None: + respx_mock.get( + "/accounts/01a7362d577a6c3019a474fd6f485823/commands/5758fefe-ae7e-4538-a39b-1fef6abcb909/downloads/filename" + ).mock(return_value=httpx.Response(200, json={"foo": "bar"})) + with client.zero_trust.dex.commands.downloads.with_streaming_response.get( + filename="filename", + account_id="01a7362d577a6c3019a474fd6f485823", + command_id="5758fefe-ae7e-4538-a39b-1fef6abcb909", + ) as download: + assert not download.is_closed + assert download.http_request.headers.get("X-Stainless-Lang") == "python" + + assert download.json() == {"foo": "bar"} + assert cast(Any, download.is_closed) is True + assert isinstance(download, StreamedBinaryAPIResponse) + + assert cast(Any, download.is_closed) is True + + @parametrize + @pytest.mark.respx(base_url=base_url) + def test_path_params_get(self, client: Cloudflare) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): + client.zero_trust.dex.commands.downloads.with_raw_response.get( + filename="filename", + account_id="", + command_id="5758fefe-ae7e-4538-a39b-1fef6abcb909", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `command_id` but received ''"): + client.zero_trust.dex.commands.downloads.with_raw_response.get( + filename="filename", + account_id="01a7362d577a6c3019a474fd6f485823", + command_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `filename` but received ''"): + client.zero_trust.dex.commands.downloads.with_raw_response.get( + filename="", + account_id="01a7362d577a6c3019a474fd6f485823", + command_id="5758fefe-ae7e-4538-a39b-1fef6abcb909", + ) + + +class TestAsyncDownloads: + parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_method_get(self, async_client: AsyncCloudflare, respx_mock: MockRouter) -> None: + respx_mock.get( + "/accounts/01a7362d577a6c3019a474fd6f485823/commands/5758fefe-ae7e-4538-a39b-1fef6abcb909/downloads/filename" + ).mock(return_value=httpx.Response(200, json={"foo": "bar"})) + download = await async_client.zero_trust.dex.commands.downloads.get( + filename="filename", + account_id="01a7362d577a6c3019a474fd6f485823", + command_id="5758fefe-ae7e-4538-a39b-1fef6abcb909", + ) + assert download.is_closed + assert await download.json() == {"foo": "bar"} + assert cast(Any, download.is_closed) is True + assert isinstance(download, AsyncBinaryAPIResponse) + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_raw_response_get(self, async_client: AsyncCloudflare, respx_mock: MockRouter) -> None: + respx_mock.get( + "/accounts/01a7362d577a6c3019a474fd6f485823/commands/5758fefe-ae7e-4538-a39b-1fef6abcb909/downloads/filename" + ).mock(return_value=httpx.Response(200, json={"foo": "bar"})) + + download = await async_client.zero_trust.dex.commands.downloads.with_raw_response.get( + filename="filename", + account_id="01a7362d577a6c3019a474fd6f485823", + command_id="5758fefe-ae7e-4538-a39b-1fef6abcb909", + ) + + assert download.is_closed is True + assert download.http_request.headers.get("X-Stainless-Lang") == "python" + assert await download.json() == {"foo": "bar"} + assert isinstance(download, AsyncBinaryAPIResponse) + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_streaming_response_get(self, async_client: AsyncCloudflare, respx_mock: MockRouter) -> None: + respx_mock.get( + "/accounts/01a7362d577a6c3019a474fd6f485823/commands/5758fefe-ae7e-4538-a39b-1fef6abcb909/downloads/filename" + ).mock(return_value=httpx.Response(200, json={"foo": "bar"})) + async with async_client.zero_trust.dex.commands.downloads.with_streaming_response.get( + filename="filename", + account_id="01a7362d577a6c3019a474fd6f485823", + command_id="5758fefe-ae7e-4538-a39b-1fef6abcb909", + ) as download: + assert not download.is_closed + assert download.http_request.headers.get("X-Stainless-Lang") == "python" + + assert await download.json() == {"foo": "bar"} + assert cast(Any, download.is_closed) is True + assert isinstance(download, AsyncStreamedBinaryAPIResponse) + + assert cast(Any, download.is_closed) is True + + @parametrize + @pytest.mark.respx(base_url=base_url) + async def test_path_params_get(self, async_client: AsyncCloudflare) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): + await async_client.zero_trust.dex.commands.downloads.with_raw_response.get( + filename="filename", + account_id="", + command_id="5758fefe-ae7e-4538-a39b-1fef6abcb909", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `command_id` but received ''"): + await async_client.zero_trust.dex.commands.downloads.with_raw_response.get( + filename="filename", + account_id="01a7362d577a6c3019a474fd6f485823", + command_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `filename` but received ''"): + await async_client.zero_trust.dex.commands.downloads.with_raw_response.get( + filename="", + account_id="01a7362d577a6c3019a474fd6f485823", + command_id="5758fefe-ae7e-4538-a39b-1fef6abcb909", + ) diff --git a/tests/api_resources/zero_trust/dex/commands/test_quota.py b/tests/api_resources/zero_trust/dex/commands/test_quota.py new file mode 100644 index 00000000000..5291e9d3113 --- /dev/null +++ b/tests/api_resources/zero_trust/dex/commands/test_quota.py @@ -0,0 +1,98 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, Optional, cast + +import pytest + +from cloudflare import Cloudflare, AsyncCloudflare +from tests.utils import assert_matches_type +from cloudflare.types.zero_trust.dex.commands import QuotaGetResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestQuota: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_get(self, client: Cloudflare) -> None: + quota = client.zero_trust.dex.commands.quota.get( + account_id="01a7362d577a6c3019a474fd6f485823", + ) + assert_matches_type(Optional[QuotaGetResponse], quota, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Cloudflare) -> None: + response = client.zero_trust.dex.commands.quota.with_raw_response.get( + account_id="01a7362d577a6c3019a474fd6f485823", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + quota = response.parse() + assert_matches_type(Optional[QuotaGetResponse], quota, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Cloudflare) -> None: + with client.zero_trust.dex.commands.quota.with_streaming_response.get( + account_id="01a7362d577a6c3019a474fd6f485823", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + quota = response.parse() + assert_matches_type(Optional[QuotaGetResponse], quota, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get(self, client: Cloudflare) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): + client.zero_trust.dex.commands.quota.with_raw_response.get( + account_id="", + ) + + +class TestAsyncQuota: + parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + async def test_method_get(self, async_client: AsyncCloudflare) -> None: + quota = await async_client.zero_trust.dex.commands.quota.get( + account_id="01a7362d577a6c3019a474fd6f485823", + ) + assert_matches_type(Optional[QuotaGetResponse], quota, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncCloudflare) -> None: + response = await async_client.zero_trust.dex.commands.quota.with_raw_response.get( + account_id="01a7362d577a6c3019a474fd6f485823", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + quota = await response.parse() + assert_matches_type(Optional[QuotaGetResponse], quota, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncCloudflare) -> None: + async with async_client.zero_trust.dex.commands.quota.with_streaming_response.get( + account_id="01a7362d577a6c3019a474fd6f485823", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + quota = await response.parse() + assert_matches_type(Optional[QuotaGetResponse], quota, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get(self, async_client: AsyncCloudflare) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): + await async_client.zero_trust.dex.commands.quota.with_raw_response.get( + account_id="", + ) diff --git a/tests/api_resources/zero_trust/dex/test_commands.py b/tests/api_resources/zero_trust/dex/test_commands.py new file mode 100644 index 00000000000..9692c4fde6c --- /dev/null +++ b/tests/api_resources/zero_trust/dex/test_commands.py @@ -0,0 +1,281 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, Optional, cast + +import pytest + +from cloudflare import Cloudflare, AsyncCloudflare +from tests.utils import assert_matches_type +from cloudflare._utils import parse_datetime +from cloudflare.pagination import SyncV4PagePagination, AsyncV4PagePagination +from cloudflare.types.zero_trust.dex import ( + CommandListResponse, + CommandCreateResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestCommands: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Cloudflare) -> None: + command = client.zero_trust.dex.commands.create( + account_id="01a7362d577a6c3019a474fd6f485823", + commands=[ + { + "command_type": "pcap", + "device_id": "device_id", + "user_email": "user_email", + } + ], + ) + assert_matches_type(Optional[CommandCreateResponse], command, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Cloudflare) -> None: + response = client.zero_trust.dex.commands.with_raw_response.create( + account_id="01a7362d577a6c3019a474fd6f485823", + commands=[ + { + "command_type": "pcap", + "device_id": "device_id", + "user_email": "user_email", + } + ], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + command = response.parse() + assert_matches_type(Optional[CommandCreateResponse], command, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Cloudflare) -> None: + with client.zero_trust.dex.commands.with_streaming_response.create( + account_id="01a7362d577a6c3019a474fd6f485823", + commands=[ + { + "command_type": "pcap", + "device_id": "device_id", + "user_email": "user_email", + } + ], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + command = response.parse() + assert_matches_type(Optional[CommandCreateResponse], command, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_create(self, client: Cloudflare) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): + client.zero_trust.dex.commands.with_raw_response.create( + account_id="", + commands=[ + { + "command_type": "pcap", + "device_id": "device_id", + "user_email": "user_email", + } + ], + ) + + @parametrize + def test_method_list(self, client: Cloudflare) -> None: + command = client.zero_trust.dex.commands.list( + account_id="01a7362d577a6c3019a474fd6f485823", + page=1, + per_page=50, + ) + assert_matches_type(SyncV4PagePagination[Optional[CommandListResponse]], command, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Cloudflare) -> None: + command = client.zero_trust.dex.commands.list( + account_id="01a7362d577a6c3019a474fd6f485823", + page=1, + per_page=50, + command_type="command_type", + device_id="device_id", + from_=parse_datetime("2023-08-20T20:45:00Z"), + status="PENDING_EXEC", + to=parse_datetime("2023-08-24T20:45:00Z"), + user_email="user_email", + ) + assert_matches_type(SyncV4PagePagination[Optional[CommandListResponse]], command, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Cloudflare) -> None: + response = client.zero_trust.dex.commands.with_raw_response.list( + account_id="01a7362d577a6c3019a474fd6f485823", + page=1, + per_page=50, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + command = response.parse() + assert_matches_type(SyncV4PagePagination[Optional[CommandListResponse]], command, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Cloudflare) -> None: + with client.zero_trust.dex.commands.with_streaming_response.list( + account_id="01a7362d577a6c3019a474fd6f485823", + page=1, + per_page=50, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + command = response.parse() + assert_matches_type(SyncV4PagePagination[Optional[CommandListResponse]], command, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: Cloudflare) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): + client.zero_trust.dex.commands.with_raw_response.list( + account_id="", + page=1, + per_page=50, + ) + + +class TestAsyncCommands: + parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + async def test_method_create(self, async_client: AsyncCloudflare) -> None: + command = await async_client.zero_trust.dex.commands.create( + account_id="01a7362d577a6c3019a474fd6f485823", + commands=[ + { + "command_type": "pcap", + "device_id": "device_id", + "user_email": "user_email", + } + ], + ) + assert_matches_type(Optional[CommandCreateResponse], command, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncCloudflare) -> None: + response = await async_client.zero_trust.dex.commands.with_raw_response.create( + account_id="01a7362d577a6c3019a474fd6f485823", + commands=[ + { + "command_type": "pcap", + "device_id": "device_id", + "user_email": "user_email", + } + ], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + command = await response.parse() + assert_matches_type(Optional[CommandCreateResponse], command, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncCloudflare) -> None: + async with async_client.zero_trust.dex.commands.with_streaming_response.create( + account_id="01a7362d577a6c3019a474fd6f485823", + commands=[ + { + "command_type": "pcap", + "device_id": "device_id", + "user_email": "user_email", + } + ], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + command = await response.parse() + assert_matches_type(Optional[CommandCreateResponse], command, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_create(self, async_client: AsyncCloudflare) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): + await async_client.zero_trust.dex.commands.with_raw_response.create( + account_id="", + commands=[ + { + "command_type": "pcap", + "device_id": "device_id", + "user_email": "user_email", + } + ], + ) + + @parametrize + async def test_method_list(self, async_client: AsyncCloudflare) -> None: + command = await async_client.zero_trust.dex.commands.list( + account_id="01a7362d577a6c3019a474fd6f485823", + page=1, + per_page=50, + ) + assert_matches_type(AsyncV4PagePagination[Optional[CommandListResponse]], command, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncCloudflare) -> None: + command = await async_client.zero_trust.dex.commands.list( + account_id="01a7362d577a6c3019a474fd6f485823", + page=1, + per_page=50, + command_type="command_type", + device_id="device_id", + from_=parse_datetime("2023-08-20T20:45:00Z"), + status="PENDING_EXEC", + to=parse_datetime("2023-08-24T20:45:00Z"), + user_email="user_email", + ) + assert_matches_type(AsyncV4PagePagination[Optional[CommandListResponse]], command, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncCloudflare) -> None: + response = await async_client.zero_trust.dex.commands.with_raw_response.list( + account_id="01a7362d577a6c3019a474fd6f485823", + page=1, + per_page=50, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + command = await response.parse() + assert_matches_type(AsyncV4PagePagination[Optional[CommandListResponse]], command, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncCloudflare) -> None: + async with async_client.zero_trust.dex.commands.with_streaming_response.list( + account_id="01a7362d577a6c3019a474fd6f485823", + page=1, + per_page=50, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + command = await response.parse() + assert_matches_type(AsyncV4PagePagination[Optional[CommandListResponse]], command, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncCloudflare) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): + await async_client.zero_trust.dex.commands.with_raw_response.list( + account_id="", + page=1, + per_page=50, + )