From 24026a3727dbc9ac01be1c03b9f2d866c54f4a9c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 24 Apr 2026 19:45:42 +0000 Subject: [PATCH 01/45] feat: feat(queues): add queues metrics endpoint * feat(queues): add queues metrics endpoint --- .stats.yml | 4 +- src/cloudflare/resources/queues/api.md | 3 +- src/cloudflare/resources/queues/queues.py | 105 ++++++++++++++++++ src/cloudflare/types/queues/__init__.py | 1 + .../queues/queue_get_metrics_response.py | 25 +++++ tests/api_resources/test_queues.py | 97 ++++++++++++++++ 6 files changed, 232 insertions(+), 3 deletions(-) create mode 100644 src/cloudflare/types/queues/queue_get_metrics_response.py diff --git a/.stats.yml b/.stats.yml index 1682359bc84..1b0284614f3 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 2194 +configured_endpoints: 2195 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-0ce49e6bb0d3819f135b9a567b661205fdf5df21cff157eab2b7abd7b5b50347.yml openapi_spec_hash: 512a5bb3a32860590c8949765605d65a -config_hash: 5367ae3e3a9a0d6578c2756965a99e3a +config_hash: 6f813d0ef66c7bf6daf8e0df5638e7a3 diff --git a/src/cloudflare/resources/queues/api.md b/src/cloudflare/resources/queues/api.md index 377d7d6186b..59d3863934b 100644 --- a/src/cloudflare/resources/queues/api.md +++ b/src/cloudflare/resources/queues/api.md @@ -3,7 +3,7 @@ Types: ```python -from cloudflare.types.queues import Queue, QueueDeleteResponse +from cloudflare.types.queues import Queue, QueueDeleteResponse, QueueGetMetricsResponse ``` Methods: @@ -14,6 +14,7 @@ Methods: - client.queues.delete(queue_id, \*, account_id) -> QueueDeleteResponse - client.queues.edit(queue_id, \*, account_id, \*\*params) -> Optional[Queue] - client.queues.get(queue_id, \*, account_id) -> Optional[Queue] +- client.queues.get_metrics(queue_id, \*, account_id) -> Optional[QueueGetMetricsResponse] ## Messages diff --git a/src/cloudflare/resources/queues/queues.py b/src/cloudflare/resources/queues/queues.py index 138d47827c4..775e62f2a71 100644 --- a/src/cloudflare/resources/queues/queues.py +++ b/src/cloudflare/resources/queues/queues.py @@ -54,6 +54,7 @@ from ...types.queues import queue_edit_params, queue_create_params, queue_update_params from ...types.queues.queue import Queue from ...types.queues.queue_delete_response import QueueDeleteResponse +from ...types.queues.queue_get_metrics_response import QueueGetMetricsResponse __all__ = ["QueuesResource", "AsyncQueuesResource"] @@ -364,6 +365,52 @@ def get( cast_to=cast(Type[Optional[Queue]], ResultWrapper[Queue]), ) + def get_metrics( + self, + queue_id: str, + *, + 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[QueueGetMetricsResponse]: + """Return best-effort metrics for a queue. + + Values may be approximate due to the + distributed nature of queues. + + Args: + account_id: A Resource identifier. + + queue_id: A Resource identifier. + + 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 queue_id: + raise ValueError(f"Expected a non-empty value for `queue_id` but received {queue_id!r}") + return self._get( + path_template("/accounts/{account_id}/queues/{queue_id}/metrics", account_id=account_id, queue_id=queue_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[Optional[QueueGetMetricsResponse]]._unwrapper, + ), + cast_to=cast(Type[Optional[QueueGetMetricsResponse]], ResultWrapper[QueueGetMetricsResponse]), + ) + class AsyncQueuesResource(AsyncAPIResource): @cached_property @@ -671,6 +718,52 @@ async def get( cast_to=cast(Type[Optional[Queue]], ResultWrapper[Queue]), ) + async def get_metrics( + self, + queue_id: str, + *, + 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[QueueGetMetricsResponse]: + """Return best-effort metrics for a queue. + + Values may be approximate due to the + distributed nature of queues. + + Args: + account_id: A Resource identifier. + + queue_id: A Resource identifier. + + 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 queue_id: + raise ValueError(f"Expected a non-empty value for `queue_id` but received {queue_id!r}") + return await self._get( + path_template("/accounts/{account_id}/queues/{queue_id}/metrics", account_id=account_id, queue_id=queue_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[Optional[QueueGetMetricsResponse]]._unwrapper, + ), + cast_to=cast(Type[Optional[QueueGetMetricsResponse]], ResultWrapper[QueueGetMetricsResponse]), + ) + class QueuesResourceWithRawResponse: def __init__(self, queues: QueuesResource) -> None: @@ -694,6 +787,9 @@ def __init__(self, queues: QueuesResource) -> None: self.get = to_raw_response_wrapper( queues.get, ) + self.get_metrics = to_raw_response_wrapper( + queues.get_metrics, + ) @cached_property def messages(self) -> MessagesResourceWithRawResponse: @@ -734,6 +830,9 @@ def __init__(self, queues: AsyncQueuesResource) -> None: self.get = async_to_raw_response_wrapper( queues.get, ) + self.get_metrics = async_to_raw_response_wrapper( + queues.get_metrics, + ) @cached_property def messages(self) -> AsyncMessagesResourceWithRawResponse: @@ -774,6 +873,9 @@ def __init__(self, queues: QueuesResource) -> None: self.get = to_streamed_response_wrapper( queues.get, ) + self.get_metrics = to_streamed_response_wrapper( + queues.get_metrics, + ) @cached_property def messages(self) -> MessagesResourceWithStreamingResponse: @@ -814,6 +916,9 @@ def __init__(self, queues: AsyncQueuesResource) -> None: self.get = async_to_streamed_response_wrapper( queues.get, ) + self.get_metrics = async_to_streamed_response_wrapper( + queues.get_metrics, + ) @cached_property def messages(self) -> AsyncMessagesResourceWithStreamingResponse: diff --git a/src/cloudflare/types/queues/__init__.py b/src/cloudflare/types/queues/__init__.py index 2d25382356d..af80c330eab 100644 --- a/src/cloudflare/types/queues/__init__.py +++ b/src/cloudflare/types/queues/__init__.py @@ -23,6 +23,7 @@ from .subscription_list_params import SubscriptionListParams as SubscriptionListParams from .subscription_get_response import SubscriptionGetResponse as SubscriptionGetResponse from .message_bulk_push_response import MessageBulkPushResponse as MessageBulkPushResponse +from .queue_get_metrics_response import QueueGetMetricsResponse as QueueGetMetricsResponse from .subscription_create_params import SubscriptionCreateParams as SubscriptionCreateParams from .subscription_list_response import SubscriptionListResponse as SubscriptionListResponse from .subscription_update_params import SubscriptionUpdateParams as SubscriptionUpdateParams diff --git a/src/cloudflare/types/queues/queue_get_metrics_response.py b/src/cloudflare/types/queues/queue_get_metrics_response.py new file mode 100644 index 00000000000..6d60e49a45b --- /dev/null +++ b/src/cloudflare/types/queues/queue_get_metrics_response.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["QueueGetMetricsResponse"] + + +class QueueGetMetricsResponse(BaseModel): + """Best-effort metrics for the queue. + + Values may be approximate due to the distributed nature of queues. + """ + + backlog_bytes: float + """The size in bytes of unacknowledged messages in the queue.""" + + backlog_count: float + """The number of unacknowledged messages in the queue.""" + + oldest_message_timestamp_ms: float + """Unix timestamp in milliseconds of the oldest unacknowledged message in the + queue. + + Returns 0 if unknown. + """ diff --git a/tests/api_resources/test_queues.py b/tests/api_resources/test_queues.py index e337e5aae5c..d2806191967 100644 --- a/tests/api_resources/test_queues.py +++ b/tests/api_resources/test_queues.py @@ -13,6 +13,7 @@ from cloudflare.types.queues import ( Queue, QueueDeleteResponse, + QueueGetMetricsResponse, ) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -321,6 +322,54 @@ def test_path_params_get(self, client: Cloudflare) -> None: account_id="023e105f4ecef8ad9ca31a8372d0c353", ) + @parametrize + def test_method_get_metrics(self, client: Cloudflare) -> None: + queue = client.queues.get_metrics( + queue_id="023e105f4ecef8ad9ca31a8372d0c353", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + assert_matches_type(Optional[QueueGetMetricsResponse], queue, path=["response"]) + + @parametrize + def test_raw_response_get_metrics(self, client: Cloudflare) -> None: + response = client.queues.with_raw_response.get_metrics( + queue_id="023e105f4ecef8ad9ca31a8372d0c353", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + queue = response.parse() + assert_matches_type(Optional[QueueGetMetricsResponse], queue, path=["response"]) + + @parametrize + def test_streaming_response_get_metrics(self, client: Cloudflare) -> None: + with client.queues.with_streaming_response.get_metrics( + queue_id="023e105f4ecef8ad9ca31a8372d0c353", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + queue = response.parse() + assert_matches_type(Optional[QueueGetMetricsResponse], queue, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_get_metrics(self, client: Cloudflare) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): + client.queues.with_raw_response.get_metrics( + queue_id="023e105f4ecef8ad9ca31a8372d0c353", + account_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `queue_id` but received ''"): + client.queues.with_raw_response.get_metrics( + queue_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + class TestAsyncQueues: parametrize = pytest.mark.parametrize( @@ -626,3 +675,51 @@ async def test_path_params_get(self, async_client: AsyncCloudflare) -> None: queue_id="", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) + + @parametrize + async def test_method_get_metrics(self, async_client: AsyncCloudflare) -> None: + queue = await async_client.queues.get_metrics( + queue_id="023e105f4ecef8ad9ca31a8372d0c353", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + assert_matches_type(Optional[QueueGetMetricsResponse], queue, path=["response"]) + + @parametrize + async def test_raw_response_get_metrics(self, async_client: AsyncCloudflare) -> None: + response = await async_client.queues.with_raw_response.get_metrics( + queue_id="023e105f4ecef8ad9ca31a8372d0c353", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + queue = await response.parse() + assert_matches_type(Optional[QueueGetMetricsResponse], queue, path=["response"]) + + @parametrize + async def test_streaming_response_get_metrics(self, async_client: AsyncCloudflare) -> None: + async with async_client.queues.with_streaming_response.get_metrics( + queue_id="023e105f4ecef8ad9ca31a8372d0c353", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + queue = await response.parse() + assert_matches_type(Optional[QueueGetMetricsResponse], queue, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_get_metrics(self, async_client: AsyncCloudflare) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): + await async_client.queues.with_raw_response.get_metrics( + queue_id="023e105f4ecef8ad9ca31a8372d0c353", + account_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `queue_id` but received ''"): + await async_client.queues.with_raw_response.get_metrics( + queue_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) From 2b3061a1f929bfafe87d96e1eee14d501e765c3e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 24 Apr 2026 19:59:23 +0000 Subject: [PATCH 02/45] feat: chore: skip failing tests for dns.records and workers.beta.workers * chore: skip failing tests for dns.records and workers.beta.workers - dns.records.scan_review: mock server returns invalid response data - dns.records.scan_list: mock server returns invalid response data - workers.beta.workers.create: HTTP 400 error from prism (missing required body properties) - workers.beta.workers.update: HTTP 400 error from prism (missing required body properties) Failures observed in both Python and TypeScript SDK test suites. --- .stats.yml | 2 +- tests/api_resources/dns/test_records.py | 18 +++++++++++++++++ .../workers/beta/test_workers.py | 20 +++++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 1b0284614f3..f772a7697f3 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 2195 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-0ce49e6bb0d3819f135b9a567b661205fdf5df21cff157eab2b7abd7b5b50347.yml openapi_spec_hash: 512a5bb3a32860590c8949765605d65a -config_hash: 6f813d0ef66c7bf6daf8e0df5638e7a3 +config_hash: a476425ca18fdfc75a509dd60a1461b7 diff --git a/tests/api_resources/dns/test_records.py b/tests/api_resources/dns/test_records.py index 947da97ff7c..9c213e26706 100644 --- a/tests/api_resources/dns/test_records.py +++ b/tests/api_resources/dns/test_records.py @@ -5866,6 +5866,7 @@ def test_path_params_scan(self, client: Cloudflare) -> None: body={}, ) + @pytest.mark.skip(reason="mock server returns invalid data") @parametrize def test_method_scan_list(self, client: Cloudflare) -> None: record = client.dns.records.scan_list( @@ -5873,6 +5874,7 @@ def test_method_scan_list(self, client: Cloudflare) -> None: ) assert_matches_type(SyncSinglePage[RecordResponse], record, path=["response"]) + @pytest.mark.skip(reason="mock server returns invalid data") @parametrize def test_raw_response_scan_list(self, client: Cloudflare) -> None: response = client.dns.records.with_raw_response.scan_list( @@ -5884,6 +5886,7 @@ def test_raw_response_scan_list(self, client: Cloudflare) -> None: record = response.parse() assert_matches_type(SyncSinglePage[RecordResponse], record, path=["response"]) + @pytest.mark.skip(reason="mock server returns invalid data") @parametrize def test_streaming_response_scan_list(self, client: Cloudflare) -> None: with client.dns.records.with_streaming_response.scan_list( @@ -5897,6 +5900,7 @@ def test_streaming_response_scan_list(self, client: Cloudflare) -> None: assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="mock server returns invalid data") @parametrize def test_path_params_scan_list(self, client: Cloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `zone_id` but received ''"): @@ -5904,6 +5908,7 @@ def test_path_params_scan_list(self, client: Cloudflare) -> None: zone_id="", ) + @pytest.mark.skip(reason="mock server returns invalid data") @parametrize def test_method_scan_review(self, client: Cloudflare) -> None: record = client.dns.records.scan_review( @@ -5911,6 +5916,7 @@ def test_method_scan_review(self, client: Cloudflare) -> None: ) assert_matches_type(Optional[RecordScanReviewResponse], record, path=["response"]) + @pytest.mark.skip(reason="mock server returns invalid data") @parametrize def test_method_scan_review_with_all_params(self, client: Cloudflare) -> None: record = client.dns.records.scan_review( @@ -5935,6 +5941,7 @@ def test_method_scan_review_with_all_params(self, client: Cloudflare) -> None: ) assert_matches_type(Optional[RecordScanReviewResponse], record, path=["response"]) + @pytest.mark.skip(reason="mock server returns invalid data") @parametrize def test_raw_response_scan_review(self, client: Cloudflare) -> None: response = client.dns.records.with_raw_response.scan_review( @@ -5946,6 +5953,7 @@ def test_raw_response_scan_review(self, client: Cloudflare) -> None: record = response.parse() assert_matches_type(Optional[RecordScanReviewResponse], record, path=["response"]) + @pytest.mark.skip(reason="mock server returns invalid data") @parametrize def test_streaming_response_scan_review(self, client: Cloudflare) -> None: with client.dns.records.with_streaming_response.scan_review( @@ -5959,6 +5967,7 @@ def test_streaming_response_scan_review(self, client: Cloudflare) -> None: assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="mock server returns invalid data") @parametrize def test_path_params_scan_review(self, client: Cloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `zone_id` but received ''"): @@ -11848,6 +11857,7 @@ async def test_path_params_scan(self, async_client: AsyncCloudflare) -> None: body={}, ) + @pytest.mark.skip(reason="mock server returns invalid data") @parametrize async def test_method_scan_list(self, async_client: AsyncCloudflare) -> None: record = await async_client.dns.records.scan_list( @@ -11855,6 +11865,7 @@ async def test_method_scan_list(self, async_client: AsyncCloudflare) -> None: ) assert_matches_type(AsyncSinglePage[RecordResponse], record, path=["response"]) + @pytest.mark.skip(reason="mock server returns invalid data") @parametrize async def test_raw_response_scan_list(self, async_client: AsyncCloudflare) -> None: response = await async_client.dns.records.with_raw_response.scan_list( @@ -11866,6 +11877,7 @@ async def test_raw_response_scan_list(self, async_client: AsyncCloudflare) -> No record = await response.parse() assert_matches_type(AsyncSinglePage[RecordResponse], record, path=["response"]) + @pytest.mark.skip(reason="mock server returns invalid data") @parametrize async def test_streaming_response_scan_list(self, async_client: AsyncCloudflare) -> None: async with async_client.dns.records.with_streaming_response.scan_list( @@ -11879,6 +11891,7 @@ async def test_streaming_response_scan_list(self, async_client: AsyncCloudflare) assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="mock server returns invalid data") @parametrize async def test_path_params_scan_list(self, async_client: AsyncCloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `zone_id` but received ''"): @@ -11886,6 +11899,7 @@ async def test_path_params_scan_list(self, async_client: AsyncCloudflare) -> Non zone_id="", ) + @pytest.mark.skip(reason="mock server returns invalid data") @parametrize async def test_method_scan_review(self, async_client: AsyncCloudflare) -> None: record = await async_client.dns.records.scan_review( @@ -11893,6 +11907,7 @@ async def test_method_scan_review(self, async_client: AsyncCloudflare) -> None: ) assert_matches_type(Optional[RecordScanReviewResponse], record, path=["response"]) + @pytest.mark.skip(reason="mock server returns invalid data") @parametrize async def test_method_scan_review_with_all_params(self, async_client: AsyncCloudflare) -> None: record = await async_client.dns.records.scan_review( @@ -11917,6 +11932,7 @@ async def test_method_scan_review_with_all_params(self, async_client: AsyncCloud ) assert_matches_type(Optional[RecordScanReviewResponse], record, path=["response"]) + @pytest.mark.skip(reason="mock server returns invalid data") @parametrize async def test_raw_response_scan_review(self, async_client: AsyncCloudflare) -> None: response = await async_client.dns.records.with_raw_response.scan_review( @@ -11928,6 +11944,7 @@ async def test_raw_response_scan_review(self, async_client: AsyncCloudflare) -> record = await response.parse() assert_matches_type(Optional[RecordScanReviewResponse], record, path=["response"]) + @pytest.mark.skip(reason="mock server returns invalid data") @parametrize async def test_streaming_response_scan_review(self, async_client: AsyncCloudflare) -> None: async with async_client.dns.records.with_streaming_response.scan_review( @@ -11941,6 +11958,7 @@ async def test_streaming_response_scan_review(self, async_client: AsyncCloudflar assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="mock server returns invalid data") @parametrize async def test_path_params_scan_review(self, async_client: AsyncCloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `zone_id` but received ''"): diff --git a/tests/api_resources/workers/beta/test_workers.py b/tests/api_resources/workers/beta/test_workers.py index 101ed4f8cae..64ee91aac7e 100644 --- a/tests/api_resources/workers/beta/test_workers.py +++ b/tests/api_resources/workers/beta/test_workers.py @@ -21,6 +21,7 @@ class TestWorkers: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize def test_method_create(self, client: Cloudflare) -> None: worker = client.workers.beta.workers.create( @@ -29,6 +30,7 @@ def test_method_create(self, client: Cloudflare) -> None: ) assert_matches_type(Worker, worker, path=["response"]) + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize def test_method_create_with_all_params(self, client: Cloudflare) -> None: worker = client.workers.beta.workers.create( @@ -61,6 +63,7 @@ def test_method_create_with_all_params(self, client: Cloudflare) -> None: ) assert_matches_type(Worker, worker, path=["response"]) + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize def test_raw_response_create(self, client: Cloudflare) -> None: response = client.workers.beta.workers.with_raw_response.create( @@ -73,6 +76,7 @@ def test_raw_response_create(self, client: Cloudflare) -> None: worker = response.parse() assert_matches_type(Worker, worker, path=["response"]) + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize def test_streaming_response_create(self, client: Cloudflare) -> None: with client.workers.beta.workers.with_streaming_response.create( @@ -87,6 +91,7 @@ def test_streaming_response_create(self, client: Cloudflare) -> None: assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="HTTP 400 error from prism") @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 ''"): @@ -95,6 +100,7 @@ def test_path_params_create(self, client: Cloudflare) -> None: name="my-worker", ) + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize def test_method_update(self, client: Cloudflare) -> None: worker = client.workers.beta.workers.update( @@ -104,6 +110,7 @@ def test_method_update(self, client: Cloudflare) -> None: ) assert_matches_type(Worker, worker, path=["response"]) + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize def test_method_update_with_all_params(self, client: Cloudflare) -> None: worker = client.workers.beta.workers.update( @@ -137,6 +144,7 @@ def test_method_update_with_all_params(self, client: Cloudflare) -> None: ) assert_matches_type(Worker, worker, path=["response"]) + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize def test_raw_response_update(self, client: Cloudflare) -> None: response = client.workers.beta.workers.with_raw_response.update( @@ -150,6 +158,7 @@ def test_raw_response_update(self, client: Cloudflare) -> None: worker = response.parse() assert_matches_type(Worker, worker, path=["response"]) + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize def test_streaming_response_update(self, client: Cloudflare) -> None: with client.workers.beta.workers.with_streaming_response.update( @@ -165,6 +174,7 @@ def test_streaming_response_update(self, client: Cloudflare) -> None: assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize def test_path_params_update(self, client: Cloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): @@ -443,6 +453,7 @@ class TestAsyncWorkers: "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] ) + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize async def test_method_create(self, async_client: AsyncCloudflare) -> None: worker = await async_client.workers.beta.workers.create( @@ -451,6 +462,7 @@ async def test_method_create(self, async_client: AsyncCloudflare) -> None: ) assert_matches_type(Worker, worker, path=["response"]) + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize async def test_method_create_with_all_params(self, async_client: AsyncCloudflare) -> None: worker = await async_client.workers.beta.workers.create( @@ -483,6 +495,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncCloudflare ) assert_matches_type(Worker, worker, path=["response"]) + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize async def test_raw_response_create(self, async_client: AsyncCloudflare) -> None: response = await async_client.workers.beta.workers.with_raw_response.create( @@ -495,6 +508,7 @@ async def test_raw_response_create(self, async_client: AsyncCloudflare) -> None: worker = await response.parse() assert_matches_type(Worker, worker, path=["response"]) + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize async def test_streaming_response_create(self, async_client: AsyncCloudflare) -> None: async with async_client.workers.beta.workers.with_streaming_response.create( @@ -509,6 +523,7 @@ async def test_streaming_response_create(self, async_client: AsyncCloudflare) -> assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="HTTP 400 error from prism") @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 ''"): @@ -517,6 +532,7 @@ async def test_path_params_create(self, async_client: AsyncCloudflare) -> None: name="my-worker", ) + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize async def test_method_update(self, async_client: AsyncCloudflare) -> None: worker = await async_client.workers.beta.workers.update( @@ -526,6 +542,7 @@ async def test_method_update(self, async_client: AsyncCloudflare) -> None: ) assert_matches_type(Worker, worker, path=["response"]) + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize async def test_method_update_with_all_params(self, async_client: AsyncCloudflare) -> None: worker = await async_client.workers.beta.workers.update( @@ -559,6 +576,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncCloudflare ) assert_matches_type(Worker, worker, path=["response"]) + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize async def test_raw_response_update(self, async_client: AsyncCloudflare) -> None: response = await async_client.workers.beta.workers.with_raw_response.update( @@ -572,6 +590,7 @@ async def test_raw_response_update(self, async_client: AsyncCloudflare) -> None: worker = await response.parse() assert_matches_type(Worker, worker, path=["response"]) + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize async def test_streaming_response_update(self, async_client: AsyncCloudflare) -> None: async with async_client.workers.beta.workers.with_streaming_response.update( @@ -587,6 +606,7 @@ async def test_streaming_response_update(self, async_client: AsyncCloudflare) -> assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize async def test_path_params_update(self, async_client: AsyncCloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): From 6b156d95f505e2550d949a606c657827ea7a2688 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 27 Apr 2026 16:24:24 +0000 Subject: [PATCH 03/45] chore(api): update composite API spec --- .stats.yml | 6 +- src/cloudflare/resources/billing/usage.py | 6 +- .../resources/email_security/api.md | 91 +--- .../email_security/investigate/__init__.py | 56 --- .../email_security/investigate/detections.py | 199 --------- .../email_security/investigate/investigate.py | 396 ++--------------- .../email_security/investigate/move.py | 157 +------ .../email_security/investigate/preview.py | 143 +----- .../email_security/investigate/raw.py | 197 --------- .../email_security/investigate/reclassify.py | 238 ---------- .../email_security/investigate/release.py | 18 +- .../email_security/investigate/trace.py | 210 --------- .../email_security/phishguard/reports.py | 36 +- .../email_security/settings/allow_policies.py | 352 ++++++++++----- .../email_security/settings/block_senders.py | 220 ++++++---- .../email_security/settings/domains.py | 285 +++++------- .../settings/impersonation_registry.py | 415 +++--------------- .../settings/trusted_domains.py | 390 +++++++--------- .../resources/email_security/submissions.py | 40 +- .../workers/observability/telemetry.py | 120 ++--- .../types/email_security/__init__.py | 2 - .../email_security/investigate/__init__.py | 8 - .../investigate/detection_get_response.py | 152 ------- .../investigate/move_bulk_params.py | 9 +- .../investigate/move_bulk_response.py | 18 +- .../investigate/move_create_params.py | 22 - .../investigate/move_create_response.py | 33 -- .../investigate/preview_create_params.py | 10 +- .../investigate/preview_get_response.py | 10 - .../investigate/raw_get_response.py | 10 - .../investigate/reclassify_create_params.py | 25 -- .../investigate/release_bulk_params.py | 3 +- .../investigate/release_bulk_response.py | 7 +- .../investigate/trace_get_params.py | 18 - .../investigate/trace_get_response.py | 42 -- .../email_security/investigate_get_params.py | 18 - .../investigate_get_response.py | 188 -------- .../email_security/investigate_list_params.py | 64 +-- .../investigate_list_response.py | 59 ++- .../phishguard/report_list_params.py | 8 +- .../phishguard/report_list_response.py | 18 +- .../types/email_security/settings/__init__.py | 7 - .../settings/allow_policy_create_params.py | 30 +- .../settings/allow_policy_create_response.py | 61 ++- .../settings/allow_policy_delete_response.py | 4 +- .../settings/allow_policy_edit_params.py | 48 +- .../settings/allow_policy_edit_response.py | 61 ++- .../settings/allow_policy_get_response.py | 61 ++- .../settings/allow_policy_list_params.py | 37 +- .../settings/allow_policy_list_response.py | 61 ++- .../settings/block_sender_create_params.py | 6 +- .../settings/block_sender_create_response.py | 25 +- .../settings/block_sender_delete_response.py | 4 +- .../settings/block_sender_edit_params.py | 12 +- .../settings/block_sender_edit_response.py | 25 +- .../settings/block_sender_get_response.py | 25 +- .../settings/block_sender_list_params.py | 16 +- .../settings/block_sender_list_response.py | 25 +- .../settings/domain_bulk_delete_response.py | 10 - .../settings/domain_delete_response.py | 4 +- .../settings/domain_edit_params.py | 10 +- .../settings/domain_edit_response.py | 71 +-- .../settings/domain_get_response.py | 71 +-- .../settings/domain_list_params.py | 25 +- .../settings/domain_list_response.py | 71 +-- .../impersonation_registry_create_params.py | 15 +- .../impersonation_registry_create_response.py | 31 +- .../impersonation_registry_delete_response.py | 9 - .../impersonation_registry_edit_params.py | 19 - .../impersonation_registry_edit_response.py | 32 -- .../impersonation_registry_get_response.py | 32 -- .../impersonation_registry_list_params.py | 14 +- .../impersonation_registry_list_response.py | 31 +- .../settings/trusted_domain_create_params.py | 40 +- .../trusted_domain_create_response.py | 54 +-- .../trusted_domain_delete_response.py | 4 +- .../settings/trusted_domain_edit_params.py | 5 +- .../settings/trusted_domain_edit_response.py | 23 +- .../settings/trusted_domain_get_response.py | 23 +- .../settings/trusted_domain_list_params.py | 22 +- .../settings/trusted_domain_list_response.py | 23 +- .../email_security/submission_list_params.py | 15 +- .../submission_list_response.py | 73 +-- .../buckets/domains/custom_create_response.py | 3 + .../types/workers/beta/workers/version.py | 7 + .../beta/workers/version_create_params.py | 7 + .../observability/telemetry_keys_params.py | 135 +++++- .../observability/telemetry_query_params.py | 287 +++++++++--- .../observability/telemetry_query_response.py | 289 ++++++++++-- .../observability/telemetry_values_params.py | 141 +++++- .../types/workers/script_update_params.py | 7 + .../script_and_version_setting_edit_params.py | 7 + ...cript_and_version_setting_edit_response.py | 7 + ...script_and_version_setting_get_response.py | 7 + .../workers/scripts/version_create_params.py | 7 + .../scripts/version_create_response.py | 7 + .../workers/scripts/version_get_response.py | 7 + .../namespaces/script_update_params.py | 7 + .../scripts/binding_get_response.py | 7 + .../namespaces/scripts/setting_edit_params.py | 7 + .../scripts/setting_edit_response.py | 7 + .../scripts/setting_get_response.py | 7 + .../investigate/test_detections.py | 120 ----- .../email_security/investigate/test_move.py | 135 +----- .../investigate/test_preview.py | 116 +---- .../email_security/investigate/test_raw.py | 120 ----- .../investigate/test_reclassify.py | 153 ------- .../investigate/test_release.py | 16 +- .../email_security/investigate/test_trace.py | 138 ------ .../settings/test_allow_policies.py | 182 +++++--- .../settings/test_block_senders.py | 166 ++++--- .../email_security/settings/test_domains.py | 219 ++++----- .../settings/test_impersonation_registry.py | 377 +++------------- .../settings/test_trusted_domains.py | 338 +++++--------- .../email_security/test_investigate.py | 127 +----- .../email_security/test_submissions.py | 6 +- .../workers/observability/test_telemetry.py | 48 +- 117 files changed, 3006 insertions(+), 5742 deletions(-) delete mode 100644 src/cloudflare/resources/email_security/investigate/detections.py delete mode 100644 src/cloudflare/resources/email_security/investigate/raw.py delete mode 100644 src/cloudflare/resources/email_security/investigate/reclassify.py delete mode 100644 src/cloudflare/resources/email_security/investigate/trace.py delete mode 100644 src/cloudflare/types/email_security/investigate/detection_get_response.py delete mode 100644 src/cloudflare/types/email_security/investigate/move_create_params.py delete mode 100644 src/cloudflare/types/email_security/investigate/move_create_response.py delete mode 100644 src/cloudflare/types/email_security/investigate/preview_get_response.py delete mode 100644 src/cloudflare/types/email_security/investigate/raw_get_response.py delete mode 100644 src/cloudflare/types/email_security/investigate/reclassify_create_params.py delete mode 100644 src/cloudflare/types/email_security/investigate/trace_get_params.py delete mode 100644 src/cloudflare/types/email_security/investigate/trace_get_response.py delete mode 100644 src/cloudflare/types/email_security/investigate_get_params.py delete mode 100644 src/cloudflare/types/email_security/investigate_get_response.py delete mode 100644 src/cloudflare/types/email_security/settings/domain_bulk_delete_response.py delete mode 100644 src/cloudflare/types/email_security/settings/impersonation_registry_delete_response.py delete mode 100644 src/cloudflare/types/email_security/settings/impersonation_registry_edit_params.py delete mode 100644 src/cloudflare/types/email_security/settings/impersonation_registry_edit_response.py delete mode 100644 src/cloudflare/types/email_security/settings/impersonation_registry_get_response.py delete mode 100644 tests/api_resources/email_security/investigate/test_detections.py delete mode 100644 tests/api_resources/email_security/investigate/test_raw.py delete mode 100644 tests/api_resources/email_security/investigate/test_reclassify.py delete mode 100644 tests/api_resources/email_security/investigate/test_trace.py diff --git a/.stats.yml b/.stats.yml index f772a7697f3..aae4f837354 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 2195 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-0ce49e6bb0d3819f135b9a567b661205fdf5df21cff157eab2b7abd7b5b50347.yml -openapi_spec_hash: 512a5bb3a32860590c8949765605d65a +configured_endpoints: 2184 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a085fe9423a471ff6a541742d5f268cc73a5a641321c8a280eec22ad5745fa52.yml +openapi_spec_hash: 8549e8a8242264b6668f327f37b307e6 config_hash: a476425ca18fdfc75a509dd60a1461b7 diff --git a/src/cloudflare/resources/billing/usage.py b/src/cloudflare/resources/billing/usage.py index d847aea692d..0071a8d4315 100644 --- a/src/cloudflare/resources/billing/usage.py +++ b/src/cloudflare/resources/billing/usage.py @@ -62,7 +62,8 @@ def paygo( When no query parameters are provided, returns usage for the current billing period. This - endpoint is currently in beta and access is restricted to select accounts. + endpoint is currently in alpha and access is restricted to select accounts. + While in alpha, the endpoint may get breaking changes. Args: account_id: Represents a Cloudflare resource identifier tag. @@ -138,7 +139,8 @@ async def paygo( When no query parameters are provided, returns usage for the current billing period. This - endpoint is currently in beta and access is restricted to select accounts. + endpoint is currently in alpha and access is restricted to select accounts. + While in alpha, the endpoint may get breaking changes. Args: account_id: Represents a Cloudflare resource identifier tag. diff --git a/src/cloudflare/resources/email_security/api.md b/src/cloudflare/resources/email_security/api.md index 53e335ba90a..0584be64fa9 100644 --- a/src/cloudflare/resources/email_security/api.md +++ b/src/cloudflare/resources/email_security/api.md @@ -5,82 +5,37 @@ Types: ```python -from cloudflare.types.email_security import InvestigateListResponse, InvestigateGetResponse +from cloudflare.types.email_security import InvestigateListResponse ``` Methods: - client.email_security.investigate.list(\*, account_id, \*\*params) -> SyncV4PagePaginationArray[InvestigateListResponse] -- client.email_security.investigate.get(postfix_id, \*, account_id, \*\*params) -> InvestigateGetResponse - -### Detections - -Types: - -```python -from cloudflare.types.email_security.investigate import DetectionGetResponse -``` - -Methods: - -- client.email_security.investigate.detections.get(postfix_id, \*, account_id) -> DetectionGetResponse ### Preview Types: ```python -from cloudflare.types.email_security.investigate import PreviewCreateResponse, PreviewGetResponse +from cloudflare.types.email_security.investigate import PreviewCreateResponse ``` Methods: - client.email_security.investigate.preview.create(\*, account_id, \*\*params) -> PreviewCreateResponse -- client.email_security.investigate.preview.get(postfix_id, \*, account_id) -> PreviewGetResponse - -### Raw - -Types: - -```python -from cloudflare.types.email_security.investigate import RawGetResponse -``` - -Methods: - -- client.email_security.investigate.raw.get(postfix_id, \*, account_id) -> RawGetResponse - -### Trace - -Types: - -```python -from cloudflare.types.email_security.investigate import TraceGetResponse -``` - -Methods: - -- client.email_security.investigate.trace.get(postfix_id, \*, account_id, \*\*params) -> TraceGetResponse ### Move Types: ```python -from cloudflare.types.email_security.investigate import MoveCreateResponse, MoveBulkResponse +from cloudflare.types.email_security.investigate import MoveBulkResponse ``` Methods: -- client.email_security.investigate.move.create(postfix_id, \*, account_id, \*\*params) -> MoveCreateResponse - client.email_security.investigate.move.bulk(\*, account_id, \*\*params) -> SyncSinglePage[MoveBulkResponse] -### Reclassify - -Methods: - -- client.email_security.investigate.reclassify.create(postfix_id, \*, account_id, \*\*params) -> object - ### Release Types: @@ -125,11 +80,11 @@ from cloudflare.types.email_security.settings import ( Methods: -- client.email_security.settings.allow_policies.create(\*, account_id, \*\*params) -> AllowPolicyCreateResponse +- client.email_security.settings.allow_policies.create(\*, account_id, \*\*params) -> Optional[AllowPolicyCreateResponse] - client.email_security.settings.allow_policies.list(\*, account_id, \*\*params) -> SyncV4PagePaginationArray[AllowPolicyListResponse] -- client.email_security.settings.allow_policies.delete(policy_id, \*, account_id) -> AllowPolicyDeleteResponse -- client.email_security.settings.allow_policies.edit(policy_id, \*, account_id, \*\*params) -> AllowPolicyEditResponse -- client.email_security.settings.allow_policies.get(policy_id, \*, account_id) -> AllowPolicyGetResponse +- client.email_security.settings.allow_policies.delete(policy_id, \*, account_id) -> Optional[AllowPolicyDeleteResponse] +- client.email_security.settings.allow_policies.edit(policy_id, \*, account_id, \*\*params) -> Optional[AllowPolicyEditResponse] +- client.email_security.settings.allow_policies.get(policy_id, \*, account_id) -> Optional[AllowPolicyGetResponse] ### BlockSenders @@ -147,11 +102,11 @@ from cloudflare.types.email_security.settings import ( Methods: -- client.email_security.settings.block_senders.create(\*, account_id, \*\*params) -> BlockSenderCreateResponse +- client.email_security.settings.block_senders.create(\*, account_id, \*\*params) -> Optional[BlockSenderCreateResponse] - client.email_security.settings.block_senders.list(\*, account_id, \*\*params) -> SyncV4PagePaginationArray[BlockSenderListResponse] -- client.email_security.settings.block_senders.delete(pattern_id, \*, account_id) -> BlockSenderDeleteResponse -- client.email_security.settings.block_senders.edit(pattern_id, \*, account_id, \*\*params) -> BlockSenderEditResponse -- client.email_security.settings.block_senders.get(pattern_id, \*, account_id) -> BlockSenderGetResponse +- client.email_security.settings.block_senders.delete(pattern_id, \*, account_id) -> Optional[BlockSenderDeleteResponse] +- client.email_security.settings.block_senders.edit(pattern_id, \*, account_id, \*\*params) -> Optional[BlockSenderEditResponse] +- client.email_security.settings.block_senders.get(pattern_id, \*, account_id) -> Optional[BlockSenderGetResponse] ### Domains @@ -161,7 +116,6 @@ Types: from cloudflare.types.email_security.settings import ( DomainListResponse, DomainDeleteResponse, - DomainBulkDeleteResponse, DomainEditResponse, DomainGetResponse, ) @@ -170,10 +124,9 @@ from cloudflare.types.email_security.settings import ( Methods: - client.email_security.settings.domains.list(\*, account_id, \*\*params) -> SyncV4PagePaginationArray[DomainListResponse] -- client.email_security.settings.domains.delete(domain_id, \*, account_id) -> DomainDeleteResponse -- client.email_security.settings.domains.bulk_delete(\*, account_id) -> SyncSinglePage[DomainBulkDeleteResponse] -- client.email_security.settings.domains.edit(domain_id, \*, account_id, \*\*params) -> DomainEditResponse -- client.email_security.settings.domains.get(domain_id, \*, account_id) -> DomainGetResponse +- client.email_security.settings.domains.delete(domain_id, \*, account_id) -> Optional[DomainDeleteResponse] +- client.email_security.settings.domains.edit(domain_id, \*, account_id, \*\*params) -> Optional[DomainEditResponse] +- client.email_security.settings.domains.get(domain_id, \*, account_id) -> Optional[DomainGetResponse] ### ImpersonationRegistry @@ -183,19 +136,13 @@ Types: from cloudflare.types.email_security.settings import ( ImpersonationRegistryCreateResponse, ImpersonationRegistryListResponse, - ImpersonationRegistryDeleteResponse, - ImpersonationRegistryEditResponse, - ImpersonationRegistryGetResponse, ) ``` Methods: -- client.email_security.settings.impersonation_registry.create(\*, account_id, \*\*params) -> ImpersonationRegistryCreateResponse +- client.email_security.settings.impersonation_registry.create(\*, account_id, \*\*params) -> Optional[ImpersonationRegistryCreateResponse] - client.email_security.settings.impersonation_registry.list(\*, account_id, \*\*params) -> SyncV4PagePaginationArray[ImpersonationRegistryListResponse] -- client.email_security.settings.impersonation_registry.delete(display_name_id, \*, account_id) -> ImpersonationRegistryDeleteResponse -- client.email_security.settings.impersonation_registry.edit(display_name_id, \*, account_id, \*\*params) -> ImpersonationRegistryEditResponse -- client.email_security.settings.impersonation_registry.get(display_name_id, \*, account_id) -> ImpersonationRegistryGetResponse ### TrustedDomains @@ -213,11 +160,11 @@ from cloudflare.types.email_security.settings import ( Methods: -- client.email_security.settings.trusted_domains.create(\*, account_id, \*\*params) -> TrustedDomainCreateResponse +- client.email_security.settings.trusted_domains.create(\*, account_id, \*\*params) -> Optional[TrustedDomainCreateResponse] - client.email_security.settings.trusted_domains.list(\*, account_id, \*\*params) -> SyncV4PagePaginationArray[TrustedDomainListResponse] -- client.email_security.settings.trusted_domains.delete(trusted_domain_id, \*, account_id) -> TrustedDomainDeleteResponse -- client.email_security.settings.trusted_domains.edit(trusted_domain_id, \*, account_id, \*\*params) -> TrustedDomainEditResponse -- client.email_security.settings.trusted_domains.get(trusted_domain_id, \*, account_id) -> TrustedDomainGetResponse +- client.email_security.settings.trusted_domains.delete(trusted_domain_id, \*, account_id) -> Optional[TrustedDomainDeleteResponse] +- client.email_security.settings.trusted_domains.edit(trusted_domain_id, \*, account_id, \*\*params) -> Optional[TrustedDomainEditResponse] +- client.email_security.settings.trusted_domains.get(trusted_domain_id, \*, account_id) -> Optional[TrustedDomainGetResponse] ## Submissions diff --git a/src/cloudflare/resources/email_security/investigate/__init__.py b/src/cloudflare/resources/email_security/investigate/__init__.py index 5b206205771..7de4ad936c0 100644 --- a/src/cloudflare/resources/email_security/investigate/__init__.py +++ b/src/cloudflare/resources/email_security/investigate/__init__.py @@ -1,13 +1,5 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from .raw import ( - RawResource, - AsyncRawResource, - RawResourceWithRawResponse, - AsyncRawResourceWithRawResponse, - RawResourceWithStreamingResponse, - AsyncRawResourceWithStreamingResponse, -) from .move import ( MoveResource, AsyncMoveResource, @@ -16,14 +8,6 @@ MoveResourceWithStreamingResponse, AsyncMoveResourceWithStreamingResponse, ) -from .trace import ( - TraceResource, - AsyncTraceResource, - TraceResourceWithRawResponse, - AsyncTraceResourceWithRawResponse, - TraceResourceWithStreamingResponse, - AsyncTraceResourceWithStreamingResponse, -) from .preview import ( PreviewResource, AsyncPreviewResource, @@ -40,22 +24,6 @@ ReleaseResourceWithStreamingResponse, AsyncReleaseResourceWithStreamingResponse, ) -from .detections import ( - DetectionsResource, - AsyncDetectionsResource, - DetectionsResourceWithRawResponse, - AsyncDetectionsResourceWithRawResponse, - DetectionsResourceWithStreamingResponse, - AsyncDetectionsResourceWithStreamingResponse, -) -from .reclassify import ( - ReclassifyResource, - AsyncReclassifyResource, - ReclassifyResourceWithRawResponse, - AsyncReclassifyResourceWithRawResponse, - ReclassifyResourceWithStreamingResponse, - AsyncReclassifyResourceWithStreamingResponse, -) from .investigate import ( InvestigateResource, AsyncInvestigateResource, @@ -66,42 +34,18 @@ ) __all__ = [ - "DetectionsResource", - "AsyncDetectionsResource", - "DetectionsResourceWithRawResponse", - "AsyncDetectionsResourceWithRawResponse", - "DetectionsResourceWithStreamingResponse", - "AsyncDetectionsResourceWithStreamingResponse", "PreviewResource", "AsyncPreviewResource", "PreviewResourceWithRawResponse", "AsyncPreviewResourceWithRawResponse", "PreviewResourceWithStreamingResponse", "AsyncPreviewResourceWithStreamingResponse", - "RawResource", - "AsyncRawResource", - "RawResourceWithRawResponse", - "AsyncRawResourceWithRawResponse", - "RawResourceWithStreamingResponse", - "AsyncRawResourceWithStreamingResponse", - "TraceResource", - "AsyncTraceResource", - "TraceResourceWithRawResponse", - "AsyncTraceResourceWithRawResponse", - "TraceResourceWithStreamingResponse", - "AsyncTraceResourceWithStreamingResponse", "MoveResource", "AsyncMoveResource", "MoveResourceWithRawResponse", "AsyncMoveResourceWithRawResponse", "MoveResourceWithStreamingResponse", "AsyncMoveResourceWithStreamingResponse", - "ReclassifyResource", - "AsyncReclassifyResource", - "ReclassifyResourceWithRawResponse", - "AsyncReclassifyResourceWithRawResponse", - "ReclassifyResourceWithStreamingResponse", - "AsyncReclassifyResourceWithStreamingResponse", "ReleaseResource", "AsyncReleaseResource", "ReleaseResourceWithRawResponse", diff --git a/src/cloudflare/resources/email_security/investigate/detections.py b/src/cloudflare/resources/email_security/investigate/detections.py deleted file mode 100644 index 3bf800a5931..00000000000 --- a/src/cloudflare/resources/email_security/investigate/detections.py +++ /dev/null @@ -1,199 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Type, cast - -import httpx - -from ...._types import Body, Query, Headers, NotGiven, not_given -from ...._utils import path_template -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.email_security.investigate.detection_get_response import DetectionGetResponse - -__all__ = ["DetectionsResource", "AsyncDetectionsResource"] - - -class DetectionsResource(SyncAPIResource): - @cached_property - def with_raw_response(self) -> DetectionsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - 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 DetectionsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> DetectionsResourceWithStreamingResponse: - """ - 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 DetectionsResourceWithStreamingResponse(self) - - def get( - self, - postfix_id: str, - *, - 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, - ) -> DetectionGetResponse: - """ - Returns detection details such as threat categories and sender information for - non-benign messages. - - Args: - account_id: Account Identifier - - postfix_id: The identifier of the message. - - 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 postfix_id: - raise ValueError(f"Expected a non-empty value for `postfix_id` but received {postfix_id!r}") - return self._get( - path_template( - "/accounts/{account_id}/email-security/investigate/{postfix_id}/detections", - account_id=account_id, - postfix_id=postfix_id, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - post_parser=ResultWrapper[DetectionGetResponse]._unwrapper, - ), - cast_to=cast(Type[DetectionGetResponse], ResultWrapper[DetectionGetResponse]), - ) - - -class AsyncDetectionsResource(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncDetectionsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - 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 AsyncDetectionsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncDetectionsResourceWithStreamingResponse: - """ - 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 AsyncDetectionsResourceWithStreamingResponse(self) - - async def get( - self, - postfix_id: str, - *, - 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, - ) -> DetectionGetResponse: - """ - Returns detection details such as threat categories and sender information for - non-benign messages. - - Args: - account_id: Account Identifier - - postfix_id: The identifier of the message. - - 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 postfix_id: - raise ValueError(f"Expected a non-empty value for `postfix_id` but received {postfix_id!r}") - return await self._get( - path_template( - "/accounts/{account_id}/email-security/investigate/{postfix_id}/detections", - account_id=account_id, - postfix_id=postfix_id, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - post_parser=ResultWrapper[DetectionGetResponse]._unwrapper, - ), - cast_to=cast(Type[DetectionGetResponse], ResultWrapper[DetectionGetResponse]), - ) - - -class DetectionsResourceWithRawResponse: - def __init__(self, detections: DetectionsResource) -> None: - self._detections = detections - - self.get = to_raw_response_wrapper( - detections.get, - ) - - -class AsyncDetectionsResourceWithRawResponse: - def __init__(self, detections: AsyncDetectionsResource) -> None: - self._detections = detections - - self.get = async_to_raw_response_wrapper( - detections.get, - ) - - -class DetectionsResourceWithStreamingResponse: - def __init__(self, detections: DetectionsResource) -> None: - self._detections = detections - - self.get = to_streamed_response_wrapper( - detections.get, - ) - - -class AsyncDetectionsResourceWithStreamingResponse: - def __init__(self, detections: AsyncDetectionsResource) -> None: - self._detections = detections - - self.get = async_to_streamed_response_wrapper( - detections.get, - ) diff --git a/src/cloudflare/resources/email_security/investigate/investigate.py b/src/cloudflare/resources/email_security/investigate/investigate.py index c6167137eed..1b2bfa3f608 100644 --- a/src/cloudflare/resources/email_security/investigate/investigate.py +++ b/src/cloudflare/resources/email_security/investigate/investigate.py @@ -2,20 +2,12 @@ from __future__ import annotations -from typing import Type, Union, Optional, cast +from typing import Union, Optional from datetime import datetime from typing_extensions import Literal import httpx -from .raw import ( - RawResource, - AsyncRawResource, - RawResourceWithRawResponse, - AsyncRawResourceWithRawResponse, - RawResourceWithStreamingResponse, - AsyncRawResourceWithStreamingResponse, -) from .move import ( MoveResource, AsyncMoveResource, @@ -24,14 +16,6 @@ MoveResourceWithStreamingResponse, AsyncMoveResourceWithStreamingResponse, ) -from .trace import ( - TraceResource, - AsyncTraceResource, - TraceResourceWithRawResponse, - AsyncTraceResourceWithRawResponse, - TraceResourceWithStreamingResponse, - AsyncTraceResourceWithStreamingResponse, -) from .preview import ( PreviewResource, AsyncPreviewResource, @@ -49,24 +33,8 @@ AsyncReleaseResourceWithStreamingResponse, ) from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import path_template, maybe_transform, async_maybe_transform +from ...._utils import path_template, maybe_transform from ...._compat import cached_property -from .detections import ( - DetectionsResource, - AsyncDetectionsResource, - DetectionsResourceWithRawResponse, - AsyncDetectionsResourceWithRawResponse, - DetectionsResourceWithStreamingResponse, - AsyncDetectionsResourceWithStreamingResponse, -) -from .reclassify import ( - ReclassifyResource, - AsyncReclassifyResource, - ReclassifyResourceWithRawResponse, - AsyncReclassifyResourceWithRawResponse, - ReclassifyResourceWithStreamingResponse, - AsyncReclassifyResourceWithStreamingResponse, -) from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import ( to_raw_response_wrapper, @@ -74,41 +42,23 @@ async_to_raw_response_wrapper, async_to_streamed_response_wrapper, ) -from ...._wrappers import ResultWrapper from ....pagination import SyncV4PagePaginationArray, AsyncV4PagePaginationArray from ...._base_client import AsyncPaginator, make_request_options -from ....types.email_security import investigate_get_params, investigate_list_params -from ....types.email_security.investigate_get_response import InvestigateGetResponse +from ....types.email_security import investigate_list_params from ....types.email_security.investigate_list_response import InvestigateListResponse __all__ = ["InvestigateResource", "AsyncInvestigateResource"] class InvestigateResource(SyncAPIResource): - @cached_property - def detections(self) -> DetectionsResource: - return DetectionsResource(self._client) - @cached_property def preview(self) -> PreviewResource: return PreviewResource(self._client) - @cached_property - def raw(self) -> RawResource: - return RawResource(self._client) - - @cached_property - def trace(self) -> TraceResource: - return TraceResource(self._client) - @cached_property def move(self) -> MoveResource: return MoveResource(self._client) - @cached_property - def reclassify(self) -> ReclassifyResource: - return ReclassifyResource(self._client) - @cached_property def release(self) -> ReleaseResource: return ReleaseResource(self._client) @@ -142,9 +92,8 @@ def list( detections_only: bool | Omit = omit, domain: str | Omit = omit, end: Union[str, datetime] | Omit = omit, - exact_subject: str | Omit = omit, final_disposition: Literal["MALICIOUS", "SUSPICIOUS", "SPOOF", "SPAM", "BULK", "NONE"] | Omit = omit, - message_action: Literal["PREVIEW", "QUARANTINE_RELEASED", "MOVED", "SUBMITTED"] | Omit = omit, + message_action: Literal["PREVIEW", "QUARANTINE_RELEASED", "MOVED"] | Omit = omit, message_id: str | Omit = omit, metric: str | Omit = omit, page: Optional[int] | Omit = omit, @@ -154,7 +103,6 @@ def list( sender: str | Omit = omit, start: Union[str, datetime] | Omit = omit, subject: str | Omit = omit, - submissions: bool | Omit = omit, # 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, @@ -162,70 +110,31 @@ def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncV4PagePaginationArray[InvestigateListResponse]: - """Returns information for each email that matches the search parameter(s). - - If the - search takes too long, the endpoint returns 202 with a Location header pointing - to a polling endpoint where results can be retrieved once ready. + """ + Returns information for each email that matches the search parameter(s). Args: - account_id: Account Identifier + account_id: Identifier. - action_log: Determines if the message action log is included in the response. + action_log: Whether to include the message action log in the response. - detections_only: Determines if the search results will include detections or not. + detections_only: Whether to include only detections in search results. - domain: Filter by a domain found in the email: sender domain, recipient domain, or a - domain in a link. + domain: Sender domains to filter by. - end: The end of the search date range. Defaults to `now` if not provided. + end: The end of the search date range. Defaults to `now`. - exact_subject: Search for messages with an exact subject match. + final_disposition: Dispositions to filter by. - final_disposition: The dispositions the search filters by. + message_action: Message actions to filter by. - message_action: The message actions the search filters by. - - page: Deprecated: Use cursor pagination instead. + page: Deprecated: Use cursor pagination instead. End of life: November 1, 2026. per_page: The number of results per page. Maximum value is 1000. - query: The space-delimited term used in the query. The search is case-insensitive. - - The content of the following email metadata fields are searched: - - - alert_id - - CC - - From (envelope_from) - - From Name - - final_disposition - - md5 hash (of any attachment) - - sha1 hash (of any attachment) - - sha256 hash (of any attachment) - - name (of any attachment) - - Reason - - Received DateTime (yyyy-mm-ddThh:mm:ss) - - Sent DateTime (yyyy-mm-ddThh:mm:ss) - - ReplyTo - - To (envelope_to) - - To Name - - Message-ID - - smtp_helo_server_ip - - smtp_previous_hop_ip - - x_originating_ip - - Subject - - recipient: Filter by recipient. Matches either an email address or a domain. + query: Space-delimited search term. Case-insensitive. - sender: Filter by sender. Matches either an email address or a domain. - - start: The beginning of the search date range. Defaults to `now - 30 days` if not - provided. - - subject: Search for messages containing individual keywords in any order within the - subject. - - submissions: Search for submissions instead of original messages + start: The beginning of the search date range. Defaults to `now - 30 days`. extra_headers: Send extra headers @@ -253,7 +162,6 @@ def list( "detections_only": detections_only, "domain": domain, "end": end, - "exact_subject": exact_subject, "final_disposition": final_disposition, "message_action": message_action, "message_id": message_id, @@ -265,7 +173,6 @@ def list( "sender": sender, "start": start, "subject": subject, - "submissions": submissions, }, investigate_list_params.InvestigateListParams, ), @@ -273,86 +180,16 @@ def list( model=InvestigateListResponse, ) - def get( - self, - postfix_id: str, - *, - account_id: str, - submission: bool | Omit = omit, - # 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, - ) -> InvestigateGetResponse: - """ - Retrieves detailed information about a specific email message, including - headers, metadata, and security scan results. - - Args: - account_id: Account Identifier - - postfix_id: The identifier of the message. - - submission: When true, search the submissions datastore only. When false or omitted, search - the regular datastore only. - - 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 postfix_id: - raise ValueError(f"Expected a non-empty value for `postfix_id` but received {postfix_id!r}") - return self._get( - path_template( - "/accounts/{account_id}/email-security/investigate/{postfix_id}", - account_id=account_id, - postfix_id=postfix_id, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform({"submission": submission}, investigate_get_params.InvestigateGetParams), - post_parser=ResultWrapper[InvestigateGetResponse]._unwrapper, - ), - cast_to=cast(Type[InvestigateGetResponse], ResultWrapper[InvestigateGetResponse]), - ) - class AsyncInvestigateResource(AsyncAPIResource): - @cached_property - def detections(self) -> AsyncDetectionsResource: - return AsyncDetectionsResource(self._client) - @cached_property def preview(self) -> AsyncPreviewResource: return AsyncPreviewResource(self._client) - @cached_property - def raw(self) -> AsyncRawResource: - return AsyncRawResource(self._client) - - @cached_property - def trace(self) -> AsyncTraceResource: - return AsyncTraceResource(self._client) - @cached_property def move(self) -> AsyncMoveResource: return AsyncMoveResource(self._client) - @cached_property - def reclassify(self) -> AsyncReclassifyResource: - return AsyncReclassifyResource(self._client) - @cached_property def release(self) -> AsyncReleaseResource: return AsyncReleaseResource(self._client) @@ -386,9 +223,8 @@ def list( detections_only: bool | Omit = omit, domain: str | Omit = omit, end: Union[str, datetime] | Omit = omit, - exact_subject: str | Omit = omit, final_disposition: Literal["MALICIOUS", "SUSPICIOUS", "SPOOF", "SPAM", "BULK", "NONE"] | Omit = omit, - message_action: Literal["PREVIEW", "QUARANTINE_RELEASED", "MOVED", "SUBMITTED"] | Omit = omit, + message_action: Literal["PREVIEW", "QUARANTINE_RELEASED", "MOVED"] | Omit = omit, message_id: str | Omit = omit, metric: str | Omit = omit, page: Optional[int] | Omit = omit, @@ -398,7 +234,6 @@ def list( sender: str | Omit = omit, start: Union[str, datetime] | Omit = omit, subject: str | Omit = omit, - submissions: bool | Omit = omit, # 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, @@ -406,70 +241,31 @@ def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[InvestigateListResponse, AsyncV4PagePaginationArray[InvestigateListResponse]]: - """Returns information for each email that matches the search parameter(s). - - If the - search takes too long, the endpoint returns 202 with a Location header pointing - to a polling endpoint where results can be retrieved once ready. + """ + Returns information for each email that matches the search parameter(s). Args: - account_id: Account Identifier - - action_log: Determines if the message action log is included in the response. + account_id: Identifier. - detections_only: Determines if the search results will include detections or not. + action_log: Whether to include the message action log in the response. - domain: Filter by a domain found in the email: sender domain, recipient domain, or a - domain in a link. + detections_only: Whether to include only detections in search results. - end: The end of the search date range. Defaults to `now` if not provided. + domain: Sender domains to filter by. - exact_subject: Search for messages with an exact subject match. + end: The end of the search date range. Defaults to `now`. - final_disposition: The dispositions the search filters by. + final_disposition: Dispositions to filter by. - message_action: The message actions the search filters by. + message_action: Message actions to filter by. - page: Deprecated: Use cursor pagination instead. + page: Deprecated: Use cursor pagination instead. End of life: November 1, 2026. per_page: The number of results per page. Maximum value is 1000. - query: The space-delimited term used in the query. The search is case-insensitive. - - The content of the following email metadata fields are searched: - - - alert_id - - CC - - From (envelope_from) - - From Name - - final_disposition - - md5 hash (of any attachment) - - sha1 hash (of any attachment) - - sha256 hash (of any attachment) - - name (of any attachment) - - Reason - - Received DateTime (yyyy-mm-ddThh:mm:ss) - - Sent DateTime (yyyy-mm-ddThh:mm:ss) - - ReplyTo - - To (envelope_to) - - To Name - - Message-ID - - smtp_helo_server_ip - - smtp_previous_hop_ip - - x_originating_ip - - Subject - - recipient: Filter by recipient. Matches either an email address or a domain. - - sender: Filter by sender. Matches either an email address or a domain. - - start: The beginning of the search date range. Defaults to `now - 30 days` if not - provided. - - subject: Search for messages containing individual keywords in any order within the - subject. + query: Space-delimited search term. Case-insensitive. - submissions: Search for submissions instead of original messages + start: The beginning of the search date range. Defaults to `now - 30 days`. extra_headers: Send extra headers @@ -497,7 +293,6 @@ def list( "detections_only": detections_only, "domain": domain, "end": end, - "exact_subject": exact_subject, "final_disposition": final_disposition, "message_action": message_action, "message_id": message_id, @@ -509,7 +304,6 @@ def list( "sender": sender, "start": start, "subject": subject, - "submissions": submissions, }, investigate_list_params.InvestigateListParams, ), @@ -517,62 +311,6 @@ def list( model=InvestigateListResponse, ) - async def get( - self, - postfix_id: str, - *, - account_id: str, - submission: bool | Omit = omit, - # 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, - ) -> InvestigateGetResponse: - """ - Retrieves detailed information about a specific email message, including - headers, metadata, and security scan results. - - Args: - account_id: Account Identifier - - postfix_id: The identifier of the message. - - submission: When true, search the submissions datastore only. When false or omitted, search - the regular datastore only. - - 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 postfix_id: - raise ValueError(f"Expected a non-empty value for `postfix_id` but received {postfix_id!r}") - return await self._get( - path_template( - "/accounts/{account_id}/email-security/investigate/{postfix_id}", - account_id=account_id, - postfix_id=postfix_id, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform( - {"submission": submission}, investigate_get_params.InvestigateGetParams - ), - post_parser=ResultWrapper[InvestigateGetResponse]._unwrapper, - ), - cast_to=cast(Type[InvestigateGetResponse], ResultWrapper[InvestigateGetResponse]), - ) - class InvestigateResourceWithRawResponse: def __init__(self, investigate: InvestigateResource) -> None: @@ -581,34 +319,15 @@ def __init__(self, investigate: InvestigateResource) -> None: self.list = to_raw_response_wrapper( investigate.list, ) - self.get = to_raw_response_wrapper( - investigate.get, - ) - - @cached_property - def detections(self) -> DetectionsResourceWithRawResponse: - return DetectionsResourceWithRawResponse(self._investigate.detections) @cached_property def preview(self) -> PreviewResourceWithRawResponse: return PreviewResourceWithRawResponse(self._investigate.preview) - @cached_property - def raw(self) -> RawResourceWithRawResponse: - return RawResourceWithRawResponse(self._investigate.raw) - - @cached_property - def trace(self) -> TraceResourceWithRawResponse: - return TraceResourceWithRawResponse(self._investigate.trace) - @cached_property def move(self) -> MoveResourceWithRawResponse: return MoveResourceWithRawResponse(self._investigate.move) - @cached_property - def reclassify(self) -> ReclassifyResourceWithRawResponse: - return ReclassifyResourceWithRawResponse(self._investigate.reclassify) - @cached_property def release(self) -> ReleaseResourceWithRawResponse: return ReleaseResourceWithRawResponse(self._investigate.release) @@ -621,34 +340,15 @@ def __init__(self, investigate: AsyncInvestigateResource) -> None: self.list = async_to_raw_response_wrapper( investigate.list, ) - self.get = async_to_raw_response_wrapper( - investigate.get, - ) - - @cached_property - def detections(self) -> AsyncDetectionsResourceWithRawResponse: - return AsyncDetectionsResourceWithRawResponse(self._investigate.detections) @cached_property def preview(self) -> AsyncPreviewResourceWithRawResponse: return AsyncPreviewResourceWithRawResponse(self._investigate.preview) - @cached_property - def raw(self) -> AsyncRawResourceWithRawResponse: - return AsyncRawResourceWithRawResponse(self._investigate.raw) - - @cached_property - def trace(self) -> AsyncTraceResourceWithRawResponse: - return AsyncTraceResourceWithRawResponse(self._investigate.trace) - @cached_property def move(self) -> AsyncMoveResourceWithRawResponse: return AsyncMoveResourceWithRawResponse(self._investigate.move) - @cached_property - def reclassify(self) -> AsyncReclassifyResourceWithRawResponse: - return AsyncReclassifyResourceWithRawResponse(self._investigate.reclassify) - @cached_property def release(self) -> AsyncReleaseResourceWithRawResponse: return AsyncReleaseResourceWithRawResponse(self._investigate.release) @@ -661,34 +361,15 @@ def __init__(self, investigate: InvestigateResource) -> None: self.list = to_streamed_response_wrapper( investigate.list, ) - self.get = to_streamed_response_wrapper( - investigate.get, - ) - - @cached_property - def detections(self) -> DetectionsResourceWithStreamingResponse: - return DetectionsResourceWithStreamingResponse(self._investigate.detections) @cached_property def preview(self) -> PreviewResourceWithStreamingResponse: return PreviewResourceWithStreamingResponse(self._investigate.preview) - @cached_property - def raw(self) -> RawResourceWithStreamingResponse: - return RawResourceWithStreamingResponse(self._investigate.raw) - - @cached_property - def trace(self) -> TraceResourceWithStreamingResponse: - return TraceResourceWithStreamingResponse(self._investigate.trace) - @cached_property def move(self) -> MoveResourceWithStreamingResponse: return MoveResourceWithStreamingResponse(self._investigate.move) - @cached_property - def reclassify(self) -> ReclassifyResourceWithStreamingResponse: - return ReclassifyResourceWithStreamingResponse(self._investigate.reclassify) - @cached_property def release(self) -> ReleaseResourceWithStreamingResponse: return ReleaseResourceWithStreamingResponse(self._investigate.release) @@ -701,34 +382,15 @@ def __init__(self, investigate: AsyncInvestigateResource) -> None: self.list = async_to_streamed_response_wrapper( investigate.list, ) - self.get = async_to_streamed_response_wrapper( - investigate.get, - ) - - @cached_property - def detections(self) -> AsyncDetectionsResourceWithStreamingResponse: - return AsyncDetectionsResourceWithStreamingResponse(self._investigate.detections) @cached_property def preview(self) -> AsyncPreviewResourceWithStreamingResponse: return AsyncPreviewResourceWithStreamingResponse(self._investigate.preview) - @cached_property - def raw(self) -> AsyncRawResourceWithStreamingResponse: - return AsyncRawResourceWithStreamingResponse(self._investigate.raw) - - @cached_property - def trace(self) -> AsyncTraceResourceWithStreamingResponse: - return AsyncTraceResourceWithStreamingResponse(self._investigate.trace) - @cached_property def move(self) -> AsyncMoveResourceWithStreamingResponse: return AsyncMoveResourceWithStreamingResponse(self._investigate.move) - @cached_property - def reclassify(self) -> AsyncReclassifyResourceWithStreamingResponse: - return AsyncReclassifyResourceWithStreamingResponse(self._investigate.reclassify) - @cached_property def release(self) -> AsyncReleaseResourceWithStreamingResponse: return AsyncReleaseResourceWithStreamingResponse(self._investigate.release) diff --git a/src/cloudflare/resources/email_security/investigate/move.py b/src/cloudflare/resources/email_security/investigate/move.py index ae07fced89e..52b6b073e5b 100644 --- a/src/cloudflare/resources/email_security/investigate/move.py +++ b/src/cloudflare/resources/email_security/investigate/move.py @@ -2,13 +2,12 @@ from __future__ import annotations -from typing import Type, cast from typing_extensions import Literal import httpx from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given -from ...._utils import path_template, maybe_transform, async_maybe_transform +from ...._utils import path_template, maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import ( @@ -17,12 +16,10 @@ async_to_raw_response_wrapper, async_to_streamed_response_wrapper, ) -from ...._wrappers import ResultWrapper from ....pagination import SyncSinglePage, AsyncSinglePage from ...._base_client import AsyncPaginator, make_request_options -from ....types.email_security.investigate import move_bulk_params, move_create_params +from ....types.email_security.investigate import move_bulk_params from ....types.email_security.investigate.move_bulk_response import MoveBulkResponse -from ....types.email_security.investigate.move_create_response import MoveCreateResponse __all__ = ["MoveResource", "AsyncMoveResource"] @@ -47,64 +44,6 @@ def with_streaming_response(self) -> MoveResourceWithStreamingResponse: """ return MoveResourceWithStreamingResponse(self) - def create( - self, - postfix_id: str, - *, - account_id: str, - destination: Literal[ - "Inbox", "JunkEmail", "DeletedItems", "RecoverableItemsDeletions", "RecoverableItemsPurges" - ], - submission: bool | Omit = omit, - # 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, - ) -> MoveCreateResponse: - """ - Moves a single email message to a different folder or changes its quarantine - status. - - Args: - account_id: Account Identifier - - postfix_id: The identifier of the message. - - submission: When true, search the submissions datastore only. When false or omitted, search - the regular datastore only. - - 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 postfix_id: - raise ValueError(f"Expected a non-empty value for `postfix_id` but received {postfix_id!r}") - return self._post( - path_template( - "/accounts/{account_id}/email-security/investigate/{postfix_id}/move", - account_id=account_id, - postfix_id=postfix_id, - ), - body=maybe_transform({"destination": destination}, move_create_params.MoveCreateParams), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform({"submission": submission}, move_create_params.MoveCreateParams), - post_parser=ResultWrapper[MoveCreateResponse]._unwrapper, - ), - cast_to=cast(Type[MoveCreateResponse], ResultWrapper[MoveCreateResponse]), - ) - def bulk( self, *, @@ -122,14 +61,17 @@ def bulk( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncSinglePage[MoveBulkResponse]: """ - Maximum batch size: 1000 messages per request + Moves multiple messages to a specified mailbox folder (Inbox, JunkEmail, + DeletedItems, RecoverableItemsDeletions, or RecoverableItemsPurges). Requires + active integration. Args: - account_id: Account Identifier + account_id: Identifier. - ids: List of message IDs to move. + ids: List of message IDs to move - postfix_ids: Deprecated: Use `ids` instead. List of message IDs to move. + postfix_ids: Deprecated, use `ids` instead. End of life: November 1, 2026. List of message + IDs to move. extra_headers: Send extra headers @@ -180,64 +122,6 @@ def with_streaming_response(self) -> AsyncMoveResourceWithStreamingResponse: """ return AsyncMoveResourceWithStreamingResponse(self) - async def create( - self, - postfix_id: str, - *, - account_id: str, - destination: Literal[ - "Inbox", "JunkEmail", "DeletedItems", "RecoverableItemsDeletions", "RecoverableItemsPurges" - ], - submission: bool | Omit = omit, - # 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, - ) -> MoveCreateResponse: - """ - Moves a single email message to a different folder or changes its quarantine - status. - - Args: - account_id: Account Identifier - - postfix_id: The identifier of the message. - - submission: When true, search the submissions datastore only. When false or omitted, search - the regular datastore only. - - 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 postfix_id: - raise ValueError(f"Expected a non-empty value for `postfix_id` but received {postfix_id!r}") - return await self._post( - path_template( - "/accounts/{account_id}/email-security/investigate/{postfix_id}/move", - account_id=account_id, - postfix_id=postfix_id, - ), - body=await async_maybe_transform({"destination": destination}, move_create_params.MoveCreateParams), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform({"submission": submission}, move_create_params.MoveCreateParams), - post_parser=ResultWrapper[MoveCreateResponse]._unwrapper, - ), - cast_to=cast(Type[MoveCreateResponse], ResultWrapper[MoveCreateResponse]), - ) - def bulk( self, *, @@ -255,14 +139,17 @@ def bulk( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[MoveBulkResponse, AsyncSinglePage[MoveBulkResponse]]: """ - Maximum batch size: 1000 messages per request + Moves multiple messages to a specified mailbox folder (Inbox, JunkEmail, + DeletedItems, RecoverableItemsDeletions, or RecoverableItemsPurges). Requires + active integration. Args: - account_id: Account Identifier + account_id: Identifier. - ids: List of message IDs to move. + ids: List of message IDs to move - postfix_ids: Deprecated: Use `ids` instead. List of message IDs to move. + postfix_ids: Deprecated, use `ids` instead. End of life: November 1, 2026. List of message + IDs to move. extra_headers: Send extra headers @@ -297,9 +184,6 @@ class MoveResourceWithRawResponse: def __init__(self, move: MoveResource) -> None: self._move = move - self.create = to_raw_response_wrapper( - move.create, - ) self.bulk = to_raw_response_wrapper( move.bulk, ) @@ -309,9 +193,6 @@ class AsyncMoveResourceWithRawResponse: def __init__(self, move: AsyncMoveResource) -> None: self._move = move - self.create = async_to_raw_response_wrapper( - move.create, - ) self.bulk = async_to_raw_response_wrapper( move.bulk, ) @@ -321,9 +202,6 @@ class MoveResourceWithStreamingResponse: def __init__(self, move: MoveResource) -> None: self._move = move - self.create = to_streamed_response_wrapper( - move.create, - ) self.bulk = to_streamed_response_wrapper( move.bulk, ) @@ -333,9 +211,6 @@ class AsyncMoveResourceWithStreamingResponse: def __init__(self, move: AsyncMoveResource) -> None: self._move = move - self.create = async_to_streamed_response_wrapper( - move.create, - ) self.bulk = async_to_streamed_response_wrapper( move.bulk, ) diff --git a/src/cloudflare/resources/email_security/investigate/preview.py b/src/cloudflare/resources/email_security/investigate/preview.py index 17fe835b7f4..7f582af0eb9 100644 --- a/src/cloudflare/resources/email_security/investigate/preview.py +++ b/src/cloudflare/resources/email_security/investigate/preview.py @@ -6,7 +6,7 @@ import httpx -from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ...._types import Body, Query, Headers, NotGiven, not_given from ...._utils import path_template, maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource @@ -19,7 +19,6 @@ from ...._wrappers import ResultWrapper from ...._base_client import make_request_options from ....types.email_security.investigate import preview_create_params -from ....types.email_security.investigate.preview_get_response import PreviewGetResponse from ....types.email_security.investigate.preview_create_response import PreviewCreateResponse __all__ = ["PreviewResource", "AsyncPreviewResource"] @@ -50,7 +49,6 @@ def create( *, account_id: str, postfix_id: str, - submission: bool | Omit = omit, # 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, @@ -59,16 +57,14 @@ def create( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> PreviewCreateResponse: """ - Generates a preview of an email message for safe viewing without executing any - embedded content. + Generates a preview image for a message that was not flagged as a detection. + Useful for investigating benign messages. Returns a base64-encoded PNG + screenshot of the email body. Args: - account_id: Account Identifier + account_id: Identifier. - postfix_id: The identifier of the message. - - submission: When true, search the submissions datastore only. When false or omitted, search - the regular datastore only. + postfix_id: The identifier of the message extra_headers: Send extra headers @@ -88,61 +84,11 @@ def create( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - query=maybe_transform({"submission": submission}, preview_create_params.PreviewCreateParams), post_parser=ResultWrapper[PreviewCreateResponse]._unwrapper, ), cast_to=cast(Type[PreviewCreateResponse], ResultWrapper[PreviewCreateResponse]), ) - def get( - self, - postfix_id: str, - *, - 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, - ) -> PreviewGetResponse: - """ - Returns a preview of the message body as a base64 encoded PNG image for - non-benign messages. - - Args: - account_id: Account Identifier - - postfix_id: The identifier of the message. - - 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 postfix_id: - raise ValueError(f"Expected a non-empty value for `postfix_id` but received {postfix_id!r}") - return self._get( - path_template( - "/accounts/{account_id}/email-security/investigate/{postfix_id}/preview", - account_id=account_id, - postfix_id=postfix_id, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - post_parser=ResultWrapper[PreviewGetResponse]._unwrapper, - ), - cast_to=cast(Type[PreviewGetResponse], ResultWrapper[PreviewGetResponse]), - ) - class AsyncPreviewResource(AsyncAPIResource): @cached_property @@ -169,7 +115,6 @@ async def create( *, account_id: str, postfix_id: str, - submission: bool | Omit = omit, # 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, @@ -178,16 +123,14 @@ async def create( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> PreviewCreateResponse: """ - Generates a preview of an email message for safe viewing without executing any - embedded content. + Generates a preview image for a message that was not flagged as a detection. + Useful for investigating benign messages. Returns a base64-encoded PNG + screenshot of the email body. Args: - account_id: Account Identifier + account_id: Identifier. - postfix_id: The identifier of the message. - - submission: When true, search the submissions datastore only. When false or omitted, search - the regular datastore only. + postfix_id: The identifier of the message extra_headers: Send extra headers @@ -207,63 +150,11 @@ async def create( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - query=await async_maybe_transform( - {"submission": submission}, preview_create_params.PreviewCreateParams - ), post_parser=ResultWrapper[PreviewCreateResponse]._unwrapper, ), cast_to=cast(Type[PreviewCreateResponse], ResultWrapper[PreviewCreateResponse]), ) - async def get( - self, - postfix_id: str, - *, - 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, - ) -> PreviewGetResponse: - """ - Returns a preview of the message body as a base64 encoded PNG image for - non-benign messages. - - Args: - account_id: Account Identifier - - postfix_id: The identifier of the message. - - 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 postfix_id: - raise ValueError(f"Expected a non-empty value for `postfix_id` but received {postfix_id!r}") - return await self._get( - path_template( - "/accounts/{account_id}/email-security/investigate/{postfix_id}/preview", - account_id=account_id, - postfix_id=postfix_id, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - post_parser=ResultWrapper[PreviewGetResponse]._unwrapper, - ), - cast_to=cast(Type[PreviewGetResponse], ResultWrapper[PreviewGetResponse]), - ) - class PreviewResourceWithRawResponse: def __init__(self, preview: PreviewResource) -> None: @@ -272,9 +163,6 @@ def __init__(self, preview: PreviewResource) -> None: self.create = to_raw_response_wrapper( preview.create, ) - self.get = to_raw_response_wrapper( - preview.get, - ) class AsyncPreviewResourceWithRawResponse: @@ -284,9 +172,6 @@ def __init__(self, preview: AsyncPreviewResource) -> None: self.create = async_to_raw_response_wrapper( preview.create, ) - self.get = async_to_raw_response_wrapper( - preview.get, - ) class PreviewResourceWithStreamingResponse: @@ -296,9 +181,6 @@ def __init__(self, preview: PreviewResource) -> None: self.create = to_streamed_response_wrapper( preview.create, ) - self.get = to_streamed_response_wrapper( - preview.get, - ) class AsyncPreviewResourceWithStreamingResponse: @@ -308,6 +190,3 @@ def __init__(self, preview: AsyncPreviewResource) -> None: self.create = async_to_streamed_response_wrapper( preview.create, ) - self.get = async_to_streamed_response_wrapper( - preview.get, - ) diff --git a/src/cloudflare/resources/email_security/investigate/raw.py b/src/cloudflare/resources/email_security/investigate/raw.py deleted file mode 100644 index 39a8a4b6d39..00000000000 --- a/src/cloudflare/resources/email_security/investigate/raw.py +++ /dev/null @@ -1,197 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Type, cast - -import httpx - -from ...._types import Body, Query, Headers, NotGiven, not_given -from ...._utils import path_template -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.email_security.investigate.raw_get_response import RawGetResponse - -__all__ = ["RawResource", "AsyncRawResource"] - - -class RawResource(SyncAPIResource): - @cached_property - def with_raw_response(self) -> RawResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - 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 RawResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> RawResourceWithStreamingResponse: - """ - 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 RawResourceWithStreamingResponse(self) - - def get( - self, - postfix_id: str, - *, - 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, - ) -> RawGetResponse: - """ - Returns the raw eml of any non-benign message. - - Args: - account_id: Account Identifier - - postfix_id: The identifier of the message. - - 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 postfix_id: - raise ValueError(f"Expected a non-empty value for `postfix_id` but received {postfix_id!r}") - return self._get( - path_template( - "/accounts/{account_id}/email-security/investigate/{postfix_id}/raw", - account_id=account_id, - postfix_id=postfix_id, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - post_parser=ResultWrapper[RawGetResponse]._unwrapper, - ), - cast_to=cast(Type[RawGetResponse], ResultWrapper[RawGetResponse]), - ) - - -class AsyncRawResource(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncRawResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - 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 AsyncRawResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncRawResourceWithStreamingResponse: - """ - 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 AsyncRawResourceWithStreamingResponse(self) - - async def get( - self, - postfix_id: str, - *, - 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, - ) -> RawGetResponse: - """ - Returns the raw eml of any non-benign message. - - Args: - account_id: Account Identifier - - postfix_id: The identifier of the message. - - 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 postfix_id: - raise ValueError(f"Expected a non-empty value for `postfix_id` but received {postfix_id!r}") - return await self._get( - path_template( - "/accounts/{account_id}/email-security/investigate/{postfix_id}/raw", - account_id=account_id, - postfix_id=postfix_id, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - post_parser=ResultWrapper[RawGetResponse]._unwrapper, - ), - cast_to=cast(Type[RawGetResponse], ResultWrapper[RawGetResponse]), - ) - - -class RawResourceWithRawResponse: - def __init__(self, raw: RawResource) -> None: - self._raw = raw - - self.get = to_raw_response_wrapper( - raw.get, - ) - - -class AsyncRawResourceWithRawResponse: - def __init__(self, raw: AsyncRawResource) -> None: - self._raw = raw - - self.get = async_to_raw_response_wrapper( - raw.get, - ) - - -class RawResourceWithStreamingResponse: - def __init__(self, raw: RawResource) -> None: - self._raw = raw - - self.get = to_streamed_response_wrapper( - raw.get, - ) - - -class AsyncRawResourceWithStreamingResponse: - def __init__(self, raw: AsyncRawResource) -> None: - self._raw = raw - - self.get = async_to_streamed_response_wrapper( - raw.get, - ) diff --git a/src/cloudflare/resources/email_security/investigate/reclassify.py b/src/cloudflare/resources/email_security/investigate/reclassify.py deleted file mode 100644 index 27daa3d7260..00000000000 --- a/src/cloudflare/resources/email_security/investigate/reclassify.py +++ /dev/null @@ -1,238 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Type, cast -from typing_extensions import Literal - -import httpx - -from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import path_template, 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 ...._base_client import make_request_options -from ....types.email_security.investigate import reclassify_create_params - -__all__ = ["ReclassifyResource", "AsyncReclassifyResource"] - - -class ReclassifyResource(SyncAPIResource): - @cached_property - def with_raw_response(self) -> ReclassifyResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - 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 ReclassifyResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> ReclassifyResourceWithStreamingResponse: - """ - 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 ReclassifyResourceWithStreamingResponse(self) - - def create( - self, - postfix_id: str, - *, - account_id: str, - expected_disposition: Literal["NONE", "BULK", "MALICIOUS", "SPAM", "SPOOF", "SUSPICIOUS"], - submission: bool | Omit = omit, - eml_content: str | Omit = omit, - escalated_submission_id: str | Omit = omit, - # 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, - ) -> object: - """ - Submits an email message for reclassification, updating its threat assessment - based on new analysis. - - Args: - account_id: Account Identifier - - postfix_id: The identifier of the message. - - submission: When true, search the submissions datastore only. When false or omitted, search - the regular datastore only. - - eml_content: Base64 encoded content of the EML file - - 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 postfix_id: - raise ValueError(f"Expected a non-empty value for `postfix_id` but received {postfix_id!r}") - return self._post( - path_template( - "/accounts/{account_id}/email-security/investigate/{postfix_id}/reclassify", - account_id=account_id, - postfix_id=postfix_id, - ), - body=maybe_transform( - { - "expected_disposition": expected_disposition, - "eml_content": eml_content, - "escalated_submission_id": escalated_submission_id, - }, - reclassify_create_params.ReclassifyCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform({"submission": submission}, reclassify_create_params.ReclassifyCreateParams), - post_parser=ResultWrapper[object]._unwrapper, - ), - cast_to=cast(Type[object], ResultWrapper[object]), - ) - - -class AsyncReclassifyResource(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncReclassifyResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - 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 AsyncReclassifyResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncReclassifyResourceWithStreamingResponse: - """ - 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 AsyncReclassifyResourceWithStreamingResponse(self) - - async def create( - self, - postfix_id: str, - *, - account_id: str, - expected_disposition: Literal["NONE", "BULK", "MALICIOUS", "SPAM", "SPOOF", "SUSPICIOUS"], - submission: bool | Omit = omit, - eml_content: str | Omit = omit, - escalated_submission_id: str | Omit = omit, - # 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, - ) -> object: - """ - Submits an email message for reclassification, updating its threat assessment - based on new analysis. - - Args: - account_id: Account Identifier - - postfix_id: The identifier of the message. - - submission: When true, search the submissions datastore only. When false or omitted, search - the regular datastore only. - - eml_content: Base64 encoded content of the EML file - - 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 postfix_id: - raise ValueError(f"Expected a non-empty value for `postfix_id` but received {postfix_id!r}") - return await self._post( - path_template( - "/accounts/{account_id}/email-security/investigate/{postfix_id}/reclassify", - account_id=account_id, - postfix_id=postfix_id, - ), - body=await async_maybe_transform( - { - "expected_disposition": expected_disposition, - "eml_content": eml_content, - "escalated_submission_id": escalated_submission_id, - }, - reclassify_create_params.ReclassifyCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform( - {"submission": submission}, reclassify_create_params.ReclassifyCreateParams - ), - post_parser=ResultWrapper[object]._unwrapper, - ), - cast_to=cast(Type[object], ResultWrapper[object]), - ) - - -class ReclassifyResourceWithRawResponse: - def __init__(self, reclassify: ReclassifyResource) -> None: - self._reclassify = reclassify - - self.create = to_raw_response_wrapper( - reclassify.create, - ) - - -class AsyncReclassifyResourceWithRawResponse: - def __init__(self, reclassify: AsyncReclassifyResource) -> None: - self._reclassify = reclassify - - self.create = async_to_raw_response_wrapper( - reclassify.create, - ) - - -class ReclassifyResourceWithStreamingResponse: - def __init__(self, reclassify: ReclassifyResource) -> None: - self._reclassify = reclassify - - self.create = to_streamed_response_wrapper( - reclassify.create, - ) - - -class AsyncReclassifyResourceWithStreamingResponse: - def __init__(self, reclassify: AsyncReclassifyResource) -> None: - self._reclassify = reclassify - - self.create = async_to_streamed_response_wrapper( - reclassify.create, - ) diff --git a/src/cloudflare/resources/email_security/investigate/release.py b/src/cloudflare/resources/email_security/investigate/release.py index 78d9770cc96..21f78d710b2 100644 --- a/src/cloudflare/resources/email_security/investigate/release.py +++ b/src/cloudflare/resources/email_security/investigate/release.py @@ -54,13 +54,12 @@ def bulk( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncSinglePage[ReleaseBulkResponse]: """ - Releases a quarantined email message, allowing it to be delivered to the - recipient. + Releases one or more quarantined messages, delivering them to the intended + recipients. Use when a message was incorrectly quarantined. Returns delivery + status for each recipient. Args: - account_id: Account Identifier - - body: A list of messages identfied by their `postfix_id`s that should be released. + account_id: Identifier. extra_headers: Send extra headers @@ -117,13 +116,12 @@ def bulk( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[ReleaseBulkResponse, AsyncSinglePage[ReleaseBulkResponse]]: """ - Releases a quarantined email message, allowing it to be delivered to the - recipient. + Releases one or more quarantined messages, delivering them to the intended + recipients. Use when a message was incorrectly quarantined. Returns delivery + status for each recipient. Args: - account_id: Account Identifier - - body: A list of messages identfied by their `postfix_id`s that should be released. + account_id: Identifier. extra_headers: Send extra headers diff --git a/src/cloudflare/resources/email_security/investigate/trace.py b/src/cloudflare/resources/email_security/investigate/trace.py deleted file mode 100644 index bcb66883386..00000000000 --- a/src/cloudflare/resources/email_security/investigate/trace.py +++ /dev/null @@ -1,210 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Type, cast - -import httpx - -from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import path_template, 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 ...._base_client import make_request_options -from ....types.email_security.investigate import trace_get_params -from ....types.email_security.investigate.trace_get_response import TraceGetResponse - -__all__ = ["TraceResource", "AsyncTraceResource"] - - -class TraceResource(SyncAPIResource): - @cached_property - def with_raw_response(self) -> TraceResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - 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 TraceResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> TraceResourceWithStreamingResponse: - """ - 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 TraceResourceWithStreamingResponse(self) - - def get( - self, - postfix_id: str, - *, - account_id: str, - submission: bool | Omit = omit, - # 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, - ) -> TraceGetResponse: - """ - Gets the delivery trace for an email message, showing its path through email - security processing. - - Args: - account_id: Account Identifier - - postfix_id: The identifier of the message. - - submission: When true, search the submissions datastore only. When false or omitted, search - the regular datastore only. - - 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 postfix_id: - raise ValueError(f"Expected a non-empty value for `postfix_id` but received {postfix_id!r}") - return self._get( - path_template( - "/accounts/{account_id}/email-security/investigate/{postfix_id}/trace", - account_id=account_id, - postfix_id=postfix_id, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform({"submission": submission}, trace_get_params.TraceGetParams), - post_parser=ResultWrapper[TraceGetResponse]._unwrapper, - ), - cast_to=cast(Type[TraceGetResponse], ResultWrapper[TraceGetResponse]), - ) - - -class AsyncTraceResource(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncTraceResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - 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 AsyncTraceResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncTraceResourceWithStreamingResponse: - """ - 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 AsyncTraceResourceWithStreamingResponse(self) - - async def get( - self, - postfix_id: str, - *, - account_id: str, - submission: bool | Omit = omit, - # 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, - ) -> TraceGetResponse: - """ - Gets the delivery trace for an email message, showing its path through email - security processing. - - Args: - account_id: Account Identifier - - postfix_id: The identifier of the message. - - submission: When true, search the submissions datastore only. When false or omitted, search - the regular datastore only. - - 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 postfix_id: - raise ValueError(f"Expected a non-empty value for `postfix_id` but received {postfix_id!r}") - return await self._get( - path_template( - "/accounts/{account_id}/email-security/investigate/{postfix_id}/trace", - account_id=account_id, - postfix_id=postfix_id, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform({"submission": submission}, trace_get_params.TraceGetParams), - post_parser=ResultWrapper[TraceGetResponse]._unwrapper, - ), - cast_to=cast(Type[TraceGetResponse], ResultWrapper[TraceGetResponse]), - ) - - -class TraceResourceWithRawResponse: - def __init__(self, trace: TraceResource) -> None: - self._trace = trace - - self.get = to_raw_response_wrapper( - trace.get, - ) - - -class AsyncTraceResourceWithRawResponse: - def __init__(self, trace: AsyncTraceResource) -> None: - self._trace = trace - - self.get = async_to_raw_response_wrapper( - trace.get, - ) - - -class TraceResourceWithStreamingResponse: - def __init__(self, trace: TraceResource) -> None: - self._trace = trace - - self.get = to_streamed_response_wrapper( - trace.get, - ) - - -class AsyncTraceResourceWithStreamingResponse: - def __init__(self, trace: AsyncTraceResource) -> None: - self._trace = trace - - self.get = async_to_streamed_response_wrapper( - trace.get, - ) diff --git a/src/cloudflare/resources/email_security/phishguard/reports.py b/src/cloudflare/resources/email_security/phishguard/reports.py index b41c7cdaefc..06029293bc6 100644 --- a/src/cloudflare/resources/email_security/phishguard/reports.py +++ b/src/cloudflare/resources/email_security/phishguard/reports.py @@ -60,16 +60,22 @@ def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncSinglePage[ReportListResponse]: - """ - Retrieves `PhishGuard` reports showing phishing attempts and suspicious email - patterns detected. + """Retrieves PhishGuard security alert reports for a specified date range. + + Reports + include detected threats, dispositions, and contextual information. Use for + security monitoring and threat analysis. Args: - account_id: Account Identifier + account_id: Identifier. + + end: End of the time range (RFC3339). Takes precedence over to_date. + + from_date: Deprecated, use `start` instead. Start date in YYYY-MM-DD format. - end: The end of the search date range (RFC3339 format). + start: Start of the time range (RFC3339). Takes precedence over from_date. - start: The beginning of the search date range (RFC3339 format). + to_date: Deprecated, use `end` instead. End date in YYYY-MM-DD format. extra_headers: Send extra headers @@ -138,16 +144,22 @@ def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[ReportListResponse, AsyncSinglePage[ReportListResponse]]: - """ - Retrieves `PhishGuard` reports showing phishing attempts and suspicious email - patterns detected. + """Retrieves PhishGuard security alert reports for a specified date range. + + Reports + include detected threats, dispositions, and contextual information. Use for + security monitoring and threat analysis. Args: - account_id: Account Identifier + account_id: Identifier. + + end: End of the time range (RFC3339). Takes precedence over to_date. + + from_date: Deprecated, use `start` instead. Start date in YYYY-MM-DD format. - end: The end of the search date range (RFC3339 format). + start: Start of the time range (RFC3339). Takes precedence over from_date. - start: The beginning of the search date range (RFC3339 format). + to_date: Deprecated, use `end` instead. End date in YYYY-MM-DD format. extra_headers: Send extra headers diff --git a/src/cloudflare/resources/email_security/settings/allow_policies.py b/src/cloudflare/resources/email_security/settings/allow_policies.py index d9c3950c649..67b7f077364 100644 --- a/src/cloudflare/resources/email_security/settings/allow_policies.py +++ b/src/cloudflare/resources/email_security/settings/allow_policies.py @@ -75,25 +75,42 @@ def create( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AllowPolicyCreateResponse: - """ - Creates a new email allow policy that permits specific senders, domains, or - patterns to bypass security scanning. + ) -> Optional[AllowPolicyCreateResponse]: + """Creates a new allow policy that exempts matching emails from security + detections. + + Use with caution as this bypasses email security scanning. Policies + can match on sender patterns and apply to specific detections or all detections. Args: - account_id: Account Identifier + account_id: Identifier. is_acceptable_sender: Messages from this sender will be exempted from Spam, Spoof and Bulk - dispositions. Note: This will not exempt messages with Malicious or Suspicious + dispositions. Note - This will not exempt messages with Malicious or Suspicious dispositions. - is_exempt_recipient: Messages to this recipient will bypass all detections. + is_exempt_recipient: Messages to this recipient will bypass all detections + + is_trusted_sender: Messages from this sender will bypass all detections and link following - is_trusted_sender: Messages from this sender will bypass all detections and link following. + pattern_type: Type of pattern matching. Note: UNKNOWN is deprecated and cannot be used when + creating or updating policies, but may be returned for existing entries. verify_sender: Enforce DMARC, SPF or DKIM authentication. When on, Email Security only honors policies that pass authentication. + is_recipient: + Deprecated as of July 1, 2025. Use `is_exempt_recipient` instead. End of life: + July 1, 2026. + + is_sender: + Deprecated as of July 1, 2025. Use `is_trusted_sender` instead. End of life: + July 1, 2026. + + is_spoof: + Deprecated as of July 1, 2025. Use `is_acceptable_sender` instead. End of life: + July 1, 2026. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -127,9 +144,9 @@ def create( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[AllowPolicyCreateResponse]._unwrapper, + post_parser=ResultWrapper[Optional[AllowPolicyCreateResponse]]._unwrapper, ), - cast_to=cast(Type[AllowPolicyCreateResponse], ResultWrapper[AllowPolicyCreateResponse]), + cast_to=cast(Type[Optional[AllowPolicyCreateResponse]], ResultWrapper[AllowPolicyCreateResponse]), ) def list( @@ -139,9 +156,6 @@ def list( direction: Literal["asc", "desc"] | Omit = omit, is_acceptable_sender: bool | Omit = omit, is_exempt_recipient: bool | Omit = omit, - is_recipient: bool | Omit = omit, - is_sender: bool | Omit = omit, - is_spoof: bool | Omit = omit, is_trusted_sender: bool | Omit = omit, order: Literal["pattern", "created_at"] | Omit = omit, page: int | Omit = omit, @@ -157,23 +171,38 @@ def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncV4PagePaginationArray[AllowPolicyListResponse]: - """ - Lists, searches, and sorts an account’s email allow policies. + """Returns a paginated list of email allow policies. + + These policies exempt matching + emails from security detection, allowing them to bypass disposition actions. + Supports filtering by pattern type and policy attributes. Args: - account_id: Account Identifier + account_id: Identifier. direction: The sorting direction. - order: The field to sort by. + is_acceptable_sender: Filter to show only policies where messages from the sender are exempted from + Spam, Spoof, and Bulk dispositions (not Malicious or Suspicious). + + is_exempt_recipient: Filter to show only policies where messages to the recipient bypass all + detections. + + is_trusted_sender: Filter to show only policies where messages from the sender bypass all + detections and link following. - page: The page number of paginated results. + order: Field to sort by. - per_page: The number of results per page. + page: Current page within paginated list of results. - search: Allows searching in multiple properties of a record simultaneously. This - parameter is intended for human users, not automation. Its exact behavior is - intentionally left unspecified and is subject to change in the future. + pattern_type: Type of pattern matching. Note: UNKNOWN is deprecated and cannot be used when + creating or updating policies, but may be returned for existing entries. + + per_page: The number of results per page. Maximum value is 1000. + + search: Search term for filtering records. Behavior may change. + + verify_sender: Filter to show only policies that enforce DMARC, SPF, or DKIM authentication. extra_headers: Send extra headers @@ -198,9 +227,6 @@ def list( "direction": direction, "is_acceptable_sender": is_acceptable_sender, "is_exempt_recipient": is_exempt_recipient, - "is_recipient": is_recipient, - "is_sender": is_sender, - "is_spoof": is_spoof, "is_trusted_sender": is_trusted_sender, "order": order, "page": page, @@ -218,7 +244,7 @@ def list( def delete( self, - policy_id: int, + policy_id: str, *, account_id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -227,16 +253,16 @@ def delete( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AllowPolicyDeleteResponse: - """Removes an email allow policy. + ) -> Optional[AllowPolicyDeleteResponse]: + """Removes an allow policy. - Previously allowed senders will be subject to - normal security scanning. + After deletion, emails matching this pattern will be + subject to normal security scanning and disposition actions. Args: - account_id: Account Identifier + account_id: Identifier. - policy_id: The unique identifier for the allow policy. + policy_id: Allow policy identifier extra_headers: Send extra headers @@ -248,6 +274,8 @@ def delete( """ if not account_id: raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + if not policy_id: + raise ValueError(f"Expected a non-empty value for `policy_id` but received {policy_id!r}") return self._delete( path_template( "/accounts/{account_id}/email-security/settings/allow_policies/{policy_id}", @@ -259,47 +287,66 @@ def delete( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[AllowPolicyDeleteResponse]._unwrapper, + post_parser=ResultWrapper[Optional[AllowPolicyDeleteResponse]]._unwrapper, ), - cast_to=cast(Type[AllowPolicyDeleteResponse], ResultWrapper[AllowPolicyDeleteResponse]), + cast_to=cast(Type[Optional[AllowPolicyDeleteResponse]], ResultWrapper[AllowPolicyDeleteResponse]), ) def edit( self, - policy_id: int, + policy_id: str, *, account_id: str, comments: Optional[str] | Omit = omit, - is_acceptable_sender: Optional[bool] | Omit = omit, - is_exempt_recipient: Optional[bool] | Omit = omit, - is_regex: Optional[bool] | Omit = omit, - is_trusted_sender: Optional[bool] | Omit = omit, - pattern: Optional[str] | Omit = omit, - pattern_type: Optional[Literal["EMAIL", "DOMAIN", "IP", "UNKNOWN"]] | Omit = omit, - verify_sender: Optional[bool] | Omit = omit, + is_acceptable_sender: bool | Omit = omit, + is_exempt_recipient: bool | Omit = omit, + is_recipient: bool | Omit = omit, + is_regex: bool | Omit = omit, + is_sender: bool | Omit = omit, + is_spoof: bool | Omit = omit, + is_trusted_sender: bool | Omit = omit, + pattern: str | Omit = omit, + pattern_type: Literal["EMAIL", "DOMAIN", "IP", "UNKNOWN"] | Omit = omit, + verify_sender: bool | Omit = omit, # 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, - ) -> AllowPolicyEditResponse: - """ - Updates an existing email allow policy, modifying its matching criteria or - scope. + ) -> Optional[AllowPolicyEditResponse]: + """Updates an existing allow policy. + + Only provided fields will be modified. Changes + take effect for new emails matching the pattern. Args: - account_id: Account Identifier + account_id: Identifier. - policy_id: The unique identifier for the allow policy. + policy_id: Allow policy identifier is_acceptable_sender: Messages from this sender will be exempted from Spam, Spoof and Bulk - dispositions. Note: This will not exempt messages with Malicious or Suspicious + dispositions. Note - This will not exempt messages with Malicious or Suspicious dispositions. - is_exempt_recipient: Messages to this recipient will bypass all detections. + is_exempt_recipient: Messages to this recipient will bypass all detections + + is_recipient: + Deprecated as of July 1, 2025. Use `is_exempt_recipient` instead. End of life: + July 1, 2026. + + is_sender: + Deprecated as of July 1, 2025. Use `is_trusted_sender` instead. End of life: + July 1, 2026. + + is_spoof: + Deprecated as of July 1, 2025. Use `is_acceptable_sender` instead. End of life: + July 1, 2026. - is_trusted_sender: Messages from this sender will bypass all detections and link following. + is_trusted_sender: Messages from this sender will bypass all detections and link following + + pattern_type: Type of pattern matching. Note: UNKNOWN is deprecated and cannot be used when + creating or updating policies, but may be returned for existing entries. verify_sender: Enforce DMARC, SPF or DKIM authentication. When on, Email Security only honors policies that pass authentication. @@ -314,6 +361,8 @@ def edit( """ if not account_id: raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + if not policy_id: + raise ValueError(f"Expected a non-empty value for `policy_id` but received {policy_id!r}") return self._patch( path_template( "/accounts/{account_id}/email-security/settings/allow_policies/{policy_id}", @@ -325,7 +374,10 @@ def edit( "comments": comments, "is_acceptable_sender": is_acceptable_sender, "is_exempt_recipient": is_exempt_recipient, + "is_recipient": is_recipient, "is_regex": is_regex, + "is_sender": is_sender, + "is_spoof": is_spoof, "is_trusted_sender": is_trusted_sender, "pattern": pattern, "pattern_type": pattern_type, @@ -338,14 +390,14 @@ def edit( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[AllowPolicyEditResponse]._unwrapper, + post_parser=ResultWrapper[Optional[AllowPolicyEditResponse]]._unwrapper, ), - cast_to=cast(Type[AllowPolicyEditResponse], ResultWrapper[AllowPolicyEditResponse]), + cast_to=cast(Type[Optional[AllowPolicyEditResponse]], ResultWrapper[AllowPolicyEditResponse]), ) def get( self, - policy_id: int, + policy_id: str, *, account_id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -354,15 +406,15 @@ def get( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AllowPolicyGetResponse: + ) -> Optional[AllowPolicyGetResponse]: """ - Retrieves details for a specific email allow policy, including its matching - criteria and scope. + Retrieves details for a specific allow policy including its pattern, + dispositions that are exempted, and whether it applies to all detections. Args: - account_id: Account Identifier + account_id: Identifier. - policy_id: The unique identifier for the allow policy. + policy_id: Allow policy identifier extra_headers: Send extra headers @@ -374,6 +426,8 @@ def get( """ if not account_id: raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + if not policy_id: + raise ValueError(f"Expected a non-empty value for `policy_id` but received {policy_id!r}") return self._get( path_template( "/accounts/{account_id}/email-security/settings/allow_policies/{policy_id}", @@ -385,9 +439,9 @@ def get( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[AllowPolicyGetResponse]._unwrapper, + post_parser=ResultWrapper[Optional[AllowPolicyGetResponse]]._unwrapper, ), - cast_to=cast(Type[AllowPolicyGetResponse], ResultWrapper[AllowPolicyGetResponse]), + cast_to=cast(Type[Optional[AllowPolicyGetResponse]], ResultWrapper[AllowPolicyGetResponse]), ) @@ -432,25 +486,42 @@ async def create( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AllowPolicyCreateResponse: - """ - Creates a new email allow policy that permits specific senders, domains, or - patterns to bypass security scanning. + ) -> Optional[AllowPolicyCreateResponse]: + """Creates a new allow policy that exempts matching emails from security + detections. + + Use with caution as this bypasses email security scanning. Policies + can match on sender patterns and apply to specific detections or all detections. Args: - account_id: Account Identifier + account_id: Identifier. is_acceptable_sender: Messages from this sender will be exempted from Spam, Spoof and Bulk - dispositions. Note: This will not exempt messages with Malicious or Suspicious + dispositions. Note - This will not exempt messages with Malicious or Suspicious dispositions. - is_exempt_recipient: Messages to this recipient will bypass all detections. + is_exempt_recipient: Messages to this recipient will bypass all detections + + is_trusted_sender: Messages from this sender will bypass all detections and link following - is_trusted_sender: Messages from this sender will bypass all detections and link following. + pattern_type: Type of pattern matching. Note: UNKNOWN is deprecated and cannot be used when + creating or updating policies, but may be returned for existing entries. verify_sender: Enforce DMARC, SPF or DKIM authentication. When on, Email Security only honors policies that pass authentication. + is_recipient: + Deprecated as of July 1, 2025. Use `is_exempt_recipient` instead. End of life: + July 1, 2026. + + is_sender: + Deprecated as of July 1, 2025. Use `is_trusted_sender` instead. End of life: + July 1, 2026. + + is_spoof: + Deprecated as of July 1, 2025. Use `is_acceptable_sender` instead. End of life: + July 1, 2026. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -484,9 +555,9 @@ async def create( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[AllowPolicyCreateResponse]._unwrapper, + post_parser=ResultWrapper[Optional[AllowPolicyCreateResponse]]._unwrapper, ), - cast_to=cast(Type[AllowPolicyCreateResponse], ResultWrapper[AllowPolicyCreateResponse]), + cast_to=cast(Type[Optional[AllowPolicyCreateResponse]], ResultWrapper[AllowPolicyCreateResponse]), ) def list( @@ -496,9 +567,6 @@ def list( direction: Literal["asc", "desc"] | Omit = omit, is_acceptable_sender: bool | Omit = omit, is_exempt_recipient: bool | Omit = omit, - is_recipient: bool | Omit = omit, - is_sender: bool | Omit = omit, - is_spoof: bool | Omit = omit, is_trusted_sender: bool | Omit = omit, order: Literal["pattern", "created_at"] | Omit = omit, page: int | Omit = omit, @@ -514,23 +582,38 @@ def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[AllowPolicyListResponse, AsyncV4PagePaginationArray[AllowPolicyListResponse]]: - """ - Lists, searches, and sorts an account’s email allow policies. + """Returns a paginated list of email allow policies. + + These policies exempt matching + emails from security detection, allowing them to bypass disposition actions. + Supports filtering by pattern type and policy attributes. Args: - account_id: Account Identifier + account_id: Identifier. direction: The sorting direction. - order: The field to sort by. + is_acceptable_sender: Filter to show only policies where messages from the sender are exempted from + Spam, Spoof, and Bulk dispositions (not Malicious or Suspicious). + + is_exempt_recipient: Filter to show only policies where messages to the recipient bypass all + detections. + + is_trusted_sender: Filter to show only policies where messages from the sender bypass all + detections and link following. - page: The page number of paginated results. + order: Field to sort by. - per_page: The number of results per page. + page: Current page within paginated list of results. - search: Allows searching in multiple properties of a record simultaneously. This - parameter is intended for human users, not automation. Its exact behavior is - intentionally left unspecified and is subject to change in the future. + pattern_type: Type of pattern matching. Note: UNKNOWN is deprecated and cannot be used when + creating or updating policies, but may be returned for existing entries. + + per_page: The number of results per page. Maximum value is 1000. + + search: Search term for filtering records. Behavior may change. + + verify_sender: Filter to show only policies that enforce DMARC, SPF, or DKIM authentication. extra_headers: Send extra headers @@ -555,9 +638,6 @@ def list( "direction": direction, "is_acceptable_sender": is_acceptable_sender, "is_exempt_recipient": is_exempt_recipient, - "is_recipient": is_recipient, - "is_sender": is_sender, - "is_spoof": is_spoof, "is_trusted_sender": is_trusted_sender, "order": order, "page": page, @@ -575,7 +655,7 @@ def list( async def delete( self, - policy_id: int, + policy_id: str, *, account_id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -584,16 +664,16 @@ async def delete( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AllowPolicyDeleteResponse: - """Removes an email allow policy. + ) -> Optional[AllowPolicyDeleteResponse]: + """Removes an allow policy. - Previously allowed senders will be subject to - normal security scanning. + After deletion, emails matching this pattern will be + subject to normal security scanning and disposition actions. Args: - account_id: Account Identifier + account_id: Identifier. - policy_id: The unique identifier for the allow policy. + policy_id: Allow policy identifier extra_headers: Send extra headers @@ -605,6 +685,8 @@ async def delete( """ if not account_id: raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + if not policy_id: + raise ValueError(f"Expected a non-empty value for `policy_id` but received {policy_id!r}") return await self._delete( path_template( "/accounts/{account_id}/email-security/settings/allow_policies/{policy_id}", @@ -616,47 +698,66 @@ async def delete( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[AllowPolicyDeleteResponse]._unwrapper, + post_parser=ResultWrapper[Optional[AllowPolicyDeleteResponse]]._unwrapper, ), - cast_to=cast(Type[AllowPolicyDeleteResponse], ResultWrapper[AllowPolicyDeleteResponse]), + cast_to=cast(Type[Optional[AllowPolicyDeleteResponse]], ResultWrapper[AllowPolicyDeleteResponse]), ) async def edit( self, - policy_id: int, + policy_id: str, *, account_id: str, comments: Optional[str] | Omit = omit, - is_acceptable_sender: Optional[bool] | Omit = omit, - is_exempt_recipient: Optional[bool] | Omit = omit, - is_regex: Optional[bool] | Omit = omit, - is_trusted_sender: Optional[bool] | Omit = omit, - pattern: Optional[str] | Omit = omit, - pattern_type: Optional[Literal["EMAIL", "DOMAIN", "IP", "UNKNOWN"]] | Omit = omit, - verify_sender: Optional[bool] | Omit = omit, + is_acceptable_sender: bool | Omit = omit, + is_exempt_recipient: bool | Omit = omit, + is_recipient: bool | Omit = omit, + is_regex: bool | Omit = omit, + is_sender: bool | Omit = omit, + is_spoof: bool | Omit = omit, + is_trusted_sender: bool | Omit = omit, + pattern: str | Omit = omit, + pattern_type: Literal["EMAIL", "DOMAIN", "IP", "UNKNOWN"] | Omit = omit, + verify_sender: bool | Omit = omit, # 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, - ) -> AllowPolicyEditResponse: - """ - Updates an existing email allow policy, modifying its matching criteria or - scope. + ) -> Optional[AllowPolicyEditResponse]: + """Updates an existing allow policy. + + Only provided fields will be modified. Changes + take effect for new emails matching the pattern. Args: - account_id: Account Identifier + account_id: Identifier. - policy_id: The unique identifier for the allow policy. + policy_id: Allow policy identifier is_acceptable_sender: Messages from this sender will be exempted from Spam, Spoof and Bulk - dispositions. Note: This will not exempt messages with Malicious or Suspicious + dispositions. Note - This will not exempt messages with Malicious or Suspicious dispositions. - is_exempt_recipient: Messages to this recipient will bypass all detections. + is_exempt_recipient: Messages to this recipient will bypass all detections + + is_recipient: + Deprecated as of July 1, 2025. Use `is_exempt_recipient` instead. End of life: + July 1, 2026. + + is_sender: + Deprecated as of July 1, 2025. Use `is_trusted_sender` instead. End of life: + July 1, 2026. + + is_spoof: + Deprecated as of July 1, 2025. Use `is_acceptable_sender` instead. End of life: + July 1, 2026. - is_trusted_sender: Messages from this sender will bypass all detections and link following. + is_trusted_sender: Messages from this sender will bypass all detections and link following + + pattern_type: Type of pattern matching. Note: UNKNOWN is deprecated and cannot be used when + creating or updating policies, but may be returned for existing entries. verify_sender: Enforce DMARC, SPF or DKIM authentication. When on, Email Security only honors policies that pass authentication. @@ -671,6 +772,8 @@ async def edit( """ if not account_id: raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + if not policy_id: + raise ValueError(f"Expected a non-empty value for `policy_id` but received {policy_id!r}") return await self._patch( path_template( "/accounts/{account_id}/email-security/settings/allow_policies/{policy_id}", @@ -682,7 +785,10 @@ async def edit( "comments": comments, "is_acceptable_sender": is_acceptable_sender, "is_exempt_recipient": is_exempt_recipient, + "is_recipient": is_recipient, "is_regex": is_regex, + "is_sender": is_sender, + "is_spoof": is_spoof, "is_trusted_sender": is_trusted_sender, "pattern": pattern, "pattern_type": pattern_type, @@ -695,14 +801,14 @@ async def edit( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[AllowPolicyEditResponse]._unwrapper, + post_parser=ResultWrapper[Optional[AllowPolicyEditResponse]]._unwrapper, ), - cast_to=cast(Type[AllowPolicyEditResponse], ResultWrapper[AllowPolicyEditResponse]), + cast_to=cast(Type[Optional[AllowPolicyEditResponse]], ResultWrapper[AllowPolicyEditResponse]), ) async def get( self, - policy_id: int, + policy_id: str, *, account_id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -711,15 +817,15 @@ async def get( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AllowPolicyGetResponse: + ) -> Optional[AllowPolicyGetResponse]: """ - Retrieves details for a specific email allow policy, including its matching - criteria and scope. + Retrieves details for a specific allow policy including its pattern, + dispositions that are exempted, and whether it applies to all detections. Args: - account_id: Account Identifier + account_id: Identifier. - policy_id: The unique identifier for the allow policy. + policy_id: Allow policy identifier extra_headers: Send extra headers @@ -731,6 +837,8 @@ async def get( """ if not account_id: raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + if not policy_id: + raise ValueError(f"Expected a non-empty value for `policy_id` but received {policy_id!r}") return await self._get( path_template( "/accounts/{account_id}/email-security/settings/allow_policies/{policy_id}", @@ -742,9 +850,9 @@ async def get( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[AllowPolicyGetResponse]._unwrapper, + post_parser=ResultWrapper[Optional[AllowPolicyGetResponse]]._unwrapper, ), - cast_to=cast(Type[AllowPolicyGetResponse], ResultWrapper[AllowPolicyGetResponse]), + cast_to=cast(Type[Optional[AllowPolicyGetResponse]], ResultWrapper[AllowPolicyGetResponse]), ) diff --git a/src/cloudflare/resources/email_security/settings/block_senders.py b/src/cloudflare/resources/email_security/settings/block_senders.py index 9f22d1a96a5..b0c57670eac 100644 --- a/src/cloudflare/resources/email_security/settings/block_senders.py +++ b/src/cloudflare/resources/email_security/settings/block_senders.py @@ -68,13 +68,18 @@ def create( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> BlockSenderCreateResponse: - """ - Adds a sender pattern to the email block list, preventing messages from matching - senders from being delivered. + ) -> Optional[BlockSenderCreateResponse]: + """Creates a new blocked sender pattern. + + Emails matching this pattern will be + blocked from delivery. Patterns can be email addresses, domains, or IP + addresses, and support regular expressions. Args: - account_id: Account Identifier + account_id: Identifier. + + pattern_type: Type of pattern matching. Note: UNKNOWN is deprecated and cannot be used when + creating or updating policies, but may be returned for existing entries. extra_headers: Send extra headers @@ -102,9 +107,9 @@ def create( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[BlockSenderCreateResponse]._unwrapper, + post_parser=ResultWrapper[Optional[BlockSenderCreateResponse]]._unwrapper, ), - cast_to=cast(Type[BlockSenderCreateResponse], ResultWrapper[BlockSenderCreateResponse]), + cast_to=cast(Type[Optional[BlockSenderCreateResponse]], ResultWrapper[BlockSenderCreateResponse]), ) def list( @@ -125,23 +130,28 @@ def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncV4PagePaginationArray[BlockSenderListResponse]: - """ - Lists all blocked sender entries with their patterns and block reasons. + """Returns a paginated list of blocked email sender patterns. + + These patterns + prevent emails from matching senders from being delivered. Supports filtering by + pattern type and searching across patterns. Args: - account_id: Account Identifier + account_id: Identifier. direction: The sorting direction. - order: The field to sort by. + order: Field to sort by. + + page: Current page within paginated list of results. + + pattern: Filter by pattern value. - page: The page number of paginated results. + pattern_type: Filter by pattern type. - per_page: The number of results per page. + per_page: The number of results per page. Maximum value is 1000. - search: Allows searching in multiple properties of a record simultaneously. This - parameter is intended for human users, not automation. Its exact behavior is - intentionally left unspecified and is subject to change in the future. + search: Search term for filtering records. Behavior may change. extra_headers: Send extra headers @@ -179,7 +189,7 @@ def list( def delete( self, - pattern_id: int, + pattern_id: str, *, account_id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -188,15 +198,16 @@ def delete( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> BlockSenderDeleteResponse: - """ - Removes a sender from the email block list, allowing their messages to be - delivered normally. + ) -> Optional[BlockSenderDeleteResponse]: + """Removes a blocked sender pattern. + + After deletion, emails from this sender will + no longer be automatically blocked based on this rule. Args: - account_id: Account Identifier + account_id: Identifier. - pattern_id: The unique identifier for the allow policy. + pattern_id: Blocked sender pattern identifier extra_headers: Send extra headers @@ -208,6 +219,8 @@ def delete( """ if not account_id: raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + if not pattern_id: + raise ValueError(f"Expected a non-empty value for `pattern_id` but received {pattern_id!r}") return self._delete( path_template( "/accounts/{account_id}/email-security/settings/block_senders/{pattern_id}", @@ -219,34 +232,39 @@ def delete( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[BlockSenderDeleteResponse]._unwrapper, + post_parser=ResultWrapper[Optional[BlockSenderDeleteResponse]]._unwrapper, ), - cast_to=cast(Type[BlockSenderDeleteResponse], ResultWrapper[BlockSenderDeleteResponse]), + cast_to=cast(Type[Optional[BlockSenderDeleteResponse]], ResultWrapper[BlockSenderDeleteResponse]), ) def edit( self, - pattern_id: int, + pattern_id: str, *, account_id: str, comments: Optional[str] | Omit = omit, - is_regex: Optional[bool] | Omit = omit, - pattern: Optional[str] | Omit = omit, - pattern_type: Optional[Literal["EMAIL", "DOMAIN", "IP", "UNKNOWN"]] | Omit = omit, + is_regex: bool | Omit = omit, + pattern: str | Omit = omit, + pattern_type: Literal["EMAIL", "DOMAIN", "IP", "UNKNOWN"] | Omit = omit, # 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, - ) -> BlockSenderEditResponse: - """ - Modifies a blocked sender entry, updating its pattern or block reason. + ) -> Optional[BlockSenderEditResponse]: + """Updates an existing blocked sender pattern. + + Only provided fields will be + modified. The pattern will continue blocking emails until deleted. Args: - account_id: Account Identifier + account_id: Identifier. + + pattern_id: Blocked sender pattern identifier - pattern_id: The unique identifier for the allow policy. + pattern_type: Type of pattern matching. Note: UNKNOWN is deprecated and cannot be used when + creating or updating policies, but may be returned for existing entries. extra_headers: Send extra headers @@ -258,6 +276,8 @@ def edit( """ if not account_id: raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + if not pattern_id: + raise ValueError(f"Expected a non-empty value for `pattern_id` but received {pattern_id!r}") return self._patch( path_template( "/accounts/{account_id}/email-security/settings/block_senders/{pattern_id}", @@ -278,14 +298,14 @@ def edit( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[BlockSenderEditResponse]._unwrapper, + post_parser=ResultWrapper[Optional[BlockSenderEditResponse]]._unwrapper, ), - cast_to=cast(Type[BlockSenderEditResponse], ResultWrapper[BlockSenderEditResponse]), + cast_to=cast(Type[Optional[BlockSenderEditResponse]], ResultWrapper[BlockSenderEditResponse]), ) def get( self, - pattern_id: int, + pattern_id: str, *, account_id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -294,15 +314,15 @@ def get( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> BlockSenderGetResponse: + ) -> Optional[BlockSenderGetResponse]: """ - Gets information about a specific blocked sender entry, including the pattern - and block reason. + Retrieves details for a specific blocked sender pattern including its pattern + type, value, and metadata. Args: - account_id: Account Identifier + account_id: Identifier. - pattern_id: The unique identifier for the allow policy. + pattern_id: Blocked sender pattern identifier extra_headers: Send extra headers @@ -314,6 +334,8 @@ def get( """ if not account_id: raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + if not pattern_id: + raise ValueError(f"Expected a non-empty value for `pattern_id` but received {pattern_id!r}") return self._get( path_template( "/accounts/{account_id}/email-security/settings/block_senders/{pattern_id}", @@ -325,9 +347,9 @@ def get( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[BlockSenderGetResponse]._unwrapper, + post_parser=ResultWrapper[Optional[BlockSenderGetResponse]]._unwrapper, ), - cast_to=cast(Type[BlockSenderGetResponse], ResultWrapper[BlockSenderGetResponse]), + cast_to=cast(Type[Optional[BlockSenderGetResponse]], ResultWrapper[BlockSenderGetResponse]), ) @@ -365,13 +387,18 @@ async def create( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> BlockSenderCreateResponse: - """ - Adds a sender pattern to the email block list, preventing messages from matching - senders from being delivered. + ) -> Optional[BlockSenderCreateResponse]: + """Creates a new blocked sender pattern. + + Emails matching this pattern will be + blocked from delivery. Patterns can be email addresses, domains, or IP + addresses, and support regular expressions. Args: - account_id: Account Identifier + account_id: Identifier. + + pattern_type: Type of pattern matching. Note: UNKNOWN is deprecated and cannot be used when + creating or updating policies, but may be returned for existing entries. extra_headers: Send extra headers @@ -399,9 +426,9 @@ async def create( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[BlockSenderCreateResponse]._unwrapper, + post_parser=ResultWrapper[Optional[BlockSenderCreateResponse]]._unwrapper, ), - cast_to=cast(Type[BlockSenderCreateResponse], ResultWrapper[BlockSenderCreateResponse]), + cast_to=cast(Type[Optional[BlockSenderCreateResponse]], ResultWrapper[BlockSenderCreateResponse]), ) def list( @@ -422,23 +449,28 @@ def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[BlockSenderListResponse, AsyncV4PagePaginationArray[BlockSenderListResponse]]: - """ - Lists all blocked sender entries with their patterns and block reasons. + """Returns a paginated list of blocked email sender patterns. + + These patterns + prevent emails from matching senders from being delivered. Supports filtering by + pattern type and searching across patterns. Args: - account_id: Account Identifier + account_id: Identifier. direction: The sorting direction. - order: The field to sort by. + order: Field to sort by. + + page: Current page within paginated list of results. + + pattern: Filter by pattern value. - page: The page number of paginated results. + pattern_type: Filter by pattern type. - per_page: The number of results per page. + per_page: The number of results per page. Maximum value is 1000. - search: Allows searching in multiple properties of a record simultaneously. This - parameter is intended for human users, not automation. Its exact behavior is - intentionally left unspecified and is subject to change in the future. + search: Search term for filtering records. Behavior may change. extra_headers: Send extra headers @@ -476,7 +508,7 @@ def list( async def delete( self, - pattern_id: int, + pattern_id: str, *, account_id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -485,15 +517,16 @@ async def delete( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> BlockSenderDeleteResponse: - """ - Removes a sender from the email block list, allowing their messages to be - delivered normally. + ) -> Optional[BlockSenderDeleteResponse]: + """Removes a blocked sender pattern. + + After deletion, emails from this sender will + no longer be automatically blocked based on this rule. Args: - account_id: Account Identifier + account_id: Identifier. - pattern_id: The unique identifier for the allow policy. + pattern_id: Blocked sender pattern identifier extra_headers: Send extra headers @@ -505,6 +538,8 @@ async def delete( """ if not account_id: raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + if not pattern_id: + raise ValueError(f"Expected a non-empty value for `pattern_id` but received {pattern_id!r}") return await self._delete( path_template( "/accounts/{account_id}/email-security/settings/block_senders/{pattern_id}", @@ -516,34 +551,39 @@ async def delete( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[BlockSenderDeleteResponse]._unwrapper, + post_parser=ResultWrapper[Optional[BlockSenderDeleteResponse]]._unwrapper, ), - cast_to=cast(Type[BlockSenderDeleteResponse], ResultWrapper[BlockSenderDeleteResponse]), + cast_to=cast(Type[Optional[BlockSenderDeleteResponse]], ResultWrapper[BlockSenderDeleteResponse]), ) async def edit( self, - pattern_id: int, + pattern_id: str, *, account_id: str, comments: Optional[str] | Omit = omit, - is_regex: Optional[bool] | Omit = omit, - pattern: Optional[str] | Omit = omit, - pattern_type: Optional[Literal["EMAIL", "DOMAIN", "IP", "UNKNOWN"]] | Omit = omit, + is_regex: bool | Omit = omit, + pattern: str | Omit = omit, + pattern_type: Literal["EMAIL", "DOMAIN", "IP", "UNKNOWN"] | Omit = omit, # 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, - ) -> BlockSenderEditResponse: - """ - Modifies a blocked sender entry, updating its pattern or block reason. + ) -> Optional[BlockSenderEditResponse]: + """Updates an existing blocked sender pattern. + + Only provided fields will be + modified. The pattern will continue blocking emails until deleted. Args: - account_id: Account Identifier + account_id: Identifier. + + pattern_id: Blocked sender pattern identifier - pattern_id: The unique identifier for the allow policy. + pattern_type: Type of pattern matching. Note: UNKNOWN is deprecated and cannot be used when + creating or updating policies, but may be returned for existing entries. extra_headers: Send extra headers @@ -555,6 +595,8 @@ async def edit( """ if not account_id: raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + if not pattern_id: + raise ValueError(f"Expected a non-empty value for `pattern_id` but received {pattern_id!r}") return await self._patch( path_template( "/accounts/{account_id}/email-security/settings/block_senders/{pattern_id}", @@ -575,14 +617,14 @@ async def edit( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[BlockSenderEditResponse]._unwrapper, + post_parser=ResultWrapper[Optional[BlockSenderEditResponse]]._unwrapper, ), - cast_to=cast(Type[BlockSenderEditResponse], ResultWrapper[BlockSenderEditResponse]), + cast_to=cast(Type[Optional[BlockSenderEditResponse]], ResultWrapper[BlockSenderEditResponse]), ) async def get( self, - pattern_id: int, + pattern_id: str, *, account_id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -591,15 +633,15 @@ async def get( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> BlockSenderGetResponse: + ) -> Optional[BlockSenderGetResponse]: """ - Gets information about a specific blocked sender entry, including the pattern - and block reason. + Retrieves details for a specific blocked sender pattern including its pattern + type, value, and metadata. Args: - account_id: Account Identifier + account_id: Identifier. - pattern_id: The unique identifier for the allow policy. + pattern_id: Blocked sender pattern identifier extra_headers: Send extra headers @@ -611,6 +653,8 @@ async def get( """ if not account_id: raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + if not pattern_id: + raise ValueError(f"Expected a non-empty value for `pattern_id` but received {pattern_id!r}") return await self._get( path_template( "/accounts/{account_id}/email-security/settings/block_senders/{pattern_id}", @@ -622,9 +666,9 @@ async def get( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[BlockSenderGetResponse]._unwrapper, + post_parser=ResultWrapper[Optional[BlockSenderGetResponse]]._unwrapper, ), - cast_to=cast(Type[BlockSenderGetResponse], ResultWrapper[BlockSenderGetResponse]), + cast_to=cast(Type[Optional[BlockSenderGetResponse]], ResultWrapper[BlockSenderGetResponse]), ) diff --git a/src/cloudflare/resources/email_security/settings/domains.py b/src/cloudflare/resources/email_security/settings/domains.py index 46628f5da7a..c8ca2d9854a 100644 --- a/src/cloudflare/resources/email_security/settings/domains.py +++ b/src/cloudflare/resources/email_security/settings/domains.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import List, Type, cast +from typing import List, Type, Optional, cast from typing_extensions import Literal import httpx @@ -18,14 +18,13 @@ async_to_streamed_response_wrapper, ) from ...._wrappers import ResultWrapper -from ....pagination import SyncSinglePage, AsyncSinglePage, SyncV4PagePaginationArray, AsyncV4PagePaginationArray +from ....pagination import SyncV4PagePaginationArray, AsyncV4PagePaginationArray from ...._base_client import AsyncPaginator, make_request_options from ....types.email_security.settings import domain_edit_params, domain_list_params from ....types.email_security.settings.domain_get_response import DomainGetResponse from ....types.email_security.settings.domain_edit_response import DomainEditResponse from ....types.email_security.settings.domain_list_response import DomainListResponse from ....types.email_security.settings.domain_delete_response import DomainDeleteResponse -from ....types.email_security.settings.domain_bulk_delete_response import DomainBulkDeleteResponse __all__ = ["DomainsResource", "AsyncDomainsResource"] @@ -63,6 +62,7 @@ def list( page: int | Omit = omit, per_page: int | Omit = omit, search: str | Omit = omit, + status: Literal["pending", "active", "failed", "timeout"] | Omit = omit, # 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, @@ -70,31 +70,34 @@ def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncV4PagePaginationArray[DomainListResponse]: - """ - Lists, searches, and sorts an account’s email domains. + """Returns a paginated list of email domains protected by Email Security. + + Includes + domain configuration, delivery modes, and authorization status. Supports + filtering by delivery mode and integration ID. Args: - account_id: Account Identifier + account_id: Identifier. - active_delivery_mode: Filters response to domains with the currently active delivery mode. + active_delivery_mode: Currently active delivery mode to filter by. - allowed_delivery_mode: Filters response to domains with the provided delivery mode. + allowed_delivery_mode: Delivery mode to filter by. direction: The sorting direction. - domain: Filters results by the provided domains, allowing for multiple occurrences. + domain: Domain names to filter by. + + integration_id: Integration ID to filter by. - integration_id: Filters response to domains with the provided integration ID. + order: Field to sort by. - order: The field to sort by. + page: Current page within paginated list of results. - page: The page number of paginated results. + per_page: The number of results per page. Maximum value is 1000. - per_page: The number of results per page. + search: Search term for filtering records. Behavior may change. - search: Allows searching in multiple properties of a record simultaneously. This - parameter is intended for human users, not automation. Its exact behavior is - intentionally left unspecified and is subject to change in the future. + status: Filters response to domains with the provided status. extra_headers: Send extra headers @@ -125,6 +128,7 @@ def list( "page": page, "per_page": per_page, "search": search, + "status": status, }, domain_list_params.DomainListParams, ), @@ -134,7 +138,7 @@ def list( def delete( self, - domain_id: int, + domain_id: str, *, account_id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -143,14 +147,17 @@ def delete( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> DomainDeleteResponse: - """ - Unprotect an email domain + ) -> Optional[DomainDeleteResponse]: + """Removes email security protection from a domain. + + After deletion, emails for this + domain will no longer be processed by Email Security. This action cannot be + undone. Args: - account_id: Account Identifier + account_id: Identifier. - domain_id: The unique identifier for the domain. + domain_id: Domain identifier extra_headers: Send extra headers @@ -162,6 +169,8 @@ def delete( """ if not account_id: raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + if not domain_id: + raise ValueError(f"Expected a non-empty value for `domain_id` but received {domain_id!r}") return self._delete( path_template( "/accounts/{account_id}/email-security/settings/domains/{domain_id}", @@ -173,55 +182,16 @@ def delete( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[DomainDeleteResponse]._unwrapper, + post_parser=ResultWrapper[Optional[DomainDeleteResponse]]._unwrapper, ), - cast_to=cast(Type[DomainDeleteResponse], ResultWrapper[DomainDeleteResponse]), - ) - - def bulk_delete( - 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, - ) -> SyncSinglePage[DomainBulkDeleteResponse]: - """ - Bulk removes multiple domains from email security configuration in a single - request. - - Args: - account_id: Account Identifier - - 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( - path_template("/accounts/{account_id}/email-security/settings/domains", account_id=account_id), - page=SyncSinglePage[DomainBulkDeleteResponse], - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - model=DomainBulkDeleteResponse, - method="delete", + cast_to=cast(Type[Optional[DomainDeleteResponse]], ResultWrapper[DomainDeleteResponse]), ) def edit( self, - domain_id: int, + domain_id: str, *, account_id: str, - ip_restrictions: SequenceNotStr[str], allowed_delivery_modes: List[Literal["DIRECT", "BCC", "JOURNAL", "API", "RETRO_SCAN"]] | Omit = omit, domain: str | Omit = omit, drop_dispositions: List[ @@ -240,7 +210,8 @@ def edit( ] | Omit = omit, folder: Literal["AllItems", "Inbox"] | Omit = omit, - integration_id: str | Omit = omit, + integration_id: Optional[str] | Omit = omit, + ip_restrictions: SequenceNotStr[str] | Omit = omit, lookback_hops: int | Omit = omit, regions: List[Literal["GLOBAL", "AU", "DE", "IN", "US"]] | Omit = omit, require_tls_inbound: bool | Omit = omit, @@ -252,14 +223,17 @@ def edit( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> DomainEditResponse: - """ - Updates configuration for a domain in email security. + ) -> Optional[DomainEditResponse]: + """Updates configuration for a protected email domain. + + Only provided fields will be + modified. Changes affect delivery mode, security settings, and regional + processing. Args: - account_id: Account Identifier + account_id: Identifier. - domain_id: The unique identifier for the domain. + domain_id: Domain identifier extra_headers: Send extra headers @@ -271,6 +245,8 @@ def edit( """ if not account_id: raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + if not domain_id: + raise ValueError(f"Expected a non-empty value for `domain_id` but received {domain_id!r}") return self._patch( path_template( "/accounts/{account_id}/email-security/settings/domains/{domain_id}", @@ -279,12 +255,12 @@ def edit( ), body=maybe_transform( { - "ip_restrictions": ip_restrictions, "allowed_delivery_modes": allowed_delivery_modes, "domain": domain, "drop_dispositions": drop_dispositions, "folder": folder, "integration_id": integration_id, + "ip_restrictions": ip_restrictions, "lookback_hops": lookback_hops, "regions": regions, "require_tls_inbound": require_tls_inbound, @@ -298,14 +274,14 @@ def edit( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[DomainEditResponse]._unwrapper, + post_parser=ResultWrapper[Optional[DomainEditResponse]]._unwrapper, ), - cast_to=cast(Type[DomainEditResponse], ResultWrapper[DomainEditResponse]), + cast_to=cast(Type[Optional[DomainEditResponse]], ResultWrapper[DomainEditResponse]), ) def get( self, - domain_id: int, + domain_id: str, *, account_id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -314,14 +290,15 @@ def get( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> DomainGetResponse: + ) -> Optional[DomainGetResponse]: """ - Gets configuration details for a specific domain in email security. + Retrieves detailed information for a specific protected email domain including + its delivery configuration, SPF/DMARC status, and authorization state. Args: - account_id: Account Identifier + account_id: Identifier. - domain_id: The unique identifier for the domain. + domain_id: Domain identifier extra_headers: Send extra headers @@ -333,6 +310,8 @@ def get( """ if not account_id: raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + if not domain_id: + raise ValueError(f"Expected a non-empty value for `domain_id` but received {domain_id!r}") return self._get( path_template( "/accounts/{account_id}/email-security/settings/domains/{domain_id}", @@ -344,9 +323,9 @@ def get( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[DomainGetResponse]._unwrapper, + post_parser=ResultWrapper[Optional[DomainGetResponse]]._unwrapper, ), - cast_to=cast(Type[DomainGetResponse], ResultWrapper[DomainGetResponse]), + cast_to=cast(Type[Optional[DomainGetResponse]], ResultWrapper[DomainGetResponse]), ) @@ -383,6 +362,7 @@ def list( page: int | Omit = omit, per_page: int | Omit = omit, search: str | Omit = omit, + status: Literal["pending", "active", "failed", "timeout"] | Omit = omit, # 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, @@ -390,31 +370,34 @@ def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[DomainListResponse, AsyncV4PagePaginationArray[DomainListResponse]]: - """ - Lists, searches, and sorts an account’s email domains. + """Returns a paginated list of email domains protected by Email Security. + + Includes + domain configuration, delivery modes, and authorization status. Supports + filtering by delivery mode and integration ID. Args: - account_id: Account Identifier + account_id: Identifier. - active_delivery_mode: Filters response to domains with the currently active delivery mode. + active_delivery_mode: Currently active delivery mode to filter by. - allowed_delivery_mode: Filters response to domains with the provided delivery mode. + allowed_delivery_mode: Delivery mode to filter by. direction: The sorting direction. - domain: Filters results by the provided domains, allowing for multiple occurrences. + domain: Domain names to filter by. - integration_id: Filters response to domains with the provided integration ID. + integration_id: Integration ID to filter by. - order: The field to sort by. + order: Field to sort by. - page: The page number of paginated results. + page: Current page within paginated list of results. - per_page: The number of results per page. + per_page: The number of results per page. Maximum value is 1000. - search: Allows searching in multiple properties of a record simultaneously. This - parameter is intended for human users, not automation. Its exact behavior is - intentionally left unspecified and is subject to change in the future. + search: Search term for filtering records. Behavior may change. + + status: Filters response to domains with the provided status. extra_headers: Send extra headers @@ -445,6 +428,7 @@ def list( "page": page, "per_page": per_page, "search": search, + "status": status, }, domain_list_params.DomainListParams, ), @@ -454,7 +438,7 @@ def list( async def delete( self, - domain_id: int, + domain_id: str, *, account_id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -463,14 +447,17 @@ async def delete( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> DomainDeleteResponse: - """ - Unprotect an email domain + ) -> Optional[DomainDeleteResponse]: + """Removes email security protection from a domain. + + After deletion, emails for this + domain will no longer be processed by Email Security. This action cannot be + undone. Args: - account_id: Account Identifier + account_id: Identifier. - domain_id: The unique identifier for the domain. + domain_id: Domain identifier extra_headers: Send extra headers @@ -482,6 +469,8 @@ async def delete( """ if not account_id: raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + if not domain_id: + raise ValueError(f"Expected a non-empty value for `domain_id` but received {domain_id!r}") return await self._delete( path_template( "/accounts/{account_id}/email-security/settings/domains/{domain_id}", @@ -493,55 +482,16 @@ async def delete( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[DomainDeleteResponse]._unwrapper, + post_parser=ResultWrapper[Optional[DomainDeleteResponse]]._unwrapper, ), - cast_to=cast(Type[DomainDeleteResponse], ResultWrapper[DomainDeleteResponse]), - ) - - def bulk_delete( - 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, - ) -> AsyncPaginator[DomainBulkDeleteResponse, AsyncSinglePage[DomainBulkDeleteResponse]]: - """ - Bulk removes multiple domains from email security configuration in a single - request. - - Args: - account_id: Account Identifier - - 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( - path_template("/accounts/{account_id}/email-security/settings/domains", account_id=account_id), - page=AsyncSinglePage[DomainBulkDeleteResponse], - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - model=DomainBulkDeleteResponse, - method="delete", + cast_to=cast(Type[Optional[DomainDeleteResponse]], ResultWrapper[DomainDeleteResponse]), ) async def edit( self, - domain_id: int, + domain_id: str, *, account_id: str, - ip_restrictions: SequenceNotStr[str], allowed_delivery_modes: List[Literal["DIRECT", "BCC", "JOURNAL", "API", "RETRO_SCAN"]] | Omit = omit, domain: str | Omit = omit, drop_dispositions: List[ @@ -560,7 +510,8 @@ async def edit( ] | Omit = omit, folder: Literal["AllItems", "Inbox"] | Omit = omit, - integration_id: str | Omit = omit, + integration_id: Optional[str] | Omit = omit, + ip_restrictions: SequenceNotStr[str] | Omit = omit, lookback_hops: int | Omit = omit, regions: List[Literal["GLOBAL", "AU", "DE", "IN", "US"]] | Omit = omit, require_tls_inbound: bool | Omit = omit, @@ -572,14 +523,17 @@ async def edit( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> DomainEditResponse: - """ - Updates configuration for a domain in email security. + ) -> Optional[DomainEditResponse]: + """Updates configuration for a protected email domain. + + Only provided fields will be + modified. Changes affect delivery mode, security settings, and regional + processing. Args: - account_id: Account Identifier + account_id: Identifier. - domain_id: The unique identifier for the domain. + domain_id: Domain identifier extra_headers: Send extra headers @@ -591,6 +545,8 @@ async def edit( """ if not account_id: raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + if not domain_id: + raise ValueError(f"Expected a non-empty value for `domain_id` but received {domain_id!r}") return await self._patch( path_template( "/accounts/{account_id}/email-security/settings/domains/{domain_id}", @@ -599,12 +555,12 @@ async def edit( ), body=await async_maybe_transform( { - "ip_restrictions": ip_restrictions, "allowed_delivery_modes": allowed_delivery_modes, "domain": domain, "drop_dispositions": drop_dispositions, "folder": folder, "integration_id": integration_id, + "ip_restrictions": ip_restrictions, "lookback_hops": lookback_hops, "regions": regions, "require_tls_inbound": require_tls_inbound, @@ -618,14 +574,14 @@ async def edit( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[DomainEditResponse]._unwrapper, + post_parser=ResultWrapper[Optional[DomainEditResponse]]._unwrapper, ), - cast_to=cast(Type[DomainEditResponse], ResultWrapper[DomainEditResponse]), + cast_to=cast(Type[Optional[DomainEditResponse]], ResultWrapper[DomainEditResponse]), ) async def get( self, - domain_id: int, + domain_id: str, *, account_id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -634,14 +590,15 @@ async def get( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> DomainGetResponse: + ) -> Optional[DomainGetResponse]: """ - Gets configuration details for a specific domain in email security. + Retrieves detailed information for a specific protected email domain including + its delivery configuration, SPF/DMARC status, and authorization state. Args: - account_id: Account Identifier + account_id: Identifier. - domain_id: The unique identifier for the domain. + domain_id: Domain identifier extra_headers: Send extra headers @@ -653,6 +610,8 @@ async def get( """ if not account_id: raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + if not domain_id: + raise ValueError(f"Expected a non-empty value for `domain_id` but received {domain_id!r}") return await self._get( path_template( "/accounts/{account_id}/email-security/settings/domains/{domain_id}", @@ -664,9 +623,9 @@ async def get( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[DomainGetResponse]._unwrapper, + post_parser=ResultWrapper[Optional[DomainGetResponse]]._unwrapper, ), - cast_to=cast(Type[DomainGetResponse], ResultWrapper[DomainGetResponse]), + cast_to=cast(Type[Optional[DomainGetResponse]], ResultWrapper[DomainGetResponse]), ) @@ -680,9 +639,6 @@ def __init__(self, domains: DomainsResource) -> None: self.delete = to_raw_response_wrapper( domains.delete, ) - self.bulk_delete = to_raw_response_wrapper( - domains.bulk_delete, - ) self.edit = to_raw_response_wrapper( domains.edit, ) @@ -701,9 +657,6 @@ def __init__(self, domains: AsyncDomainsResource) -> None: self.delete = async_to_raw_response_wrapper( domains.delete, ) - self.bulk_delete = async_to_raw_response_wrapper( - domains.bulk_delete, - ) self.edit = async_to_raw_response_wrapper( domains.edit, ) @@ -722,9 +675,6 @@ def __init__(self, domains: DomainsResource) -> None: self.delete = to_streamed_response_wrapper( domains.delete, ) - self.bulk_delete = to_streamed_response_wrapper( - domains.bulk_delete, - ) self.edit = to_streamed_response_wrapper( domains.edit, ) @@ -743,9 +693,6 @@ def __init__(self, domains: AsyncDomainsResource) -> None: self.delete = async_to_streamed_response_wrapper( domains.delete, ) - self.bulk_delete = async_to_streamed_response_wrapper( - domains.bulk_delete, - ) self.edit = async_to_streamed_response_wrapper( domains.edit, ) diff --git a/src/cloudflare/resources/email_security/settings/impersonation_registry.py b/src/cloudflare/resources/email_security/settings/impersonation_registry.py index cc5a887645a..76b24c7d633 100644 --- a/src/cloudflare/resources/email_security/settings/impersonation_registry.py +++ b/src/cloudflare/resources/email_security/settings/impersonation_registry.py @@ -20,16 +20,9 @@ from ...._wrappers import ResultWrapper from ....pagination import SyncV4PagePaginationArray, AsyncV4PagePaginationArray from ...._base_client import AsyncPaginator, make_request_options -from ....types.email_security.settings import ( - impersonation_registry_edit_params, - impersonation_registry_list_params, - impersonation_registry_create_params, -) -from ....types.email_security.settings.impersonation_registry_get_response import ImpersonationRegistryGetResponse -from ....types.email_security.settings.impersonation_registry_edit_response import ImpersonationRegistryEditResponse +from ....types.email_security.settings import impersonation_registry_list_params, impersonation_registry_create_params from ....types.email_security.settings.impersonation_registry_list_response import ImpersonationRegistryListResponse from ....types.email_security.settings.impersonation_registry_create_response import ImpersonationRegistryCreateResponse -from ....types.email_security.settings.impersonation_registry_delete_response import ImpersonationRegistryDeleteResponse __all__ = ["ImpersonationRegistryResource", "AsyncImpersonationRegistryResource"] @@ -61,18 +54,26 @@ def create( email: str, is_email_regex: bool, name: str, + comments: Optional[str] | Omit = omit, + directory_id: Optional[int] | Omit = omit, + directory_node_id: Optional[int] | Omit = omit, + external_directory_node_id: Optional[str] | Omit = omit, + provenance: Literal["A1S_INTERNAL", "SNOOPY-CASB_OFFICE_365", "SNOOPY-OFFICE_365", "SNOOPY-GOOGLE_DIRECTORY"] + | Omit = omit, # 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, - ) -> ImpersonationRegistryCreateResponse: + ) -> Optional[ImpersonationRegistryCreateResponse]: """ - Creates a display name entry for email security impersonation protection. + Creates a new entry in the impersonation registry to protect against + impersonation. Emails attempting to impersonate this identity will be flagged. + Supports regex patterns for flexible email matching. Args: - account_id: Account Identifier + account_id: Identifier. extra_headers: Send extra headers @@ -93,6 +94,11 @@ def create( "email": email, "is_email_regex": is_email_regex, "name": name, + "comments": comments, + "directory_id": directory_id, + "directory_node_id": directory_node_id, + "external_directory_node_id": external_directory_node_id, + "provenance": provenance, }, impersonation_registry_create_params.ImpersonationRegistryCreateParams, ), @@ -101,9 +107,11 @@ def create( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[ImpersonationRegistryCreateResponse]._unwrapper, + post_parser=ResultWrapper[Optional[ImpersonationRegistryCreateResponse]]._unwrapper, + ), + cast_to=cast( + Type[Optional[ImpersonationRegistryCreateResponse]], ResultWrapper[ImpersonationRegistryCreateResponse] ), - cast_to=cast(Type[ImpersonationRegistryCreateResponse], ResultWrapper[ImpersonationRegistryCreateResponse]), ) def list( @@ -125,22 +133,23 @@ def list( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncV4PagePaginationArray[ImpersonationRegistryListResponse]: """ - Lists, searches, and sorts entries in the impersonation registry. + Returns a paginated list of protected identities in the impersonation registry. + These entries define identities and email addresses to protect from + impersonation attacks. Can be manually added or automatically synced from + directory integrations. Args: - account_id: Account Identifier + account_id: Identifier. direction: The sorting direction. - order: The field to sort by. + order: Field to sort by. - page: The page number of paginated results. + page: Current page within paginated list of results. - per_page: The number of results per page. + per_page: The number of results per page. Maximum value is 1000. - search: Allows searching in multiple properties of a record simultaneously. This - parameter is intended for human users, not automation. Its exact behavior is - intentionally left unspecified and is subject to change in the future. + search: Search term for filtering records. Behavior may change. extra_headers: Send extra headers @@ -177,149 +186,6 @@ def list( model=ImpersonationRegistryListResponse, ) - def delete( - self, - display_name_id: int, - *, - 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, - ) -> ImpersonationRegistryDeleteResponse: - """ - Removes a display name from impersonation protection monitoring. - - Args: - account_id: Account Identifier - - 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._delete( - path_template( - "/accounts/{account_id}/email-security/settings/impersonation_registry/{display_name_id}", - account_id=account_id, - display_name_id=display_name_id, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - post_parser=ResultWrapper[ImpersonationRegistryDeleteResponse]._unwrapper, - ), - cast_to=cast(Type[ImpersonationRegistryDeleteResponse], ResultWrapper[ImpersonationRegistryDeleteResponse]), - ) - - def edit( - self, - display_name_id: int, - *, - account_id: str, - email: Optional[str] | Omit = omit, - is_email_regex: Optional[bool] | Omit = omit, - name: Optional[str] | Omit = omit, - # 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, - ) -> ImpersonationRegistryEditResponse: - """ - Updates a display name entry used for impersonation protection. - - Args: - account_id: Account Identifier - - 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._patch( - path_template( - "/accounts/{account_id}/email-security/settings/impersonation_registry/{display_name_id}", - account_id=account_id, - display_name_id=display_name_id, - ), - body=maybe_transform( - { - "email": email, - "is_email_regex": is_email_regex, - "name": name, - }, - impersonation_registry_edit_params.ImpersonationRegistryEditParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - post_parser=ResultWrapper[ImpersonationRegistryEditResponse]._unwrapper, - ), - cast_to=cast(Type[ImpersonationRegistryEditResponse], ResultWrapper[ImpersonationRegistryEditResponse]), - ) - - def get( - self, - display_name_id: int, - *, - 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, - ) -> ImpersonationRegistryGetResponse: - """ - Retrieves a display name entry used for impersonation protection. - - Args: - account_id: Account Identifier - - 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( - path_template( - "/accounts/{account_id}/email-security/settings/impersonation_registry/{display_name_id}", - account_id=account_id, - display_name_id=display_name_id, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - post_parser=ResultWrapper[ImpersonationRegistryGetResponse]._unwrapper, - ), - cast_to=cast(Type[ImpersonationRegistryGetResponse], ResultWrapper[ImpersonationRegistryGetResponse]), - ) - class AsyncImpersonationRegistryResource(AsyncAPIResource): @cached_property @@ -348,18 +214,26 @@ async def create( email: str, is_email_regex: bool, name: str, + comments: Optional[str] | Omit = omit, + directory_id: Optional[int] | Omit = omit, + directory_node_id: Optional[int] | Omit = omit, + external_directory_node_id: Optional[str] | Omit = omit, + provenance: Literal["A1S_INTERNAL", "SNOOPY-CASB_OFFICE_365", "SNOOPY-OFFICE_365", "SNOOPY-GOOGLE_DIRECTORY"] + | Omit = omit, # 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, - ) -> ImpersonationRegistryCreateResponse: + ) -> Optional[ImpersonationRegistryCreateResponse]: """ - Creates a display name entry for email security impersonation protection. + Creates a new entry in the impersonation registry to protect against + impersonation. Emails attempting to impersonate this identity will be flagged. + Supports regex patterns for flexible email matching. Args: - account_id: Account Identifier + account_id: Identifier. extra_headers: Send extra headers @@ -380,6 +254,11 @@ async def create( "email": email, "is_email_regex": is_email_regex, "name": name, + "comments": comments, + "directory_id": directory_id, + "directory_node_id": directory_node_id, + "external_directory_node_id": external_directory_node_id, + "provenance": provenance, }, impersonation_registry_create_params.ImpersonationRegistryCreateParams, ), @@ -388,9 +267,11 @@ async def create( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[ImpersonationRegistryCreateResponse]._unwrapper, + post_parser=ResultWrapper[Optional[ImpersonationRegistryCreateResponse]]._unwrapper, + ), + cast_to=cast( + Type[Optional[ImpersonationRegistryCreateResponse]], ResultWrapper[ImpersonationRegistryCreateResponse] ), - cast_to=cast(Type[ImpersonationRegistryCreateResponse], ResultWrapper[ImpersonationRegistryCreateResponse]), ) def list( @@ -414,22 +295,23 @@ def list( ImpersonationRegistryListResponse, AsyncV4PagePaginationArray[ImpersonationRegistryListResponse] ]: """ - Lists, searches, and sorts entries in the impersonation registry. + Returns a paginated list of protected identities in the impersonation registry. + These entries define identities and email addresses to protect from + impersonation attacks. Can be manually added or automatically synced from + directory integrations. Args: - account_id: Account Identifier + account_id: Identifier. direction: The sorting direction. - order: The field to sort by. + order: Field to sort by. - page: The page number of paginated results. + page: Current page within paginated list of results. - per_page: The number of results per page. + per_page: The number of results per page. Maximum value is 1000. - search: Allows searching in multiple properties of a record simultaneously. This - parameter is intended for human users, not automation. Its exact behavior is - intentionally left unspecified and is subject to change in the future. + search: Search term for filtering records. Behavior may change. extra_headers: Send extra headers @@ -466,149 +348,6 @@ def list( model=ImpersonationRegistryListResponse, ) - async def delete( - self, - display_name_id: int, - *, - 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, - ) -> ImpersonationRegistryDeleteResponse: - """ - Removes a display name from impersonation protection monitoring. - - Args: - account_id: Account Identifier - - 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._delete( - path_template( - "/accounts/{account_id}/email-security/settings/impersonation_registry/{display_name_id}", - account_id=account_id, - display_name_id=display_name_id, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - post_parser=ResultWrapper[ImpersonationRegistryDeleteResponse]._unwrapper, - ), - cast_to=cast(Type[ImpersonationRegistryDeleteResponse], ResultWrapper[ImpersonationRegistryDeleteResponse]), - ) - - async def edit( - self, - display_name_id: int, - *, - account_id: str, - email: Optional[str] | Omit = omit, - is_email_regex: Optional[bool] | Omit = omit, - name: Optional[str] | Omit = omit, - # 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, - ) -> ImpersonationRegistryEditResponse: - """ - Updates a display name entry used for impersonation protection. - - Args: - account_id: Account Identifier - - 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._patch( - path_template( - "/accounts/{account_id}/email-security/settings/impersonation_registry/{display_name_id}", - account_id=account_id, - display_name_id=display_name_id, - ), - body=await async_maybe_transform( - { - "email": email, - "is_email_regex": is_email_regex, - "name": name, - }, - impersonation_registry_edit_params.ImpersonationRegistryEditParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - post_parser=ResultWrapper[ImpersonationRegistryEditResponse]._unwrapper, - ), - cast_to=cast(Type[ImpersonationRegistryEditResponse], ResultWrapper[ImpersonationRegistryEditResponse]), - ) - - async def get( - self, - display_name_id: int, - *, - 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, - ) -> ImpersonationRegistryGetResponse: - """ - Retrieves a display name entry used for impersonation protection. - - Args: - account_id: Account Identifier - - 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( - path_template( - "/accounts/{account_id}/email-security/settings/impersonation_registry/{display_name_id}", - account_id=account_id, - display_name_id=display_name_id, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - post_parser=ResultWrapper[ImpersonationRegistryGetResponse]._unwrapper, - ), - cast_to=cast(Type[ImpersonationRegistryGetResponse], ResultWrapper[ImpersonationRegistryGetResponse]), - ) - class ImpersonationRegistryResourceWithRawResponse: def __init__(self, impersonation_registry: ImpersonationRegistryResource) -> None: @@ -620,15 +359,6 @@ def __init__(self, impersonation_registry: ImpersonationRegistryResource) -> Non self.list = to_raw_response_wrapper( impersonation_registry.list, ) - self.delete = to_raw_response_wrapper( - impersonation_registry.delete, - ) - self.edit = to_raw_response_wrapper( - impersonation_registry.edit, - ) - self.get = to_raw_response_wrapper( - impersonation_registry.get, - ) class AsyncImpersonationRegistryResourceWithRawResponse: @@ -641,15 +371,6 @@ def __init__(self, impersonation_registry: AsyncImpersonationRegistryResource) - self.list = async_to_raw_response_wrapper( impersonation_registry.list, ) - self.delete = async_to_raw_response_wrapper( - impersonation_registry.delete, - ) - self.edit = async_to_raw_response_wrapper( - impersonation_registry.edit, - ) - self.get = async_to_raw_response_wrapper( - impersonation_registry.get, - ) class ImpersonationRegistryResourceWithStreamingResponse: @@ -662,15 +383,6 @@ def __init__(self, impersonation_registry: ImpersonationRegistryResource) -> Non self.list = to_streamed_response_wrapper( impersonation_registry.list, ) - self.delete = to_streamed_response_wrapper( - impersonation_registry.delete, - ) - self.edit = to_streamed_response_wrapper( - impersonation_registry.edit, - ) - self.get = to_streamed_response_wrapper( - impersonation_registry.get, - ) class AsyncImpersonationRegistryResourceWithStreamingResponse: @@ -683,12 +395,3 @@ def __init__(self, impersonation_registry: AsyncImpersonationRegistryResource) - self.list = async_to_streamed_response_wrapper( impersonation_registry.list, ) - self.delete = async_to_streamed_response_wrapper( - impersonation_registry.delete, - ) - self.edit = async_to_streamed_response_wrapper( - impersonation_registry.edit, - ) - self.get = async_to_streamed_response_wrapper( - impersonation_registry.get, - ) diff --git a/src/cloudflare/resources/email_security/settings/trusted_domains.py b/src/cloudflare/resources/email_security/settings/trusted_domains.py index 2bc4c7a45d2..3f5c4b27cef 100644 --- a/src/cloudflare/resources/email_security/settings/trusted_domains.py +++ b/src/cloudflare/resources/email_security/settings/trusted_domains.py @@ -2,13 +2,13 @@ from __future__ import annotations -from typing import Any, Type, Iterable, Optional, cast -from typing_extensions import Literal, overload +from typing import Type, Optional, cast +from typing_extensions import Literal import httpx from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import path_template, required_args, maybe_transform, async_maybe_transform +from ...._utils import path_template, maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import ( @@ -54,7 +54,6 @@ def with_streaming_response(self) -> TrustedDomainsResourceWithStreamingResponse """ return TrustedDomainsResourceWithStreamingResponse(self) - @overload def create( self, *, @@ -70,13 +69,15 @@ def create( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> TrustedDomainCreateResponse: - """ - Adds a domain to the trusted domains list for email security, reducing false - positive detections. + ) -> Optional[TrustedDomainCreateResponse]: + """Creates a new trusted domain pattern. + + Use for partner domains or approved + senders that should bypass recent domain registration and similarity checks. + Configure whether it prevents recent domain or spoof dispositions. Args: - account_id: Account Identifier + account_id: Identifier. is_recent: Select to prevent recently registered domains from triggering a Suspicious or Malicious disposition. @@ -92,84 +93,28 @@ def create( timeout: Override the client-level default timeout for this request, in seconds """ - ... - - @overload - def create( - self, - *, - account_id: str, - body: Iterable[trusted_domain_create_params.Variant1Body], - # 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, - ) -> TrustedDomainCreateResponse: - """ - Adds a domain to the trusted domains list for email security, reducing false - positive detections. - - Args: - account_id: Account Identifier - - 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 - """ - ... - - @required_args(["account_id", "is_recent", "is_regex", "is_similarity", "pattern"], ["account_id", "body"]) - def create( - self, - *, - account_id: str, - is_recent: bool | Omit = omit, - is_regex: bool | Omit = omit, - is_similarity: bool | Omit = omit, - pattern: str | Omit = omit, - comments: Optional[str] | Omit = omit, - body: Iterable[trusted_domain_create_params.Variant1Body] | Omit = omit, - # 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, - ) -> TrustedDomainCreateResponse: if not account_id: raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") - return cast( - TrustedDomainCreateResponse, - self._post( - path_template("/accounts/{account_id}/email-security/settings/trusted_domains", account_id=account_id), - body=maybe_transform( - { - "is_recent": is_recent, - "is_regex": is_regex, - "is_similarity": is_similarity, - "pattern": pattern, - "comments": comments, - "body": body, - }, - trusted_domain_create_params.TrustedDomainCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - post_parser=ResultWrapper[TrustedDomainCreateResponse]._unwrapper, - ), - cast_to=cast( - Any, ResultWrapper[TrustedDomainCreateResponse] - ), # Union types cannot be passed in as arguments in the type system + return self._post( + path_template("/accounts/{account_id}/email-security/settings/trusted_domains", account_id=account_id), + body=maybe_transform( + { + "is_recent": is_recent, + "is_regex": is_regex, + "is_similarity": is_similarity, + "pattern": pattern, + "comments": comments, + }, + trusted_domain_create_params.TrustedDomainCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[Optional[TrustedDomainCreateResponse]]._unwrapper, ), + cast_to=cast(Type[Optional[TrustedDomainCreateResponse]], ResultWrapper[TrustedDomainCreateResponse]), ) def list( @@ -191,23 +136,30 @@ def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncV4PagePaginationArray[TrustedDomainListResponse]: - """ - Lists, searches, and sorts an account’s trusted email domains. + """Returns a paginated list of trusted domain patterns. + + Trusted domains prevent + false positives for recently registered domains and lookalike domain detections. + Patterns can use regular expressions for flexible matching. Args: - account_id: Account Identifier + account_id: Identifier. direction: The sorting direction. - order: The field to sort by. + is_recent: Filter to show only recently registered domains that are trusted to prevent + triggering Suspicious or Malicious dispositions. + + is_similarity: Filter to show only proximity domains (partner or approved domains with similar + spelling to connected domains) that prevent Spoof dispositions. - page: The page number of paginated results. + order: Field to sort by. - per_page: The number of results per page. + page: Current page within paginated list of results. - search: Allows searching in multiple properties of a record simultaneously. This - parameter is intended for human users, not automation. Its exact behavior is - intentionally left unspecified and is subject to change in the future. + per_page: The number of results per page. Maximum value is 1000. + + search: Search term for filtering records. Behavior may change. extra_headers: Send extra headers @@ -246,7 +198,7 @@ def list( def delete( self, - trusted_domain_id: int, + trusted_domain_id: str, *, account_id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -255,15 +207,16 @@ def delete( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> TrustedDomainDeleteResponse: - """ - Removes a domain from the trusted domains list, subjecting it to normal security - scanning. + ) -> Optional[TrustedDomainDeleteResponse]: + """Removes a trusted domain pattern. + + After deletion, emails from this domain will + be subject to normal recent domain and similarity checks. Args: - account_id: Account Identifier + account_id: Identifier. - trusted_domain_id: The unique identifier for the trusted domain. + trusted_domain_id: Trusted domain identifier extra_headers: Send extra headers @@ -275,6 +228,8 @@ def delete( """ if not account_id: raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + if not trusted_domain_id: + raise ValueError(f"Expected a non-empty value for `trusted_domain_id` but received {trusted_domain_id!r}") return self._delete( path_template( "/accounts/{account_id}/email-security/settings/trusted_domains/{trusted_domain_id}", @@ -286,17 +241,17 @@ def delete( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[TrustedDomainDeleteResponse]._unwrapper, + post_parser=ResultWrapper[Optional[TrustedDomainDeleteResponse]]._unwrapper, ), - cast_to=cast(Type[TrustedDomainDeleteResponse], ResultWrapper[TrustedDomainDeleteResponse]), + cast_to=cast(Type[Optional[TrustedDomainDeleteResponse]], ResultWrapper[TrustedDomainDeleteResponse]), ) def edit( self, - trusted_domain_id: int, + trusted_domain_id: str, *, account_id: str, - comments: str | Omit = omit, + comments: Optional[str] | Omit = omit, is_recent: bool | Omit = omit, is_regex: bool | Omit = omit, is_similarity: bool | Omit = omit, @@ -307,14 +262,16 @@ def edit( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> TrustedDomainEditResponse: - """ - Modifies a trusted domain entry's configuration. + ) -> Optional[TrustedDomainEditResponse]: + """Updates an existing trusted domain pattern. + + Only provided fields will be + modified. Changes take effect for new emails matching the pattern. Args: - account_id: Account Identifier + account_id: Identifier. - trusted_domain_id: The unique identifier for the trusted domain. + trusted_domain_id: Trusted domain identifier is_recent: Select to prevent recently registered domains from triggering a Suspicious or Malicious disposition. @@ -332,6 +289,8 @@ def edit( """ if not account_id: raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + if not trusted_domain_id: + raise ValueError(f"Expected a non-empty value for `trusted_domain_id` but received {trusted_domain_id!r}") return self._patch( path_template( "/accounts/{account_id}/email-security/settings/trusted_domains/{trusted_domain_id}", @@ -353,14 +312,14 @@ def edit( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[TrustedDomainEditResponse]._unwrapper, + post_parser=ResultWrapper[Optional[TrustedDomainEditResponse]]._unwrapper, ), - cast_to=cast(Type[TrustedDomainEditResponse], ResultWrapper[TrustedDomainEditResponse]), + cast_to=cast(Type[Optional[TrustedDomainEditResponse]], ResultWrapper[TrustedDomainEditResponse]), ) def get( self, - trusted_domain_id: int, + trusted_domain_id: str, *, account_id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -369,14 +328,15 @@ def get( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> TrustedDomainGetResponse: + ) -> Optional[TrustedDomainGetResponse]: """ - Gets information about a specific trusted domain entry. + Retrieves details for a specific trusted domain pattern including its pattern + value, whether it uses regex matching, and which detection types it affects. Args: - account_id: Account Identifier + account_id: Identifier. - trusted_domain_id: The unique identifier for the trusted domain. + trusted_domain_id: Trusted domain identifier extra_headers: Send extra headers @@ -388,6 +348,8 @@ def get( """ if not account_id: raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + if not trusted_domain_id: + raise ValueError(f"Expected a non-empty value for `trusted_domain_id` but received {trusted_domain_id!r}") return self._get( path_template( "/accounts/{account_id}/email-security/settings/trusted_domains/{trusted_domain_id}", @@ -399,9 +361,9 @@ def get( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[TrustedDomainGetResponse]._unwrapper, + post_parser=ResultWrapper[Optional[TrustedDomainGetResponse]]._unwrapper, ), - cast_to=cast(Type[TrustedDomainGetResponse], ResultWrapper[TrustedDomainGetResponse]), + cast_to=cast(Type[Optional[TrustedDomainGetResponse]], ResultWrapper[TrustedDomainGetResponse]), ) @@ -425,7 +387,6 @@ def with_streaming_response(self) -> AsyncTrustedDomainsResourceWithStreamingRes """ return AsyncTrustedDomainsResourceWithStreamingResponse(self) - @overload async def create( self, *, @@ -441,13 +402,15 @@ async def create( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> TrustedDomainCreateResponse: - """ - Adds a domain to the trusted domains list for email security, reducing false - positive detections. + ) -> Optional[TrustedDomainCreateResponse]: + """Creates a new trusted domain pattern. + + Use for partner domains or approved + senders that should bypass recent domain registration and similarity checks. + Configure whether it prevents recent domain or spoof dispositions. Args: - account_id: Account Identifier + account_id: Identifier. is_recent: Select to prevent recently registered domains from triggering a Suspicious or Malicious disposition. @@ -463,84 +426,28 @@ async def create( timeout: Override the client-level default timeout for this request, in seconds """ - ... - - @overload - async def create( - self, - *, - account_id: str, - body: Iterable[trusted_domain_create_params.Variant1Body], - # 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, - ) -> TrustedDomainCreateResponse: - """ - Adds a domain to the trusted domains list for email security, reducing false - positive detections. - - Args: - account_id: Account Identifier - - 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 - """ - ... - - @required_args(["account_id", "is_recent", "is_regex", "is_similarity", "pattern"], ["account_id", "body"]) - async def create( - self, - *, - account_id: str, - is_recent: bool | Omit = omit, - is_regex: bool | Omit = omit, - is_similarity: bool | Omit = omit, - pattern: str | Omit = omit, - comments: Optional[str] | Omit = omit, - body: Iterable[trusted_domain_create_params.Variant1Body] | Omit = omit, - # 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, - ) -> TrustedDomainCreateResponse: if not account_id: raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") - return cast( - TrustedDomainCreateResponse, - await self._post( - path_template("/accounts/{account_id}/email-security/settings/trusted_domains", account_id=account_id), - body=await async_maybe_transform( - { - "is_recent": is_recent, - "is_regex": is_regex, - "is_similarity": is_similarity, - "pattern": pattern, - "comments": comments, - "body": body, - }, - trusted_domain_create_params.TrustedDomainCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - post_parser=ResultWrapper[TrustedDomainCreateResponse]._unwrapper, - ), - cast_to=cast( - Any, ResultWrapper[TrustedDomainCreateResponse] - ), # Union types cannot be passed in as arguments in the type system + return await self._post( + path_template("/accounts/{account_id}/email-security/settings/trusted_domains", account_id=account_id), + body=await async_maybe_transform( + { + "is_recent": is_recent, + "is_regex": is_regex, + "is_similarity": is_similarity, + "pattern": pattern, + "comments": comments, + }, + trusted_domain_create_params.TrustedDomainCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[Optional[TrustedDomainCreateResponse]]._unwrapper, ), + cast_to=cast(Type[Optional[TrustedDomainCreateResponse]], ResultWrapper[TrustedDomainCreateResponse]), ) def list( @@ -562,23 +469,30 @@ def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[TrustedDomainListResponse, AsyncV4PagePaginationArray[TrustedDomainListResponse]]: - """ - Lists, searches, and sorts an account’s trusted email domains. + """Returns a paginated list of trusted domain patterns. + + Trusted domains prevent + false positives for recently registered domains and lookalike domain detections. + Patterns can use regular expressions for flexible matching. Args: - account_id: Account Identifier + account_id: Identifier. direction: The sorting direction. - order: The field to sort by. + is_recent: Filter to show only recently registered domains that are trusted to prevent + triggering Suspicious or Malicious dispositions. + + is_similarity: Filter to show only proximity domains (partner or approved domains with similar + spelling to connected domains) that prevent Spoof dispositions. - page: The page number of paginated results. + order: Field to sort by. - per_page: The number of results per page. + page: Current page within paginated list of results. - search: Allows searching in multiple properties of a record simultaneously. This - parameter is intended for human users, not automation. Its exact behavior is - intentionally left unspecified and is subject to change in the future. + per_page: The number of results per page. Maximum value is 1000. + + search: Search term for filtering records. Behavior may change. extra_headers: Send extra headers @@ -617,7 +531,7 @@ def list( async def delete( self, - trusted_domain_id: int, + trusted_domain_id: str, *, account_id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -626,15 +540,16 @@ async def delete( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> TrustedDomainDeleteResponse: - """ - Removes a domain from the trusted domains list, subjecting it to normal security - scanning. + ) -> Optional[TrustedDomainDeleteResponse]: + """Removes a trusted domain pattern. + + After deletion, emails from this domain will + be subject to normal recent domain and similarity checks. Args: - account_id: Account Identifier + account_id: Identifier. - trusted_domain_id: The unique identifier for the trusted domain. + trusted_domain_id: Trusted domain identifier extra_headers: Send extra headers @@ -646,6 +561,8 @@ async def delete( """ if not account_id: raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + if not trusted_domain_id: + raise ValueError(f"Expected a non-empty value for `trusted_domain_id` but received {trusted_domain_id!r}") return await self._delete( path_template( "/accounts/{account_id}/email-security/settings/trusted_domains/{trusted_domain_id}", @@ -657,17 +574,17 @@ async def delete( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[TrustedDomainDeleteResponse]._unwrapper, + post_parser=ResultWrapper[Optional[TrustedDomainDeleteResponse]]._unwrapper, ), - cast_to=cast(Type[TrustedDomainDeleteResponse], ResultWrapper[TrustedDomainDeleteResponse]), + cast_to=cast(Type[Optional[TrustedDomainDeleteResponse]], ResultWrapper[TrustedDomainDeleteResponse]), ) async def edit( self, - trusted_domain_id: int, + trusted_domain_id: str, *, account_id: str, - comments: str | Omit = omit, + comments: Optional[str] | Omit = omit, is_recent: bool | Omit = omit, is_regex: bool | Omit = omit, is_similarity: bool | Omit = omit, @@ -678,14 +595,16 @@ async def edit( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> TrustedDomainEditResponse: - """ - Modifies a trusted domain entry's configuration. + ) -> Optional[TrustedDomainEditResponse]: + """Updates an existing trusted domain pattern. + + Only provided fields will be + modified. Changes take effect for new emails matching the pattern. Args: - account_id: Account Identifier + account_id: Identifier. - trusted_domain_id: The unique identifier for the trusted domain. + trusted_domain_id: Trusted domain identifier is_recent: Select to prevent recently registered domains from triggering a Suspicious or Malicious disposition. @@ -703,6 +622,8 @@ async def edit( """ if not account_id: raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + if not trusted_domain_id: + raise ValueError(f"Expected a non-empty value for `trusted_domain_id` but received {trusted_domain_id!r}") return await self._patch( path_template( "/accounts/{account_id}/email-security/settings/trusted_domains/{trusted_domain_id}", @@ -724,14 +645,14 @@ async def edit( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[TrustedDomainEditResponse]._unwrapper, + post_parser=ResultWrapper[Optional[TrustedDomainEditResponse]]._unwrapper, ), - cast_to=cast(Type[TrustedDomainEditResponse], ResultWrapper[TrustedDomainEditResponse]), + cast_to=cast(Type[Optional[TrustedDomainEditResponse]], ResultWrapper[TrustedDomainEditResponse]), ) async def get( self, - trusted_domain_id: int, + trusted_domain_id: str, *, account_id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -740,14 +661,15 @@ async def get( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> TrustedDomainGetResponse: + ) -> Optional[TrustedDomainGetResponse]: """ - Gets information about a specific trusted domain entry. + Retrieves details for a specific trusted domain pattern including its pattern + value, whether it uses regex matching, and which detection types it affects. Args: - account_id: Account Identifier + account_id: Identifier. - trusted_domain_id: The unique identifier for the trusted domain. + trusted_domain_id: Trusted domain identifier extra_headers: Send extra headers @@ -759,6 +681,8 @@ async def get( """ if not account_id: raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}") + if not trusted_domain_id: + raise ValueError(f"Expected a non-empty value for `trusted_domain_id` but received {trusted_domain_id!r}") return await self._get( path_template( "/accounts/{account_id}/email-security/settings/trusted_domains/{trusted_domain_id}", @@ -770,9 +694,9 @@ async def get( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[TrustedDomainGetResponse]._unwrapper, + post_parser=ResultWrapper[Optional[TrustedDomainGetResponse]]._unwrapper, ), - cast_to=cast(Type[TrustedDomainGetResponse], ResultWrapper[TrustedDomainGetResponse]), + cast_to=cast(Type[Optional[TrustedDomainGetResponse]], ResultWrapper[TrustedDomainGetResponse]), ) diff --git a/src/cloudflare/resources/email_security/submissions.py b/src/cloudflare/resources/email_security/submissions.py index a35b261041e..be830a3f4e9 100644 --- a/src/cloudflare/resources/email_security/submissions.py +++ b/src/cloudflare/resources/email_security/submissions.py @@ -50,7 +50,6 @@ def list( self, *, account_id: str, - customer_status: Literal["escalated", "reviewed", "unreviewed"] | Omit = omit, end: Union[str, datetime] | Omit = omit, original_disposition: Literal["MALICIOUS", "SUSPICIOUS", "SPOOF", "SPAM", "BULK", "NONE"] | Omit = omit, outcome_disposition: Literal["MALICIOUS", "SUSPICIOUS", "SPOOF", "SPAM", "BULK", "NONE"] | Omit = omit, @@ -69,20 +68,22 @@ def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncV4PagePaginationArray[SubmissionListResponse]: - """ - This endpoint returns information for submissions to made to reclassify emails. + """Returns information for submissions made to reclassify emails. + + Shows the status, + outcome, and disposition changes for reclassification requests made by users or + the security team. Useful for tracking false positive/negative reports. Args: - account_id: Account Identifier + account_id: Identifier. - end: The end of the search date range. Defaults to `now` if not provided. + end: The end of the search date range. Defaults to `now`. - page: The page number of paginated results. + page: Current page within paginated list of results. - per_page: The number of results per page. + per_page: The number of results per page. Maximum value is 1000. - start: The beginning of the search date range. Defaults to `now - 30 days` if not - provided. + start: The beginning of the search date range. Defaults to `now - 30 days`. extra_headers: Send extra headers @@ -104,7 +105,6 @@ def list( timeout=timeout, query=maybe_transform( { - "customer_status": customer_status, "end": end, "original_disposition": original_disposition, "outcome_disposition": outcome_disposition, @@ -148,7 +148,6 @@ def list( self, *, account_id: str, - customer_status: Literal["escalated", "reviewed", "unreviewed"] | Omit = omit, end: Union[str, datetime] | Omit = omit, original_disposition: Literal["MALICIOUS", "SUSPICIOUS", "SPOOF", "SPAM", "BULK", "NONE"] | Omit = omit, outcome_disposition: Literal["MALICIOUS", "SUSPICIOUS", "SPOOF", "SPAM", "BULK", "NONE"] | Omit = omit, @@ -167,20 +166,22 @@ def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[SubmissionListResponse, AsyncV4PagePaginationArray[SubmissionListResponse]]: - """ - This endpoint returns information for submissions to made to reclassify emails. + """Returns information for submissions made to reclassify emails. + + Shows the status, + outcome, and disposition changes for reclassification requests made by users or + the security team. Useful for tracking false positive/negative reports. Args: - account_id: Account Identifier + account_id: Identifier. - end: The end of the search date range. Defaults to `now` if not provided. + end: The end of the search date range. Defaults to `now`. - page: The page number of paginated results. + page: Current page within paginated list of results. - per_page: The number of results per page. + per_page: The number of results per page. Maximum value is 1000. - start: The beginning of the search date range. Defaults to `now - 30 days` if not - provided. + start: The beginning of the search date range. Defaults to `now - 30 days`. extra_headers: Send extra headers @@ -202,7 +203,6 @@ def list( timeout=timeout, query=maybe_transform( { - "customer_status": customer_status, "end": end, "original_disposition": original_disposition, "outcome_disposition": outcome_disposition, diff --git a/src/cloudflare/resources/workers/observability/telemetry.py b/src/cloudflare/resources/workers/observability/telemetry.py index 757102e555a..782b8f08f19 100644 --- a/src/cloudflare/resources/workers/observability/telemetry.py +++ b/src/cloudflare/resources/workers/observability/telemetry.py @@ -139,44 +139,53 @@ def query( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> TelemetryQueryResponse: - """ - Run a temporary or saved query. + """Run a temporary or saved query. Args: - query_id: Unique identifier for the query to execute + query_id: Identifier for the query. + + When parameters are omitted, this ID is used to load a + previously saved query's parameters. When providing parameters inline, pass any + identifier (e.g. an ad-hoc ID). - timeframe: Timeframe for your query using Unix timestamps in milliseconds. Provide from/to - epoch ms; narrower timeframes provide faster responses and more specific - results. + timeframe: Timeframe for the query using Unix timestamps in milliseconds. Narrower + timeframes produce faster responses and more specific results. - chart: Whether to include timeseties data in the response + chart: When true, includes time-series data in the response. - compare: Whether to include comparison data with previous time periods + compare: When true, includes a comparison dataset from the previous time period of equal + length. - dry: Whether to perform a dry run without saving the results of the query. Useful for - validation + dry: When true, executes the query without persisting the results. Useful for + validation or previewing. - granularity: This is only used when the view is calculations. Leaving it empty lets Workers - Observability detect the correct granularity. + granularity: Number of time-series buckets. Only used when view is 'calculations'. Omit to + let the system auto-detect an appropriate granularity. - ignore_series: Whether to ignore time-series data in the results and return only aggregated - values + ignore_series: When true, omits time-series data from the response and returns only aggregated + values. Reduces response size when series are not needed. - limit: Use this limit to cap the number of events returned when the view is events. + limit: Maximum number of events to return when view is 'events'. Also controls the + number of group-by rows when view is 'calculations'. - offset: Cursor pagination for event/trace/invocation views. Pass the last item's - $metadata.id as the next offset. + offset: Cursor for pagination in event, trace, and invocation views. Pass the + $metadata.id of the last returned item to fetch the next page. - offset_by: Numeric offset for pattern results (top-N list). Use with limit to page pattern - groups; not used by cursor pagination. + offset_by: Numeric offset for paginating grouped/pattern results (top-N lists). Use + together with limit. Not used by cursor-based pagination. - offset_direction: Direction for offset-based pagination (e.g., 'next', 'prev') + offset_direction: Pagination direction: 'next' for forward, 'prev' for backward. - parameters: Optional parameters to pass to the query execution + parameters: Query parameters defining what data to retrieve — filters, calculations, + group-bys, and ordering. In practice this should always be provided for ad-hoc + queries. Only omit when executing a previously saved query by queryId. Use the + keys and values endpoints to discover available fields before building filters. - view: Examples by view type. Events: show errors for a worker in the last 30 minutes. - Calculations: p99 of wall time or count by status code. Invocations: find a - specific request that resulted in a 500. + view: Controls the shape of the response. 'events': individual log lines matching the + query. 'calculations': aggregated metrics (count, avg, p99, etc.) with optional + group-by breakdowns and time-series. 'invocations': events grouped by request + ID. 'traces': distributed trace summaries. 'agents': Durable Object agent + summaries. extra_headers: Send extra headers @@ -245,7 +254,8 @@ def values( filters: Apply filters before listing values. Supports nested groups via kind: 'group'. Maximum nesting depth is 4. - needle: Search for a specific substring in the event. + needle: Full-text search expression to match events containing the specified text or + pattern. extra_headers: Send extra headers @@ -391,44 +401,53 @@ async def query( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> TelemetryQueryResponse: - """ - Run a temporary or saved query. + """Run a temporary or saved query. Args: - query_id: Unique identifier for the query to execute + query_id: Identifier for the query. + + When parameters are omitted, this ID is used to load a + previously saved query's parameters. When providing parameters inline, pass any + identifier (e.g. an ad-hoc ID). - timeframe: Timeframe for your query using Unix timestamps in milliseconds. Provide from/to - epoch ms; narrower timeframes provide faster responses and more specific - results. + timeframe: Timeframe for the query using Unix timestamps in milliseconds. Narrower + timeframes produce faster responses and more specific results. - chart: Whether to include timeseties data in the response + chart: When true, includes time-series data in the response. - compare: Whether to include comparison data with previous time periods + compare: When true, includes a comparison dataset from the previous time period of equal + length. - dry: Whether to perform a dry run without saving the results of the query. Useful for - validation + dry: When true, executes the query without persisting the results. Useful for + validation or previewing. - granularity: This is only used when the view is calculations. Leaving it empty lets Workers - Observability detect the correct granularity. + granularity: Number of time-series buckets. Only used when view is 'calculations'. Omit to + let the system auto-detect an appropriate granularity. - ignore_series: Whether to ignore time-series data in the results and return only aggregated - values + ignore_series: When true, omits time-series data from the response and returns only aggregated + values. Reduces response size when series are not needed. - limit: Use this limit to cap the number of events returned when the view is events. + limit: Maximum number of events to return when view is 'events'. Also controls the + number of group-by rows when view is 'calculations'. - offset: Cursor pagination for event/trace/invocation views. Pass the last item's - $metadata.id as the next offset. + offset: Cursor for pagination in event, trace, and invocation views. Pass the + $metadata.id of the last returned item to fetch the next page. - offset_by: Numeric offset for pattern results (top-N list). Use with limit to page pattern - groups; not used by cursor pagination. + offset_by: Numeric offset for paginating grouped/pattern results (top-N lists). Use + together with limit. Not used by cursor-based pagination. - offset_direction: Direction for offset-based pagination (e.g., 'next', 'prev') + offset_direction: Pagination direction: 'next' for forward, 'prev' for backward. - parameters: Optional parameters to pass to the query execution + parameters: Query parameters defining what data to retrieve — filters, calculations, + group-bys, and ordering. In practice this should always be provided for ad-hoc + queries. Only omit when executing a previously saved query by queryId. Use the + keys and values endpoints to discover available fields before building filters. - view: Examples by view type. Events: show errors for a worker in the last 30 minutes. - Calculations: p99 of wall time or count by status code. Invocations: find a - specific request that resulted in a 500. + view: Controls the shape of the response. 'events': individual log lines matching the + query. 'calculations': aggregated metrics (count, avg, p99, etc.) with optional + group-by breakdowns and time-series. 'invocations': events grouped by request + ID. 'traces': distributed trace summaries. 'agents': Durable Object agent + summaries. extra_headers: Send extra headers @@ -497,7 +516,8 @@ def values( filters: Apply filters before listing values. Supports nested groups via kind: 'group'. Maximum nesting depth is 4. - needle: Search for a specific substring in the event. + needle: Full-text search expression to match events containing the specified text or + pattern. extra_headers: Send extra headers diff --git a/src/cloudflare/types/email_security/__init__.py b/src/cloudflare/types/email_security/__init__.py index 7d6d4897e12..55fad65cd27 100644 --- a/src/cloudflare/types/email_security/__init__.py +++ b/src/cloudflare/types/email_security/__init__.py @@ -2,9 +2,7 @@ from __future__ import annotations -from .investigate_get_params import InvestigateGetParams as InvestigateGetParams from .submission_list_params import SubmissionListParams as SubmissionListParams from .investigate_list_params import InvestigateListParams as InvestigateListParams -from .investigate_get_response import InvestigateGetResponse as InvestigateGetResponse from .submission_list_response import SubmissionListResponse as SubmissionListResponse from .investigate_list_response import InvestigateListResponse as InvestigateListResponse diff --git a/src/cloudflare/types/email_security/investigate/__init__.py b/src/cloudflare/types/email_security/investigate/__init__.py index a86e5ccf9aa..2657a470e2c 100644 --- a/src/cloudflare/types/email_security/investigate/__init__.py +++ b/src/cloudflare/types/email_security/investigate/__init__.py @@ -3,16 +3,8 @@ from __future__ import annotations from .move_bulk_params import MoveBulkParams as MoveBulkParams -from .raw_get_response import RawGetResponse as RawGetResponse -from .trace_get_params import TraceGetParams as TraceGetParams from .move_bulk_response import MoveBulkResponse as MoveBulkResponse -from .move_create_params import MoveCreateParams as MoveCreateParams -from .trace_get_response import TraceGetResponse as TraceGetResponse from .release_bulk_params import ReleaseBulkParams as ReleaseBulkParams -from .move_create_response import MoveCreateResponse as MoveCreateResponse -from .preview_get_response import PreviewGetResponse as PreviewGetResponse from .preview_create_params import PreviewCreateParams as PreviewCreateParams from .release_bulk_response import ReleaseBulkResponse as ReleaseBulkResponse -from .detection_get_response import DetectionGetResponse as DetectionGetResponse from .preview_create_response import PreviewCreateResponse as PreviewCreateResponse -from .reclassify_create_params import ReclassifyCreateParams as ReclassifyCreateParams diff --git a/src/cloudflare/types/email_security/investigate/detection_get_response.py b/src/cloudflare/types/email_security/investigate/detection_get_response.py deleted file mode 100644 index 444f1b45083..00000000000 --- a/src/cloudflare/types/email_security/investigate/detection_get_response.py +++ /dev/null @@ -1,152 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = [ - "DetectionGetResponse", - "Attachment", - "Finding", - "Header", - "Link", - "SenderInfo", - "ThreatCategory", - "Validation", -] - - -class Attachment(BaseModel): - size: int - - content_type: Optional[str] = None - - detection: Optional[ - Literal[ - "MALICIOUS", - "MALICIOUS-BEC", - "SUSPICIOUS", - "SPOOF", - "SPAM", - "BULK", - "ENCRYPTED", - "EXTERNAL", - "UNKNOWN", - "NONE", - ] - ] = None - - encrypted: Optional[bool] = None - - name: Optional[str] = None - - -class Finding(BaseModel): - attachment: Optional[str] = None - - detail: Optional[str] = None - - detection: Optional[ - Literal[ - "MALICIOUS", - "MALICIOUS-BEC", - "SUSPICIOUS", - "SPOOF", - "SPAM", - "BULK", - "ENCRYPTED", - "EXTERNAL", - "UNKNOWN", - "NONE", - ] - ] = None - - field: Optional[str] = None - - name: Optional[str] = None - - portion: Optional[str] = None - - reason: Optional[str] = None - - score: Optional[float] = None - - value: Optional[str] = None - - -class Header(BaseModel): - name: str - - value: str - - -class Link(BaseModel): - href: str - - text: Optional[str] = None - - -class SenderInfo(BaseModel): - as_name: Optional[str] = None - """The name of the autonomous system.""" - - as_number: Optional[int] = None - """The number of the autonomous system.""" - - geo: Optional[str] = None - - ip: Optional[str] = None - - pld: Optional[str] = None - - -class ThreatCategory(BaseModel): - id: int - - description: Optional[str] = None - - name: Optional[str] = None - - -class Validation(BaseModel): - comment: Optional[str] = None - - dkim: Optional[Literal["pass", "neutral", "fail", "error", "none"]] = None - - dmarc: Optional[Literal["pass", "neutral", "fail", "error", "none"]] = None - - spf: Optional[Literal["pass", "neutral", "fail", "error", "none"]] = None - - -class DetectionGetResponse(BaseModel): - action: str - - attachments: List[Attachment] - - findings: List[Finding] - - headers: List[Header] - - links: List[Link] - - sender_info: SenderInfo - - threat_categories: List[ThreatCategory] - - validation: Validation - - final_disposition: Optional[ - Literal[ - "MALICIOUS", - "MALICIOUS-BEC", - "SUSPICIOUS", - "SPOOF", - "SPAM", - "BULK", - "ENCRYPTED", - "EXTERNAL", - "UNKNOWN", - "NONE", - ] - ] = None diff --git a/src/cloudflare/types/email_security/investigate/move_bulk_params.py b/src/cloudflare/types/email_security/investigate/move_bulk_params.py index b269132b524..35a0e5ac6d6 100644 --- a/src/cloudflare/types/email_security/investigate/move_bulk_params.py +++ b/src/cloudflare/types/email_security/investigate/move_bulk_params.py @@ -11,14 +11,17 @@ class MoveBulkParams(TypedDict, total=False): account_id: Required[str] - """Account Identifier""" + """Identifier.""" destination: Required[ Literal["Inbox", "JunkEmail", "DeletedItems", "RecoverableItemsDeletions", "RecoverableItemsPurges"] ] ids: SequenceNotStr[str] - """List of message IDs to move.""" + """List of message IDs to move""" postfix_ids: SequenceNotStr[str] - """Deprecated: Use `ids` instead. List of message IDs to move.""" + """Deprecated, use `ids` instead. + + End of life: November 1, 2026. List of message IDs to move. + """ diff --git a/src/cloudflare/types/email_security/investigate/move_bulk_response.py b/src/cloudflare/types/email_security/investigate/move_bulk_response.py index 1d660a890ae..34dec906dd2 100644 --- a/src/cloudflare/types/email_security/investigate/move_bulk_response.py +++ b/src/cloudflare/types/email_security/investigate/move_bulk_response.py @@ -9,21 +9,29 @@ class MoveBulkResponse(BaseModel): - completed_timestamp: datetime - """Deprecated, use `completed_at` instead""" - - item_count: int - success: bool + """Whether the operation succeeded""" completed_at: Optional[datetime] = None + """When the move operation completed (UTC)""" + + completed_timestamp: Optional[datetime] = None + """Deprecated, use `completed_at` instead. End of life: November 1, 2026.""" destination: Optional[str] = None + """Destination folder for the message""" + + item_count: Optional[int] = None + """Number of items moved. End of life: November 1, 2026.""" message_id: Optional[str] = None + """Message identifier""" operation: Optional[str] = None + """Type of operation performed""" recipient: Optional[str] = None + """Recipient email address""" status: Optional[str] = None + """Operation status""" diff --git a/src/cloudflare/types/email_security/investigate/move_create_params.py b/src/cloudflare/types/email_security/investigate/move_create_params.py deleted file mode 100644 index c4c977447e5..00000000000 --- a/src/cloudflare/types/email_security/investigate/move_create_params.py +++ /dev/null @@ -1,22 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["MoveCreateParams"] - - -class MoveCreateParams(TypedDict, total=False): - account_id: Required[str] - """Account Identifier""" - - destination: Required[ - Literal["Inbox", "JunkEmail", "DeletedItems", "RecoverableItemsDeletions", "RecoverableItemsPurges"] - ] - - submission: bool - """When true, search the submissions datastore only. - - When false or omitted, search the regular datastore only. - """ diff --git a/src/cloudflare/types/email_security/investigate/move_create_response.py b/src/cloudflare/types/email_security/investigate/move_create_response.py deleted file mode 100644 index 9dac3bddcd8..00000000000 --- a/src/cloudflare/types/email_security/investigate/move_create_response.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from datetime import datetime -from typing_extensions import TypeAlias - -from ...._models import BaseModel - -__all__ = ["MoveCreateResponse", "MoveCreateResponseItem"] - - -class MoveCreateResponseItem(BaseModel): - completed_timestamp: datetime - """Deprecated, use `completed_at` instead""" - - item_count: int - - success: bool - - completed_at: Optional[datetime] = None - - destination: Optional[str] = None - - message_id: Optional[str] = None - - operation: Optional[str] = None - - recipient: Optional[str] = None - - status: Optional[str] = None - - -MoveCreateResponse: TypeAlias = List[MoveCreateResponseItem] diff --git a/src/cloudflare/types/email_security/investigate/preview_create_params.py b/src/cloudflare/types/email_security/investigate/preview_create_params.py index f14b41a6449..58affde473a 100644 --- a/src/cloudflare/types/email_security/investigate/preview_create_params.py +++ b/src/cloudflare/types/email_security/investigate/preview_create_params.py @@ -9,13 +9,7 @@ class PreviewCreateParams(TypedDict, total=False): account_id: Required[str] - """Account Identifier""" + """Identifier.""" postfix_id: Required[str] - """The identifier of the message.""" - - submission: bool - """When true, search the submissions datastore only. - - When false or omitted, search the regular datastore only. - """ + """The identifier of the message""" diff --git a/src/cloudflare/types/email_security/investigate/preview_get_response.py b/src/cloudflare/types/email_security/investigate/preview_get_response.py deleted file mode 100644 index a34a109ac48..00000000000 --- a/src/cloudflare/types/email_security/investigate/preview_get_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ...._models import BaseModel - -__all__ = ["PreviewGetResponse"] - - -class PreviewGetResponse(BaseModel): - screenshot: str - """A base64 encoded PNG image of the email.""" diff --git a/src/cloudflare/types/email_security/investigate/raw_get_response.py b/src/cloudflare/types/email_security/investigate/raw_get_response.py deleted file mode 100644 index 06544943fca..00000000000 --- a/src/cloudflare/types/email_security/investigate/raw_get_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ...._models import BaseModel - -__all__ = ["RawGetResponse"] - - -class RawGetResponse(BaseModel): - raw: str - """A UTF-8 encoded eml file of the email.""" diff --git a/src/cloudflare/types/email_security/investigate/reclassify_create_params.py b/src/cloudflare/types/email_security/investigate/reclassify_create_params.py deleted file mode 100644 index 9bc5a664d51..00000000000 --- a/src/cloudflare/types/email_security/investigate/reclassify_create_params.py +++ /dev/null @@ -1,25 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ReclassifyCreateParams"] - - -class ReclassifyCreateParams(TypedDict, total=False): - account_id: Required[str] - """Account Identifier""" - - expected_disposition: Required[Literal["NONE", "BULK", "MALICIOUS", "SPAM", "SPOOF", "SUSPICIOUS"]] - - submission: bool - """When true, search the submissions datastore only. - - When false or omitted, search the regular datastore only. - """ - - eml_content: str - """Base64 encoded content of the EML file""" - - escalated_submission_id: str diff --git a/src/cloudflare/types/email_security/investigate/release_bulk_params.py b/src/cloudflare/types/email_security/investigate/release_bulk_params.py index fa6f4ef65b3..80b195efca0 100644 --- a/src/cloudflare/types/email_security/investigate/release_bulk_params.py +++ b/src/cloudflare/types/email_security/investigate/release_bulk_params.py @@ -11,7 +11,6 @@ class ReleaseBulkParams(TypedDict, total=False): account_id: Required[str] - """Account Identifier""" + """Identifier.""" body: Required[SequenceNotStr[str]] - """A list of messages identfied by their `postfix_id`s that should be released.""" diff --git a/src/cloudflare/types/email_security/investigate/release_bulk_response.py b/src/cloudflare/types/email_security/investigate/release_bulk_response.py index b766ac7b3f0..26dcb001d44 100644 --- a/src/cloudflare/types/email_security/investigate/release_bulk_response.py +++ b/src/cloudflare/types/email_security/investigate/release_bulk_response.py @@ -9,12 +9,13 @@ class ReleaseBulkResponse(BaseModel): id: str - - postfix_id: str - """The identifier of the message.""" + """Unique identifier for a message retrieved from investigation""" delivered: Optional[List[str]] = None failed: Optional[List[str]] = None + postfix_id: Optional[str] = None + """Deprecated, use `id` instead. End of life: November 1, 2026.""" + undelivered: Optional[List[str]] = None diff --git a/src/cloudflare/types/email_security/investigate/trace_get_params.py b/src/cloudflare/types/email_security/investigate/trace_get_params.py deleted file mode 100644 index d4d5cf33670..00000000000 --- a/src/cloudflare/types/email_security/investigate/trace_get_params.py +++ /dev/null @@ -1,18 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["TraceGetParams"] - - -class TraceGetParams(TypedDict, total=False): - account_id: Required[str] - """Account Identifier""" - - submission: bool - """When true, search the submissions datastore only. - - When false or omitted, search the regular datastore only. - """ diff --git a/src/cloudflare/types/email_security/investigate/trace_get_response.py b/src/cloudflare/types/email_security/investigate/trace_get_response.py deleted file mode 100644 index 98bce7e2bd2..00000000000 --- a/src/cloudflare/types/email_security/investigate/trace_get_response.py +++ /dev/null @@ -1,42 +0,0 @@ -# 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__ = ["TraceGetResponse", "Inbound", "InboundLine", "Outbound", "OutboundLine"] - - -class InboundLine(BaseModel): - lineno: int - - message: str - - ts: datetime - - -class Inbound(BaseModel): - lines: Optional[List[InboundLine]] = None - - pending: Optional[bool] = None - - -class OutboundLine(BaseModel): - lineno: int - - message: str - - ts: datetime - - -class Outbound(BaseModel): - lines: Optional[List[OutboundLine]] = None - - pending: Optional[bool] = None - - -class TraceGetResponse(BaseModel): - inbound: Inbound - - outbound: Outbound diff --git a/src/cloudflare/types/email_security/investigate_get_params.py b/src/cloudflare/types/email_security/investigate_get_params.py deleted file mode 100644 index 083388f1cad..00000000000 --- a/src/cloudflare/types/email_security/investigate_get_params.py +++ /dev/null @@ -1,18 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["InvestigateGetParams"] - - -class InvestigateGetParams(TypedDict, total=False): - account_id: Required[str] - """Account Identifier""" - - submission: bool - """When true, search the submissions datastore only. - - When false or omitted, search the regular datastore only. - """ diff --git a/src/cloudflare/types/email_security/investigate_get_response.py b/src/cloudflare/types/email_security/investigate_get_response.py deleted file mode 100644 index 1396753de51..00000000000 --- a/src/cloudflare/types/email_security/investigate_get_response.py +++ /dev/null @@ -1,188 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from datetime import datetime -from typing_extensions import Literal - -from pydantic import Field as FieldInfo - -from ..._models import BaseModel - -__all__ = ["InvestigateGetResponse", "Properties", "Finding", "Validation"] - - -class Properties(BaseModel): - allowlisted_pattern: Optional[str] = None - - allowlisted_pattern_type: Optional[ - Literal[ - "quarantine_release", - "acceptable_sender", - "allowed_sender", - "allowed_recipient", - "domain_similarity", - "domain_recency", - "managed_acceptable_sender", - "outbound_ndr", - ] - ] = None - - blocklisted_message: Optional[bool] = None - - blocklisted_pattern: Optional[str] = None - - whitelisted_pattern_type: Optional[ - Literal[ - "quarantine_release", - "acceptable_sender", - "allowed_sender", - "allowed_recipient", - "domain_similarity", - "domain_recency", - "managed_acceptable_sender", - "outbound_ndr", - ] - ] = None - - -class Finding(BaseModel): - attachment: Optional[str] = None - - detail: Optional[str] = None - - detection: Optional[ - Literal[ - "MALICIOUS", - "MALICIOUS-BEC", - "SUSPICIOUS", - "SPOOF", - "SPAM", - "BULK", - "ENCRYPTED", - "EXTERNAL", - "UNKNOWN", - "NONE", - ] - ] = None - - field: Optional[str] = None - - name: Optional[str] = None - - portion: Optional[str] = None - - reason: Optional[str] = None - - score: Optional[float] = None - - value: Optional[str] = None - - -class Validation(BaseModel): - comment: Optional[str] = None - - dkim: Optional[Literal["pass", "neutral", "fail", "error", "none"]] = None - - dmarc: Optional[Literal["pass", "neutral", "fail", "error", "none"]] = None - - spf: Optional[Literal["pass", "neutral", "fail", "error", "none"]] = None - - -class InvestigateGetResponse(BaseModel): - id: str - - action_log: object - """Deprecated: use `/investigate/{id}/action_log` instead.""" - - client_recipients: List[str] - - detection_reasons: List[str] - - is_phish_submission: bool - - is_quarantined: bool - - postfix_id: str - """The identifier of the message.""" - - properties: Properties - - ts: str - """Deprecated, use `scanned_at` instead""" - - alert_id: Optional[str] = None - - delivery_mode: Optional[ - Literal[ - "DIRECT", - "BCC", - "JOURNAL", - "REVIEW_SUBMISSION", - "DMARC_UNVERIFIED", - "DMARC_FAILURE_REPORT", - "DMARC_AGGREGATE_REPORT", - "THREAT_INTEL_SUBMISSION", - "SIMULATION_SUBMISSION", - "API", - "RETRO_SCAN", - ] - ] = None - - delivery_status: Optional[ - List[Literal["delivered", "moved", "quarantined", "rejected", "deferred", "bounced", "queued"]] - ] = None - - edf_hash: Optional[str] = None - - envelope_from: Optional[str] = None - - envelope_to: Optional[List[str]] = None - - final_disposition: Optional[ - Literal[ - "MALICIOUS", - "MALICIOUS-BEC", - "SUSPICIOUS", - "SPOOF", - "SPAM", - "BULK", - "ENCRYPTED", - "EXTERNAL", - "UNKNOWN", - "NONE", - ] - ] = None - - findings: Optional[List[Finding]] = None - """Deprecated: use `/investigate/{id}/detections` instead.""" - - from_: Optional[str] = FieldInfo(alias="from", default=None) - - from_name: Optional[str] = None - - htmltext_structure_hash: Optional[str] = None - - message_id: Optional[str] = None - - post_delivery_operations: Optional[List[Literal["PREVIEW", "QUARANTINE_RELEASE", "SUBMISSION", "MOVE"]]] = None - - postfix_id_outbound: Optional[str] = None - - replyto: Optional[str] = None - - scanned_at: Optional[datetime] = None - - sent_at: Optional[datetime] = None - - sent_date: Optional[str] = None - """Deprecated, use `sent_at` instead""" - - subject: Optional[str] = None - - threat_categories: Optional[List[str]] = None - - to: Optional[List[str]] = None - - to_name: Optional[List[str]] = None - - validation: Optional[Validation] = None diff --git a/src/cloudflare/types/email_security/investigate_list_params.py b/src/cloudflare/types/email_security/investigate_list_params.py index 53d42d0d208..6cb7270dabb 100644 --- a/src/cloudflare/types/email_security/investigate_list_params.py +++ b/src/cloudflare/types/email_security/investigate_list_params.py @@ -13,90 +13,48 @@ class InvestigateListParams(TypedDict, total=False): account_id: Required[str] - """Account Identifier""" + """Identifier.""" action_log: bool - """Determines if the message action log is included in the response.""" + """Whether to include the message action log in the response.""" alert_id: str cursor: str detections_only: bool - """Determines if the search results will include detections or not.""" + """Whether to include only detections in search results.""" domain: str - """ - Filter by a domain found in the email: sender domain, recipient domain, or a - domain in a link. - """ + """Sender domains to filter by.""" end: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """The end of the search date range. Defaults to `now` if not provided.""" - - exact_subject: str - """Search for messages with an exact subject match.""" + """The end of the search date range. Defaults to `now`.""" final_disposition: Literal["MALICIOUS", "SUSPICIOUS", "SPOOF", "SPAM", "BULK", "NONE"] - """The dispositions the search filters by.""" + """Dispositions to filter by.""" - message_action: Literal["PREVIEW", "QUARANTINE_RELEASED", "MOVED", "SUBMITTED"] - """The message actions the search filters by.""" + message_action: Literal["PREVIEW", "QUARANTINE_RELEASED", "MOVED"] + """Message actions to filter by.""" message_id: str metric: str page: Optional[int] - """Deprecated: Use cursor pagination instead.""" + """Deprecated: Use cursor pagination instead. End of life: November 1, 2026.""" per_page: int """The number of results per page. Maximum value is 1000.""" query: str - """The space-delimited term used in the query. The search is case-insensitive. - - The content of the following email metadata fields are searched: - - - alert_id - - CC - - From (envelope_from) - - From Name - - final_disposition - - md5 hash (of any attachment) - - sha1 hash (of any attachment) - - sha256 hash (of any attachment) - - name (of any attachment) - - Reason - - Received DateTime (yyyy-mm-ddThh:mm:ss) - - Sent DateTime (yyyy-mm-ddThh:mm:ss) - - ReplyTo - - To (envelope_to) - - To Name - - Message-ID - - smtp_helo_server_ip - - smtp_previous_hop_ip - - x_originating_ip - - Subject - """ + """Space-delimited search term. Case-insensitive.""" recipient: str - """Filter by recipient. Matches either an email address or a domain.""" sender: str - """Filter by sender. Matches either an email address or a domain.""" start: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """ - The beginning of the search date range. Defaults to `now - 30 days` if not - provided. - """ + """The beginning of the search date range. Defaults to `now - 30 days`.""" subject: str - """ - Search for messages containing individual keywords in any order within the - subject. - """ - - submissions: bool - """Search for submissions instead of original messages""" diff --git a/src/cloudflare/types/email_security/investigate_list_response.py b/src/cloudflare/types/email_security/investigate_list_response.py index 12c5ae7cb75..d13d2fb80dd 100644 --- a/src/cloudflare/types/email_security/investigate_list_response.py +++ b/src/cloudflare/types/email_security/investigate_list_response.py @@ -8,11 +8,41 @@ from ..._models import BaseModel -__all__ = ["InvestigateListResponse", "Properties", "Finding", "Validation"] +__all__ = ["InvestigateListResponse", "ActionLog", "ActionLogProperties", "Properties", "Finding", "Validation"] + + +class ActionLogProperties(BaseModel): + """Additional properties for the action""" + + folder: Optional[str] = None + """Target folder for move operations""" + + requested_by: Optional[str] = None + """User who requested the action""" + + +class ActionLog(BaseModel): + completed_at: datetime + """Timestamp when action completed""" + + operation: Literal["MOVE", "RELEASE", "RECLASSIFY", "SUBMISSION", "QUARANTINE_RELEASE", "PREVIEW"] + """Type of action performed""" + + completed_timestamp: Optional[str] = None + """Deprecated, use `completed_at` instead. End of life: November 1, 2026.""" + + properties: Optional[ActionLogProperties] = None + """Additional properties for the action""" + + status: Optional[str] = None + """Status of the action""" class Properties(BaseModel): + """Message processing properties""" + allowlisted_pattern: Optional[str] = None + """Pattern that allowlisted this message""" allowlisted_pattern_type: Optional[ Literal[ @@ -26,10 +56,13 @@ class Properties(BaseModel): "outbound_ndr", ] ] = None + """Type of allowlist pattern""" blocklisted_message: Optional[bool] = None + """Whether message was blocklisted""" blocklisted_pattern: Optional[str] = None + """Pattern that blocklisted this message""" whitelisted_pattern_type: Optional[ Literal[ @@ -43,6 +76,7 @@ class Properties(BaseModel): "outbound_ndr", ] ] = None + """Legacy field for allowlist pattern type""" class Finding(BaseModel): @@ -90,9 +124,13 @@ class Validation(BaseModel): class InvestigateListResponse(BaseModel): id: str + """Unique identifier for a message retrieved from investigation""" + + action_log: List[ActionLog] + """Deprecated, use `GET /investigate/{investigate_id}/action_log` instead. - action_log: object - """Deprecated: use `/investigate/{id}/action_log` instead.""" + End of life: November 1, 2026. + """ client_recipients: List[str] @@ -103,12 +141,13 @@ class InvestigateListResponse(BaseModel): is_quarantined: bool postfix_id: str - """The identifier of the message.""" + """The identifier of the message""" properties: Properties + """Message processing properties""" ts: str - """Deprecated, use `scanned_at` instead""" + """Deprecated, use `scanned_at` instead. End of life: November 1, 2026.""" alert_id: Optional[str] = None @@ -154,7 +193,11 @@ class InvestigateListResponse(BaseModel): ] = None findings: Optional[List[Finding]] = None - """Deprecated: use `/investigate/{id}/detections` instead.""" + """ + Deprecated, use the `findings` field from + `GET /investigate/{investigate_id}/detections` instead. End of life: November + 1, 2026. Detection findings for this message. + """ from_: Optional[str] = FieldInfo(alias="from", default=None) @@ -165,17 +208,19 @@ class InvestigateListResponse(BaseModel): message_id: Optional[str] = None post_delivery_operations: Optional[List[Literal["PREVIEW", "QUARANTINE_RELEASE", "SUBMISSION", "MOVE"]]] = None + """Post-delivery operations performed on this message""" postfix_id_outbound: Optional[str] = None replyto: Optional[str] = None scanned_at: Optional[datetime] = None + """When the message was scanned (UTC)""" sent_at: Optional[datetime] = None + """When the message was sent (UTC)""" sent_date: Optional[str] = None - """Deprecated, use `sent_at` instead""" subject: Optional[str] = None diff --git a/src/cloudflare/types/email_security/phishguard/report_list_params.py b/src/cloudflare/types/email_security/phishguard/report_list_params.py index d138ab6e96c..7f8fd4a7254 100644 --- a/src/cloudflare/types/email_security/phishguard/report_list_params.py +++ b/src/cloudflare/types/email_security/phishguard/report_list_params.py @@ -13,14 +13,16 @@ class ReportListParams(TypedDict, total=False): account_id: Required[str] - """Account Identifier""" + """Identifier.""" end: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """The end of the search date range (RFC3339 format).""" + """End of the time range (RFC3339). Takes precedence over to_date.""" from_date: Annotated[Union[str, date], PropertyInfo(format="iso8601")] + """Deprecated, use `start` instead. Start date in YYYY-MM-DD format.""" start: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """The beginning of the search date range (RFC3339 format).""" + """Start of the time range (RFC3339). Takes precedence over from_date.""" to_date: Annotated[Union[str, date], PropertyInfo(format="iso8601")] + """Deprecated, use `end` instead. End date in YYYY-MM-DD format.""" diff --git a/src/cloudflare/types/email_security/phishguard/report_list_response.py b/src/cloudflare/types/email_security/phishguard/report_list_response.py index 2f8b6b21cf2..c97e9941b10 100644 --- a/src/cloudflare/types/email_security/phishguard/report_list_response.py +++ b/src/cloudflare/types/email_security/phishguard/report_list_response.py @@ -14,12 +14,15 @@ class Fields(BaseModel): to: List[str] - ts: datetime - from_: Optional[str] = FieldInfo(alias="from", default=None) + occurred_at: Optional[datetime] = None + postfix_id: Optional[str] = None + ts: Optional[datetime] = None + """Deprecated, use `occurred_at` instead""" + class Tag(BaseModel): category: str @@ -32,8 +35,6 @@ class ReportListResponse(BaseModel): content: str - created_at: datetime - disposition: Literal[ "MALICIOUS", "MALICIOUS-BEC", "SUSPICIOUS", "SPOOF", "SPAM", "BULK", "ENCRYPTED", "EXTERNAL", "UNKNOWN", "NONE" ] @@ -44,8 +45,11 @@ class ReportListResponse(BaseModel): title: str - ts: datetime - - updated_at: datetime + created_at: Optional[datetime] = None tags: Optional[List[Tag]] = None + + ts: Optional[datetime] = None + """Deprecated, use `created_at` instead""" + + updated_at: Optional[datetime] = None diff --git a/src/cloudflare/types/email_security/settings/__init__.py b/src/cloudflare/types/email_security/settings/__init__.py index 26c5fc41f06..866ff04dbcc 100644 --- a/src/cloudflare/types/email_security/settings/__init__.py +++ b/src/cloudflare/types/email_security/settings/__init__.py @@ -22,7 +22,6 @@ from .block_sender_list_response import BlockSenderListResponse as BlockSenderListResponse from .trusted_domain_edit_params import TrustedDomainEditParams as TrustedDomainEditParams from .trusted_domain_list_params import TrustedDomainListParams as TrustedDomainListParams -from .domain_bulk_delete_response import DomainBulkDeleteResponse as DomainBulkDeleteResponse from .trusted_domain_get_response import TrustedDomainGetResponse as TrustedDomainGetResponse from .allow_policy_create_response import AllowPolicyCreateResponse as AllowPolicyCreateResponse from .allow_policy_delete_response import AllowPolicyDeleteResponse as AllowPolicyDeleteResponse @@ -33,15 +32,9 @@ from .trusted_domain_list_response import TrustedDomainListResponse as TrustedDomainListResponse from .trusted_domain_create_response import TrustedDomainCreateResponse as TrustedDomainCreateResponse from .trusted_domain_delete_response import TrustedDomainDeleteResponse as TrustedDomainDeleteResponse -from .impersonation_registry_edit_params import ImpersonationRegistryEditParams as ImpersonationRegistryEditParams from .impersonation_registry_list_params import ImpersonationRegistryListParams as ImpersonationRegistryListParams -from .impersonation_registry_get_response import ImpersonationRegistryGetResponse as ImpersonationRegistryGetResponse from .impersonation_registry_create_params import ImpersonationRegistryCreateParams as ImpersonationRegistryCreateParams -from .impersonation_registry_edit_response import ImpersonationRegistryEditResponse as ImpersonationRegistryEditResponse from .impersonation_registry_list_response import ImpersonationRegistryListResponse as ImpersonationRegistryListResponse from .impersonation_registry_create_response import ( ImpersonationRegistryCreateResponse as ImpersonationRegistryCreateResponse, ) -from .impersonation_registry_delete_response import ( - ImpersonationRegistryDeleteResponse as ImpersonationRegistryDeleteResponse, -) diff --git a/src/cloudflare/types/email_security/settings/allow_policy_create_params.py b/src/cloudflare/types/email_security/settings/allow_policy_create_params.py index 9c0e132e1b2..fed310a2694 100644 --- a/src/cloudflare/types/email_security/settings/allow_policy_create_params.py +++ b/src/cloudflare/types/email_security/settings/allow_policy_create_params.py @@ -10,37 +10,53 @@ class AllowPolicyCreateParams(TypedDict, total=False): account_id: Required[str] - """Account Identifier""" + """Identifier.""" is_acceptable_sender: Required[bool] """ Messages from this sender will be exempted from Spam, Spoof and Bulk - dispositions. Note: This will not exempt messages with Malicious or Suspicious + dispositions. Note - This will not exempt messages with Malicious or Suspicious dispositions. """ is_exempt_recipient: Required[bool] - """Messages to this recipient will bypass all detections.""" + """Messages to this recipient will bypass all detections""" is_regex: Required[bool] is_trusted_sender: Required[bool] - """Messages from this sender will bypass all detections and link following.""" + """Messages from this sender will bypass all detections and link following""" pattern: Required[str] pattern_type: Required[Literal["EMAIL", "DOMAIN", "IP", "UNKNOWN"]] + """ + Type of pattern matching. Note: UNKNOWN is deprecated and cannot be used when + creating or updating policies, but may be returned for existing entries. + """ verify_sender: Required[bool] - """ - Enforce DMARC, SPF or DKIM authentication. When on, Email Security only honors - policies that pass authentication. + """Enforce DMARC, SPF or DKIM authentication. + + When on, Email Security only honors policies that pass authentication. """ comments: Optional[str] is_recipient: bool + """Deprecated as of July 1, 2025. + + Use `is_exempt_recipient` instead. End of life: July 1, 2026. + """ is_sender: bool + """Deprecated as of July 1, 2025. + + Use `is_trusted_sender` instead. End of life: July 1, 2026. + """ is_spoof: bool + """Deprecated as of July 1, 2025. + + Use `is_acceptable_sender` instead. End of life: July 1, 2026. + """ diff --git a/src/cloudflare/types/email_security/settings/allow_policy_create_response.py b/src/cloudflare/types/email_security/settings/allow_policy_create_response.py index 312ff7e2a7c..de5da6c4541 100644 --- a/src/cloudflare/types/email_security/settings/allow_policy_create_response.py +++ b/src/cloudflare/types/email_security/settings/allow_policy_create_response.py @@ -10,42 +10,63 @@ class AllowPolicyCreateResponse(BaseModel): - id: int - """The unique identifier for the allow policy.""" + """An email allow policy""" + + id: str + """Allow policy identifier""" created_at: datetime - is_acceptable_sender: bool + last_modified: datetime + """Deprecated, use `modified_at` instead. End of life: November 1, 2026.""" + + comments: Optional[str] = None + + is_acceptable_sender: Optional[bool] = None """ Messages from this sender will be exempted from Spam, Spoof and Bulk - dispositions. Note: This will not exempt messages with Malicious or Suspicious + dispositions. Note - This will not exempt messages with Malicious or Suspicious dispositions. """ - is_exempt_recipient: bool - """Messages to this recipient will bypass all detections.""" - - is_regex: bool + is_exempt_recipient: Optional[bool] = None + """Messages to this recipient will bypass all detections""" - is_trusted_sender: bool - """Messages from this sender will bypass all detections and link following.""" + is_recipient: Optional[bool] = None + """Deprecated as of July 1, 2025. - last_modified: datetime + Use `is_exempt_recipient` instead. End of life: July 1, 2026. + """ - pattern: str + is_regex: Optional[bool] = None - pattern_type: Literal["EMAIL", "DOMAIN", "IP", "UNKNOWN"] + is_sender: Optional[bool] = None + """Deprecated as of July 1, 2025. - verify_sender: bool + Use `is_trusted_sender` instead. End of life: July 1, 2026. """ - Enforce DMARC, SPF or DKIM authentication. When on, Email Security only honors - policies that pass authentication. + + is_spoof: Optional[bool] = None + """Deprecated as of July 1, 2025. + + Use `is_acceptable_sender` instead. End of life: July 1, 2026. """ - comments: Optional[str] = None + is_trusted_sender: Optional[bool] = None + """Messages from this sender will bypass all detections and link following""" - is_recipient: Optional[bool] = None + modified_at: Optional[datetime] = None - is_sender: Optional[bool] = None + pattern: Optional[str] = None - is_spoof: Optional[bool] = None + pattern_type: Optional[Literal["EMAIL", "DOMAIN", "IP", "UNKNOWN"]] = None + """ + Type of pattern matching. Note: UNKNOWN is deprecated and cannot be used when + creating or updating policies, but may be returned for existing entries. + """ + + verify_sender: Optional[bool] = None + """Enforce DMARC, SPF or DKIM authentication. + + When on, Email Security only honors policies that pass authentication. + """ diff --git a/src/cloudflare/types/email_security/settings/allow_policy_delete_response.py b/src/cloudflare/types/email_security/settings/allow_policy_delete_response.py index 38627fc0c30..d46f059d358 100644 --- a/src/cloudflare/types/email_security/settings/allow_policy_delete_response.py +++ b/src/cloudflare/types/email_security/settings/allow_policy_delete_response.py @@ -6,5 +6,5 @@ class AllowPolicyDeleteResponse(BaseModel): - id: int - """The unique identifier for the allow policy.""" + id: str + """Allow policy identifier""" diff --git a/src/cloudflare/types/email_security/settings/allow_policy_edit_params.py b/src/cloudflare/types/email_security/settings/allow_policy_edit_params.py index 6b4de29a3bb..b9d37e6e6f5 100644 --- a/src/cloudflare/types/email_security/settings/allow_policy_edit_params.py +++ b/src/cloudflare/types/email_security/settings/allow_policy_edit_params.py @@ -10,31 +10,53 @@ class AllowPolicyEditParams(TypedDict, total=False): account_id: Required[str] - """Account Identifier""" + """Identifier.""" comments: Optional[str] - is_acceptable_sender: Optional[bool] + is_acceptable_sender: bool """ Messages from this sender will be exempted from Spam, Spoof and Bulk - dispositions. Note: This will not exempt messages with Malicious or Suspicious + dispositions. Note - This will not exempt messages with Malicious or Suspicious dispositions. """ - is_exempt_recipient: Optional[bool] - """Messages to this recipient will bypass all detections.""" + is_exempt_recipient: bool + """Messages to this recipient will bypass all detections""" - is_regex: Optional[bool] + is_recipient: bool + """Deprecated as of July 1, 2025. - is_trusted_sender: Optional[bool] - """Messages from this sender will bypass all detections and link following.""" + Use `is_exempt_recipient` instead. End of life: July 1, 2026. + """ + + is_regex: bool + + is_sender: bool + """Deprecated as of July 1, 2025. - pattern: Optional[str] + Use `is_trusted_sender` instead. End of life: July 1, 2026. + """ - pattern_type: Optional[Literal["EMAIL", "DOMAIN", "IP", "UNKNOWN"]] + is_spoof: bool + """Deprecated as of July 1, 2025. - verify_sender: Optional[bool] + Use `is_acceptable_sender` instead. End of life: July 1, 2026. """ - Enforce DMARC, SPF or DKIM authentication. When on, Email Security only honors - policies that pass authentication. + + is_trusted_sender: bool + """Messages from this sender will bypass all detections and link following""" + + pattern: str + + pattern_type: Literal["EMAIL", "DOMAIN", "IP", "UNKNOWN"] + """ + Type of pattern matching. Note: UNKNOWN is deprecated and cannot be used when + creating or updating policies, but may be returned for existing entries. + """ + + verify_sender: bool + """Enforce DMARC, SPF or DKIM authentication. + + When on, Email Security only honors policies that pass authentication. """ diff --git a/src/cloudflare/types/email_security/settings/allow_policy_edit_response.py b/src/cloudflare/types/email_security/settings/allow_policy_edit_response.py index eb66126b593..ed1743f4f0a 100644 --- a/src/cloudflare/types/email_security/settings/allow_policy_edit_response.py +++ b/src/cloudflare/types/email_security/settings/allow_policy_edit_response.py @@ -10,42 +10,63 @@ class AllowPolicyEditResponse(BaseModel): - id: int - """The unique identifier for the allow policy.""" + """An email allow policy""" + + id: str + """Allow policy identifier""" created_at: datetime - is_acceptable_sender: bool + last_modified: datetime + """Deprecated, use `modified_at` instead. End of life: November 1, 2026.""" + + comments: Optional[str] = None + + is_acceptable_sender: Optional[bool] = None """ Messages from this sender will be exempted from Spam, Spoof and Bulk - dispositions. Note: This will not exempt messages with Malicious or Suspicious + dispositions. Note - This will not exempt messages with Malicious or Suspicious dispositions. """ - is_exempt_recipient: bool - """Messages to this recipient will bypass all detections.""" - - is_regex: bool + is_exempt_recipient: Optional[bool] = None + """Messages to this recipient will bypass all detections""" - is_trusted_sender: bool - """Messages from this sender will bypass all detections and link following.""" + is_recipient: Optional[bool] = None + """Deprecated as of July 1, 2025. - last_modified: datetime + Use `is_exempt_recipient` instead. End of life: July 1, 2026. + """ - pattern: str + is_regex: Optional[bool] = None - pattern_type: Literal["EMAIL", "DOMAIN", "IP", "UNKNOWN"] + is_sender: Optional[bool] = None + """Deprecated as of July 1, 2025. - verify_sender: bool + Use `is_trusted_sender` instead. End of life: July 1, 2026. """ - Enforce DMARC, SPF or DKIM authentication. When on, Email Security only honors - policies that pass authentication. + + is_spoof: Optional[bool] = None + """Deprecated as of July 1, 2025. + + Use `is_acceptable_sender` instead. End of life: July 1, 2026. """ - comments: Optional[str] = None + is_trusted_sender: Optional[bool] = None + """Messages from this sender will bypass all detections and link following""" - is_recipient: Optional[bool] = None + modified_at: Optional[datetime] = None - is_sender: Optional[bool] = None + pattern: Optional[str] = None - is_spoof: Optional[bool] = None + pattern_type: Optional[Literal["EMAIL", "DOMAIN", "IP", "UNKNOWN"]] = None + """ + Type of pattern matching. Note: UNKNOWN is deprecated and cannot be used when + creating or updating policies, but may be returned for existing entries. + """ + + verify_sender: Optional[bool] = None + """Enforce DMARC, SPF or DKIM authentication. + + When on, Email Security only honors policies that pass authentication. + """ diff --git a/src/cloudflare/types/email_security/settings/allow_policy_get_response.py b/src/cloudflare/types/email_security/settings/allow_policy_get_response.py index e9cb0384cf3..c2cb6e12603 100644 --- a/src/cloudflare/types/email_security/settings/allow_policy_get_response.py +++ b/src/cloudflare/types/email_security/settings/allow_policy_get_response.py @@ -10,42 +10,63 @@ class AllowPolicyGetResponse(BaseModel): - id: int - """The unique identifier for the allow policy.""" + """An email allow policy""" + + id: str + """Allow policy identifier""" created_at: datetime - is_acceptable_sender: bool + last_modified: datetime + """Deprecated, use `modified_at` instead. End of life: November 1, 2026.""" + + comments: Optional[str] = None + + is_acceptable_sender: Optional[bool] = None """ Messages from this sender will be exempted from Spam, Spoof and Bulk - dispositions. Note: This will not exempt messages with Malicious or Suspicious + dispositions. Note - This will not exempt messages with Malicious or Suspicious dispositions. """ - is_exempt_recipient: bool - """Messages to this recipient will bypass all detections.""" - - is_regex: bool + is_exempt_recipient: Optional[bool] = None + """Messages to this recipient will bypass all detections""" - is_trusted_sender: bool - """Messages from this sender will bypass all detections and link following.""" + is_recipient: Optional[bool] = None + """Deprecated as of July 1, 2025. - last_modified: datetime + Use `is_exempt_recipient` instead. End of life: July 1, 2026. + """ - pattern: str + is_regex: Optional[bool] = None - pattern_type: Literal["EMAIL", "DOMAIN", "IP", "UNKNOWN"] + is_sender: Optional[bool] = None + """Deprecated as of July 1, 2025. - verify_sender: bool + Use `is_trusted_sender` instead. End of life: July 1, 2026. """ - Enforce DMARC, SPF or DKIM authentication. When on, Email Security only honors - policies that pass authentication. + + is_spoof: Optional[bool] = None + """Deprecated as of July 1, 2025. + + Use `is_acceptable_sender` instead. End of life: July 1, 2026. """ - comments: Optional[str] = None + is_trusted_sender: Optional[bool] = None + """Messages from this sender will bypass all detections and link following""" - is_recipient: Optional[bool] = None + modified_at: Optional[datetime] = None - is_sender: Optional[bool] = None + pattern: Optional[str] = None - is_spoof: Optional[bool] = None + pattern_type: Optional[Literal["EMAIL", "DOMAIN", "IP", "UNKNOWN"]] = None + """ + Type of pattern matching. Note: UNKNOWN is deprecated and cannot be used when + creating or updating policies, but may be returned for existing entries. + """ + + verify_sender: Optional[bool] = None + """Enforce DMARC, SPF or DKIM authentication. + + When on, Email Security only honors policies that pass authentication. + """ diff --git a/src/cloudflare/types/email_security/settings/allow_policy_list_params.py b/src/cloudflare/types/email_security/settings/allow_policy_list_params.py index 85380271064..5c57fcb71a4 100644 --- a/src/cloudflare/types/email_security/settings/allow_policy_list_params.py +++ b/src/cloudflare/types/email_security/settings/allow_policy_list_params.py @@ -9,41 +9,48 @@ class AllowPolicyListParams(TypedDict, total=False): account_id: Required[str] - """Account Identifier""" + """Identifier.""" direction: Literal["asc", "desc"] """The sorting direction.""" is_acceptable_sender: bool + """ + Filter to show only policies where messages from the sender are exempted from + Spam, Spoof, and Bulk dispositions (not Malicious or Suspicious). + """ is_exempt_recipient: bool - - is_recipient: bool - - is_sender: bool - - is_spoof: bool + """ + Filter to show only policies where messages to the recipient bypass all + detections. + """ is_trusted_sender: bool + """ + Filter to show only policies where messages from the sender bypass all + detections and link following. + """ order: Literal["pattern", "created_at"] - """The field to sort by.""" + """Field to sort by.""" page: int - """The page number of paginated results.""" + """Current page within paginated list of results.""" pattern: str pattern_type: Literal["EMAIL", "DOMAIN", "IP", "UNKNOWN"] + """ + Type of pattern matching. Note: UNKNOWN is deprecated and cannot be used when + creating or updating policies, but may be returned for existing entries. + """ per_page: int - """The number of results per page.""" + """The number of results per page. Maximum value is 1000.""" search: str - """ - Allows searching in multiple properties of a record simultaneously. This - parameter is intended for human users, not automation. Its exact behavior is - intentionally left unspecified and is subject to change in the future. - """ + """Search term for filtering records. Behavior may change.""" verify_sender: bool + """Filter to show only policies that enforce DMARC, SPF, or DKIM authentication.""" diff --git a/src/cloudflare/types/email_security/settings/allow_policy_list_response.py b/src/cloudflare/types/email_security/settings/allow_policy_list_response.py index 9b4c57f2a22..9e77c75eccc 100644 --- a/src/cloudflare/types/email_security/settings/allow_policy_list_response.py +++ b/src/cloudflare/types/email_security/settings/allow_policy_list_response.py @@ -10,42 +10,63 @@ class AllowPolicyListResponse(BaseModel): - id: int - """The unique identifier for the allow policy.""" + """An email allow policy""" + + id: str + """Allow policy identifier""" created_at: datetime - is_acceptable_sender: bool + last_modified: datetime + """Deprecated, use `modified_at` instead. End of life: November 1, 2026.""" + + comments: Optional[str] = None + + is_acceptable_sender: Optional[bool] = None """ Messages from this sender will be exempted from Spam, Spoof and Bulk - dispositions. Note: This will not exempt messages with Malicious or Suspicious + dispositions. Note - This will not exempt messages with Malicious or Suspicious dispositions. """ - is_exempt_recipient: bool - """Messages to this recipient will bypass all detections.""" - - is_regex: bool + is_exempt_recipient: Optional[bool] = None + """Messages to this recipient will bypass all detections""" - is_trusted_sender: bool - """Messages from this sender will bypass all detections and link following.""" + is_recipient: Optional[bool] = None + """Deprecated as of July 1, 2025. - last_modified: datetime + Use `is_exempt_recipient` instead. End of life: July 1, 2026. + """ - pattern: str + is_regex: Optional[bool] = None - pattern_type: Literal["EMAIL", "DOMAIN", "IP", "UNKNOWN"] + is_sender: Optional[bool] = None + """Deprecated as of July 1, 2025. - verify_sender: bool + Use `is_trusted_sender` instead. End of life: July 1, 2026. """ - Enforce DMARC, SPF or DKIM authentication. When on, Email Security only honors - policies that pass authentication. + + is_spoof: Optional[bool] = None + """Deprecated as of July 1, 2025. + + Use `is_acceptable_sender` instead. End of life: July 1, 2026. """ - comments: Optional[str] = None + is_trusted_sender: Optional[bool] = None + """Messages from this sender will bypass all detections and link following""" - is_recipient: Optional[bool] = None + modified_at: Optional[datetime] = None - is_sender: Optional[bool] = None + pattern: Optional[str] = None - is_spoof: Optional[bool] = None + pattern_type: Optional[Literal["EMAIL", "DOMAIN", "IP", "UNKNOWN"]] = None + """ + Type of pattern matching. Note: UNKNOWN is deprecated and cannot be used when + creating or updating policies, but may be returned for existing entries. + """ + + verify_sender: Optional[bool] = None + """Enforce DMARC, SPF or DKIM authentication. + + When on, Email Security only honors policies that pass authentication. + """ diff --git a/src/cloudflare/types/email_security/settings/block_sender_create_params.py b/src/cloudflare/types/email_security/settings/block_sender_create_params.py index dc5290d600f..7b1c5b3a3d0 100644 --- a/src/cloudflare/types/email_security/settings/block_sender_create_params.py +++ b/src/cloudflare/types/email_security/settings/block_sender_create_params.py @@ -10,12 +10,16 @@ class BlockSenderCreateParams(TypedDict, total=False): account_id: Required[str] - """Account Identifier""" + """Identifier.""" is_regex: Required[bool] pattern: Required[str] pattern_type: Required[Literal["EMAIL", "DOMAIN", "IP", "UNKNOWN"]] + """ + Type of pattern matching. Note: UNKNOWN is deprecated and cannot be used when + creating or updating policies, but may be returned for existing entries. + """ comments: Optional[str] diff --git a/src/cloudflare/types/email_security/settings/block_sender_create_response.py b/src/cloudflare/types/email_security/settings/block_sender_create_response.py index 615755f8fd7..b3b0d507355 100644 --- a/src/cloudflare/types/email_security/settings/block_sender_create_response.py +++ b/src/cloudflare/types/email_security/settings/block_sender_create_response.py @@ -10,17 +10,26 @@ class BlockSenderCreateResponse(BaseModel): - id: int - """The unique identifier for the allow policy.""" + """A blocked sender pattern""" - created_at: datetime + id: Optional[str] = None + """Blocked sender pattern identifier""" - is_regex: bool + comments: Optional[str] = None - last_modified: datetime + created_at: Optional[datetime] = None - pattern: str + is_regex: Optional[bool] = None - pattern_type: Literal["EMAIL", "DOMAIN", "IP", "UNKNOWN"] + last_modified: Optional[datetime] = None + """Deprecated, use `modified_at` instead. End of life: November 1, 2026.""" - comments: Optional[str] = None + modified_at: Optional[datetime] = None + + pattern: Optional[str] = None + + pattern_type: Optional[Literal["EMAIL", "DOMAIN", "IP", "UNKNOWN"]] = None + """ + Type of pattern matching. Note: UNKNOWN is deprecated and cannot be used when + creating or updating policies, but may be returned for existing entries. + """ diff --git a/src/cloudflare/types/email_security/settings/block_sender_delete_response.py b/src/cloudflare/types/email_security/settings/block_sender_delete_response.py index ea8337060bf..cf2927b2847 100644 --- a/src/cloudflare/types/email_security/settings/block_sender_delete_response.py +++ b/src/cloudflare/types/email_security/settings/block_sender_delete_response.py @@ -6,5 +6,5 @@ class BlockSenderDeleteResponse(BaseModel): - id: int - """The unique identifier for the allow policy.""" + id: str + """Blocked sender pattern identifier""" diff --git a/src/cloudflare/types/email_security/settings/block_sender_edit_params.py b/src/cloudflare/types/email_security/settings/block_sender_edit_params.py index 19f2d23458a..756f0a1e79e 100644 --- a/src/cloudflare/types/email_security/settings/block_sender_edit_params.py +++ b/src/cloudflare/types/email_security/settings/block_sender_edit_params.py @@ -10,12 +10,16 @@ class BlockSenderEditParams(TypedDict, total=False): account_id: Required[str] - """Account Identifier""" + """Identifier.""" comments: Optional[str] - is_regex: Optional[bool] + is_regex: bool - pattern: Optional[str] + pattern: str - pattern_type: Optional[Literal["EMAIL", "DOMAIN", "IP", "UNKNOWN"]] + pattern_type: Literal["EMAIL", "DOMAIN", "IP", "UNKNOWN"] + """ + Type of pattern matching. Note: UNKNOWN is deprecated and cannot be used when + creating or updating policies, but may be returned for existing entries. + """ diff --git a/src/cloudflare/types/email_security/settings/block_sender_edit_response.py b/src/cloudflare/types/email_security/settings/block_sender_edit_response.py index 764d9fd5dee..0ade492c40b 100644 --- a/src/cloudflare/types/email_security/settings/block_sender_edit_response.py +++ b/src/cloudflare/types/email_security/settings/block_sender_edit_response.py @@ -10,17 +10,26 @@ class BlockSenderEditResponse(BaseModel): - id: int - """The unique identifier for the allow policy.""" + """A blocked sender pattern""" - created_at: datetime + id: Optional[str] = None + """Blocked sender pattern identifier""" - is_regex: bool + comments: Optional[str] = None - last_modified: datetime + created_at: Optional[datetime] = None - pattern: str + is_regex: Optional[bool] = None - pattern_type: Literal["EMAIL", "DOMAIN", "IP", "UNKNOWN"] + last_modified: Optional[datetime] = None + """Deprecated, use `modified_at` instead. End of life: November 1, 2026.""" - comments: Optional[str] = None + modified_at: Optional[datetime] = None + + pattern: Optional[str] = None + + pattern_type: Optional[Literal["EMAIL", "DOMAIN", "IP", "UNKNOWN"]] = None + """ + Type of pattern matching. Note: UNKNOWN is deprecated and cannot be used when + creating or updating policies, but may be returned for existing entries. + """ diff --git a/src/cloudflare/types/email_security/settings/block_sender_get_response.py b/src/cloudflare/types/email_security/settings/block_sender_get_response.py index 66f03f3e3f6..9a513f36a76 100644 --- a/src/cloudflare/types/email_security/settings/block_sender_get_response.py +++ b/src/cloudflare/types/email_security/settings/block_sender_get_response.py @@ -10,17 +10,26 @@ class BlockSenderGetResponse(BaseModel): - id: int - """The unique identifier for the allow policy.""" + """A blocked sender pattern""" - created_at: datetime + id: Optional[str] = None + """Blocked sender pattern identifier""" - is_regex: bool + comments: Optional[str] = None - last_modified: datetime + created_at: Optional[datetime] = None - pattern: str + is_regex: Optional[bool] = None - pattern_type: Literal["EMAIL", "DOMAIN", "IP", "UNKNOWN"] + last_modified: Optional[datetime] = None + """Deprecated, use `modified_at` instead. End of life: November 1, 2026.""" - comments: Optional[str] = None + modified_at: Optional[datetime] = None + + pattern: Optional[str] = None + + pattern_type: Optional[Literal["EMAIL", "DOMAIN", "IP", "UNKNOWN"]] = None + """ + Type of pattern matching. Note: UNKNOWN is deprecated and cannot be used when + creating or updating policies, but may be returned for existing entries. + """ diff --git a/src/cloudflare/types/email_security/settings/block_sender_list_params.py b/src/cloudflare/types/email_security/settings/block_sender_list_params.py index 712ad5932dd..9c1fe7b8850 100644 --- a/src/cloudflare/types/email_security/settings/block_sender_list_params.py +++ b/src/cloudflare/types/email_security/settings/block_sender_list_params.py @@ -9,27 +9,25 @@ class BlockSenderListParams(TypedDict, total=False): account_id: Required[str] - """Account Identifier""" + """Identifier.""" direction: Literal["asc", "desc"] """The sorting direction.""" order: Literal["pattern", "created_at"] - """The field to sort by.""" + """Field to sort by.""" page: int - """The page number of paginated results.""" + """Current page within paginated list of results.""" pattern: str + """Filter by pattern value.""" pattern_type: Literal["EMAIL", "DOMAIN", "IP", "UNKNOWN"] + """Filter by pattern type.""" per_page: int - """The number of results per page.""" + """The number of results per page. Maximum value is 1000.""" search: str - """ - Allows searching in multiple properties of a record simultaneously. This - parameter is intended for human users, not automation. Its exact behavior is - intentionally left unspecified and is subject to change in the future. - """ + """Search term for filtering records. Behavior may change.""" diff --git a/src/cloudflare/types/email_security/settings/block_sender_list_response.py b/src/cloudflare/types/email_security/settings/block_sender_list_response.py index 497ae4dc93d..10587592feb 100644 --- a/src/cloudflare/types/email_security/settings/block_sender_list_response.py +++ b/src/cloudflare/types/email_security/settings/block_sender_list_response.py @@ -10,17 +10,26 @@ class BlockSenderListResponse(BaseModel): - id: int - """The unique identifier for the allow policy.""" + """A blocked sender pattern""" - created_at: datetime + id: Optional[str] = None + """Blocked sender pattern identifier""" - is_regex: bool + comments: Optional[str] = None - last_modified: datetime + created_at: Optional[datetime] = None - pattern: str + is_regex: Optional[bool] = None - pattern_type: Literal["EMAIL", "DOMAIN", "IP", "UNKNOWN"] + last_modified: Optional[datetime] = None + """Deprecated, use `modified_at` instead. End of life: November 1, 2026.""" - comments: Optional[str] = None + modified_at: Optional[datetime] = None + + pattern: Optional[str] = None + + pattern_type: Optional[Literal["EMAIL", "DOMAIN", "IP", "UNKNOWN"]] = None + """ + Type of pattern matching. Note: UNKNOWN is deprecated and cannot be used when + creating or updating policies, but may be returned for existing entries. + """ diff --git a/src/cloudflare/types/email_security/settings/domain_bulk_delete_response.py b/src/cloudflare/types/email_security/settings/domain_bulk_delete_response.py deleted file mode 100644 index 76cb04b1987..00000000000 --- a/src/cloudflare/types/email_security/settings/domain_bulk_delete_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ...._models import BaseModel - -__all__ = ["DomainBulkDeleteResponse"] - - -class DomainBulkDeleteResponse(BaseModel): - id: int - """The unique identifier for the domain.""" diff --git a/src/cloudflare/types/email_security/settings/domain_delete_response.py b/src/cloudflare/types/email_security/settings/domain_delete_response.py index ab5ea3c8842..13a307fe1e9 100644 --- a/src/cloudflare/types/email_security/settings/domain_delete_response.py +++ b/src/cloudflare/types/email_security/settings/domain_delete_response.py @@ -6,5 +6,5 @@ class DomainDeleteResponse(BaseModel): - id: int - """The unique identifier for the domain.""" + id: str + """Domain identifier""" diff --git a/src/cloudflare/types/email_security/settings/domain_edit_params.py b/src/cloudflare/types/email_security/settings/domain_edit_params.py index bf6dec63309..f05612d8726 100644 --- a/src/cloudflare/types/email_security/settings/domain_edit_params.py +++ b/src/cloudflare/types/email_security/settings/domain_edit_params.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import List +from typing import List, Optional from typing_extensions import Literal, Required, TypedDict from ...._types import SequenceNotStr @@ -12,9 +12,7 @@ class DomainEditParams(TypedDict, total=False): account_id: Required[str] - """Account Identifier""" - - ip_restrictions: Required[SequenceNotStr[str]] + """Identifier.""" allowed_delivery_modes: List[Literal["DIRECT", "BCC", "JOURNAL", "API", "RETRO_SCAN"]] @@ -37,7 +35,9 @@ class DomainEditParams(TypedDict, total=False): folder: Literal["AllItems", "Inbox"] - integration_id: str + integration_id: Optional[str] + + ip_restrictions: SequenceNotStr[str] lookback_hops: int diff --git a/src/cloudflare/types/email_security/settings/domain_edit_response.py b/src/cloudflare/types/email_security/settings/domain_edit_response.py index 341b48ed16d..60f594792bb 100644 --- a/src/cloudflare/types/email_security/settings/domain_edit_response.py +++ b/src/cloudflare/types/email_security/settings/domain_edit_response.py @@ -26,44 +26,36 @@ class EmailsProcessed(BaseModel): class DomainEditResponse(BaseModel): - id: int - """The unique identifier for the domain.""" - - allowed_delivery_modes: List[Literal["DIRECT", "BCC", "JOURNAL", "API", "RETRO_SCAN"]] - - created_at: datetime - - domain: str - - drop_dispositions: List[ - Literal[ - "MALICIOUS", - "MALICIOUS-BEC", - "SUSPICIOUS", - "SPOOF", - "SPAM", - "BULK", - "ENCRYPTED", - "EXTERNAL", - "UNKNOWN", - "NONE", - ] - ] - - ip_restrictions: List[str] - - last_modified: datetime - - lookback_hops: int + id: Optional[str] = None + """Domain identifier""" - regions: List[Literal["GLOBAL", "AU", "DE", "IN", "US"]] - - transport: str + allowed_delivery_modes: Optional[List[Literal["DIRECT", "BCC", "JOURNAL", "API", "RETRO_SCAN"]]] = None authorization: Optional[Authorization] = None + created_at: Optional[datetime] = None + dmarc_status: Optional[Literal["none", "good", "invalid"]] = None + domain: Optional[str] = None + + drop_dispositions: Optional[ + List[ + Literal[ + "MALICIOUS", + "MALICIOUS-BEC", + "SUSPICIOUS", + "SPOOF", + "SPAM", + "BULK", + "ENCRYPTED", + "EXTERNAL", + "UNKNOWN", + "NONE", + ] + ] + ] = None + emails_processed: Optional[EmailsProcessed] = None folder: Optional[Literal["AllItems", "Inbox"]] = None @@ -72,10 +64,25 @@ class DomainEditResponse(BaseModel): integration_id: Optional[str] = None + ip_restrictions: Optional[List[str]] = None + + last_modified: Optional[datetime] = None + """Deprecated, use `modified_at` instead. End of life: November 1, 2026.""" + + lookback_hops: Optional[int] = None + + modified_at: Optional[datetime] = None + o365_tenant_id: Optional[str] = None + regions: Optional[List[Literal["GLOBAL", "AU", "DE", "IN", "US"]]] = None + require_tls_inbound: Optional[bool] = None require_tls_outbound: Optional[bool] = None spf_status: Optional[Literal["none", "good", "neutral", "open", "invalid"]] = None + + status: Optional[Literal["pending", "active", "failed", "timeout"]] = None + + transport: Optional[str] = None diff --git a/src/cloudflare/types/email_security/settings/domain_get_response.py b/src/cloudflare/types/email_security/settings/domain_get_response.py index 08557681736..d175d364946 100644 --- a/src/cloudflare/types/email_security/settings/domain_get_response.py +++ b/src/cloudflare/types/email_security/settings/domain_get_response.py @@ -26,44 +26,36 @@ class EmailsProcessed(BaseModel): class DomainGetResponse(BaseModel): - id: int - """The unique identifier for the domain.""" - - allowed_delivery_modes: List[Literal["DIRECT", "BCC", "JOURNAL", "API", "RETRO_SCAN"]] - - created_at: datetime - - domain: str - - drop_dispositions: List[ - Literal[ - "MALICIOUS", - "MALICIOUS-BEC", - "SUSPICIOUS", - "SPOOF", - "SPAM", - "BULK", - "ENCRYPTED", - "EXTERNAL", - "UNKNOWN", - "NONE", - ] - ] - - ip_restrictions: List[str] - - last_modified: datetime - - lookback_hops: int + id: Optional[str] = None + """Domain identifier""" - regions: List[Literal["GLOBAL", "AU", "DE", "IN", "US"]] - - transport: str + allowed_delivery_modes: Optional[List[Literal["DIRECT", "BCC", "JOURNAL", "API", "RETRO_SCAN"]]] = None authorization: Optional[Authorization] = None + created_at: Optional[datetime] = None + dmarc_status: Optional[Literal["none", "good", "invalid"]] = None + domain: Optional[str] = None + + drop_dispositions: Optional[ + List[ + Literal[ + "MALICIOUS", + "MALICIOUS-BEC", + "SUSPICIOUS", + "SPOOF", + "SPAM", + "BULK", + "ENCRYPTED", + "EXTERNAL", + "UNKNOWN", + "NONE", + ] + ] + ] = None + emails_processed: Optional[EmailsProcessed] = None folder: Optional[Literal["AllItems", "Inbox"]] = None @@ -72,10 +64,25 @@ class DomainGetResponse(BaseModel): integration_id: Optional[str] = None + ip_restrictions: Optional[List[str]] = None + + last_modified: Optional[datetime] = None + """Deprecated, use `modified_at` instead. End of life: November 1, 2026.""" + + lookback_hops: Optional[int] = None + + modified_at: Optional[datetime] = None + o365_tenant_id: Optional[str] = None + regions: Optional[List[Literal["GLOBAL", "AU", "DE", "IN", "US"]]] = None + require_tls_inbound: Optional[bool] = None require_tls_outbound: Optional[bool] = None spf_status: Optional[Literal["none", "good", "neutral", "open", "invalid"]] = None + + status: Optional[Literal["pending", "active", "failed", "timeout"]] = None + + transport: Optional[str] = None diff --git a/src/cloudflare/types/email_security/settings/domain_list_params.py b/src/cloudflare/types/email_security/settings/domain_list_params.py index 6546a419a74..cccbbee8649 100644 --- a/src/cloudflare/types/email_security/settings/domain_list_params.py +++ b/src/cloudflare/types/email_security/settings/domain_list_params.py @@ -11,35 +11,34 @@ class DomainListParams(TypedDict, total=False): account_id: Required[str] - """Account Identifier""" + """Identifier.""" active_delivery_mode: Literal["DIRECT", "BCC", "JOURNAL", "API", "RETRO_SCAN"] - """Filters response to domains with the currently active delivery mode.""" + """Currently active delivery mode to filter by.""" allowed_delivery_mode: Literal["DIRECT", "BCC", "JOURNAL", "API", "RETRO_SCAN"] - """Filters response to domains with the provided delivery mode.""" + """Delivery mode to filter by.""" direction: Literal["asc", "desc"] """The sorting direction.""" domain: SequenceNotStr[str] - """Filters results by the provided domains, allowing for multiple occurrences.""" + """Domain names to filter by.""" integration_id: str - """Filters response to domains with the provided integration ID.""" + """Integration ID to filter by.""" order: Literal["domain", "created_at"] - """The field to sort by.""" + """Field to sort by.""" page: int - """The page number of paginated results.""" + """Current page within paginated list of results.""" per_page: int - """The number of results per page.""" + """The number of results per page. Maximum value is 1000.""" search: str - """ - Allows searching in multiple properties of a record simultaneously. This - parameter is intended for human users, not automation. Its exact behavior is - intentionally left unspecified and is subject to change in the future. - """ + """Search term for filtering records. Behavior may change.""" + + status: Literal["pending", "active", "failed", "timeout"] + """Filters response to domains with the provided status.""" diff --git a/src/cloudflare/types/email_security/settings/domain_list_response.py b/src/cloudflare/types/email_security/settings/domain_list_response.py index eec5a9fcc9c..cca762dcd41 100644 --- a/src/cloudflare/types/email_security/settings/domain_list_response.py +++ b/src/cloudflare/types/email_security/settings/domain_list_response.py @@ -26,44 +26,36 @@ class EmailsProcessed(BaseModel): class DomainListResponse(BaseModel): - id: int - """The unique identifier for the domain.""" - - allowed_delivery_modes: List[Literal["DIRECT", "BCC", "JOURNAL", "API", "RETRO_SCAN"]] - - created_at: datetime - - domain: str - - drop_dispositions: List[ - Literal[ - "MALICIOUS", - "MALICIOUS-BEC", - "SUSPICIOUS", - "SPOOF", - "SPAM", - "BULK", - "ENCRYPTED", - "EXTERNAL", - "UNKNOWN", - "NONE", - ] - ] - - ip_restrictions: List[str] - - last_modified: datetime - - lookback_hops: int + id: Optional[str] = None + """Domain identifier""" - regions: List[Literal["GLOBAL", "AU", "DE", "IN", "US"]] - - transport: str + allowed_delivery_modes: Optional[List[Literal["DIRECT", "BCC", "JOURNAL", "API", "RETRO_SCAN"]]] = None authorization: Optional[Authorization] = None + created_at: Optional[datetime] = None + dmarc_status: Optional[Literal["none", "good", "invalid"]] = None + domain: Optional[str] = None + + drop_dispositions: Optional[ + List[ + Literal[ + "MALICIOUS", + "MALICIOUS-BEC", + "SUSPICIOUS", + "SPOOF", + "SPAM", + "BULK", + "ENCRYPTED", + "EXTERNAL", + "UNKNOWN", + "NONE", + ] + ] + ] = None + emails_processed: Optional[EmailsProcessed] = None folder: Optional[Literal["AllItems", "Inbox"]] = None @@ -72,10 +64,25 @@ class DomainListResponse(BaseModel): integration_id: Optional[str] = None + ip_restrictions: Optional[List[str]] = None + + last_modified: Optional[datetime] = None + """Deprecated, use `modified_at` instead. End of life: November 1, 2026.""" + + lookback_hops: Optional[int] = None + + modified_at: Optional[datetime] = None + o365_tenant_id: Optional[str] = None + regions: Optional[List[Literal["GLOBAL", "AU", "DE", "IN", "US"]]] = None + require_tls_inbound: Optional[bool] = None require_tls_outbound: Optional[bool] = None spf_status: Optional[Literal["none", "good", "neutral", "open", "invalid"]] = None + + status: Optional[Literal["pending", "active", "failed", "timeout"]] = None + + transport: Optional[str] = None diff --git a/src/cloudflare/types/email_security/settings/impersonation_registry_create_params.py b/src/cloudflare/types/email_security/settings/impersonation_registry_create_params.py index db25db7e746..a2e4c838eac 100644 --- a/src/cloudflare/types/email_security/settings/impersonation_registry_create_params.py +++ b/src/cloudflare/types/email_security/settings/impersonation_registry_create_params.py @@ -2,17 +2,28 @@ from __future__ import annotations -from typing_extensions import Required, TypedDict +from typing import Optional +from typing_extensions import Literal, Required, TypedDict __all__ = ["ImpersonationRegistryCreateParams"] class ImpersonationRegistryCreateParams(TypedDict, total=False): account_id: Required[str] - """Account Identifier""" + """Identifier.""" email: Required[str] is_email_regex: Required[bool] name: Required[str] + + comments: Optional[str] + + directory_id: Optional[int] + + directory_node_id: Optional[int] + + external_directory_node_id: Optional[str] + + provenance: Literal["A1S_INTERNAL", "SNOOPY-CASB_OFFICE_365", "SNOOPY-OFFICE_365", "SNOOPY-GOOGLE_DIRECTORY"] diff --git a/src/cloudflare/types/email_security/settings/impersonation_registry_create_response.py b/src/cloudflare/types/email_security/settings/impersonation_registry_create_response.py index c0dd1f55354..e34f1dab28b 100644 --- a/src/cloudflare/types/email_security/settings/impersonation_registry_create_response.py +++ b/src/cloudflare/types/email_security/settings/impersonation_registry_create_response.py @@ -2,6 +2,7 @@ from typing import Optional from datetime import datetime +from typing_extensions import Literal from ...._models import BaseModel @@ -9,24 +10,32 @@ class ImpersonationRegistryCreateResponse(BaseModel): - id: int + """An impersonation registry entry""" - created_at: datetime - - email: str - - is_email_regex: bool - - last_modified: datetime - - name: str + id: Optional[str] = None + """Impersonation registry entry identifier""" comments: Optional[str] = None + created_at: Optional[datetime] = None + directory_id: Optional[int] = None directory_node_id: Optional[int] = None + email: Optional[str] = None + external_directory_node_id: Optional[str] = None - provenance: Optional[str] = None + is_email_regex: Optional[bool] = None + + last_modified: Optional[datetime] = None + """Deprecated, use `modified_at` instead. End of life: November 1, 2026.""" + + modified_at: Optional[datetime] = None + + name: Optional[str] = None + + provenance: Optional[ + Literal["A1S_INTERNAL", "SNOOPY-CASB_OFFICE_365", "SNOOPY-OFFICE_365", "SNOOPY-GOOGLE_DIRECTORY"] + ] = None diff --git a/src/cloudflare/types/email_security/settings/impersonation_registry_delete_response.py b/src/cloudflare/types/email_security/settings/impersonation_registry_delete_response.py deleted file mode 100644 index ba4913c92f1..00000000000 --- a/src/cloudflare/types/email_security/settings/impersonation_registry_delete_response.py +++ /dev/null @@ -1,9 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ...._models import BaseModel - -__all__ = ["ImpersonationRegistryDeleteResponse"] - - -class ImpersonationRegistryDeleteResponse(BaseModel): - id: int diff --git a/src/cloudflare/types/email_security/settings/impersonation_registry_edit_params.py b/src/cloudflare/types/email_security/settings/impersonation_registry_edit_params.py deleted file mode 100644 index 8dceb0e75f7..00000000000 --- a/src/cloudflare/types/email_security/settings/impersonation_registry_edit_params.py +++ /dev/null @@ -1,19 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Required, TypedDict - -__all__ = ["ImpersonationRegistryEditParams"] - - -class ImpersonationRegistryEditParams(TypedDict, total=False): - account_id: Required[str] - """Account Identifier""" - - email: Optional[str] - - is_email_regex: Optional[bool] - - name: Optional[str] diff --git a/src/cloudflare/types/email_security/settings/impersonation_registry_edit_response.py b/src/cloudflare/types/email_security/settings/impersonation_registry_edit_response.py deleted file mode 100644 index 824a0946f7c..00000000000 --- a/src/cloudflare/types/email_security/settings/impersonation_registry_edit_response.py +++ /dev/null @@ -1,32 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from datetime import datetime - -from ...._models import BaseModel - -__all__ = ["ImpersonationRegistryEditResponse"] - - -class ImpersonationRegistryEditResponse(BaseModel): - id: int - - created_at: datetime - - email: str - - is_email_regex: bool - - last_modified: datetime - - name: str - - comments: Optional[str] = None - - directory_id: Optional[int] = None - - directory_node_id: Optional[int] = None - - external_directory_node_id: Optional[str] = None - - provenance: Optional[str] = None diff --git a/src/cloudflare/types/email_security/settings/impersonation_registry_get_response.py b/src/cloudflare/types/email_security/settings/impersonation_registry_get_response.py deleted file mode 100644 index 85a8ab50d71..00000000000 --- a/src/cloudflare/types/email_security/settings/impersonation_registry_get_response.py +++ /dev/null @@ -1,32 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from datetime import datetime - -from ...._models import BaseModel - -__all__ = ["ImpersonationRegistryGetResponse"] - - -class ImpersonationRegistryGetResponse(BaseModel): - id: int - - created_at: datetime - - email: str - - is_email_regex: bool - - last_modified: datetime - - name: str - - comments: Optional[str] = None - - directory_id: Optional[int] = None - - directory_node_id: Optional[int] = None - - external_directory_node_id: Optional[str] = None - - provenance: Optional[str] = None diff --git a/src/cloudflare/types/email_security/settings/impersonation_registry_list_params.py b/src/cloudflare/types/email_security/settings/impersonation_registry_list_params.py index 49a2b1ddf0a..d652f6012b8 100644 --- a/src/cloudflare/types/email_security/settings/impersonation_registry_list_params.py +++ b/src/cloudflare/types/email_security/settings/impersonation_registry_list_params.py @@ -9,25 +9,21 @@ class ImpersonationRegistryListParams(TypedDict, total=False): account_id: Required[str] - """Account Identifier""" + """Identifier.""" direction: Literal["asc", "desc"] """The sorting direction.""" order: Literal["name", "email", "created_at"] - """The field to sort by.""" + """Field to sort by.""" page: int - """The page number of paginated results.""" + """Current page within paginated list of results.""" per_page: int - """The number of results per page.""" + """The number of results per page. Maximum value is 1000.""" provenance: Literal["A1S_INTERNAL", "SNOOPY-CASB_OFFICE_365", "SNOOPY-OFFICE_365", "SNOOPY-GOOGLE_DIRECTORY"] search: str - """ - Allows searching in multiple properties of a record simultaneously. This - parameter is intended for human users, not automation. Its exact behavior is - intentionally left unspecified and is subject to change in the future. - """ + """Search term for filtering records. Behavior may change.""" diff --git a/src/cloudflare/types/email_security/settings/impersonation_registry_list_response.py b/src/cloudflare/types/email_security/settings/impersonation_registry_list_response.py index 800c8d4bfd7..17299856d1a 100644 --- a/src/cloudflare/types/email_security/settings/impersonation_registry_list_response.py +++ b/src/cloudflare/types/email_security/settings/impersonation_registry_list_response.py @@ -2,6 +2,7 @@ from typing import Optional from datetime import datetime +from typing_extensions import Literal from ...._models import BaseModel @@ -9,24 +10,32 @@ class ImpersonationRegistryListResponse(BaseModel): - id: int + """An impersonation registry entry""" - created_at: datetime - - email: str - - is_email_regex: bool - - last_modified: datetime - - name: str + id: Optional[str] = None + """Impersonation registry entry identifier""" comments: Optional[str] = None + created_at: Optional[datetime] = None + directory_id: Optional[int] = None directory_node_id: Optional[int] = None + email: Optional[str] = None + external_directory_node_id: Optional[str] = None - provenance: Optional[str] = None + is_email_regex: Optional[bool] = None + + last_modified: Optional[datetime] = None + """Deprecated, use `modified_at` instead. End of life: November 1, 2026.""" + + modified_at: Optional[datetime] = None + + name: Optional[str] = None + + provenance: Optional[ + Literal["A1S_INTERNAL", "SNOOPY-CASB_OFFICE_365", "SNOOPY-OFFICE_365", "SNOOPY-GOOGLE_DIRECTORY"] + ] = None diff --git a/src/cloudflare/types/email_security/settings/trusted_domain_create_params.py b/src/cloudflare/types/email_security/settings/trusted_domain_create_params.py index 3159478e22d..0ea1e50ccd5 100644 --- a/src/cloudflare/types/email_security/settings/trusted_domain_create_params.py +++ b/src/cloudflare/types/email_security/settings/trusted_domain_create_params.py @@ -2,15 +2,15 @@ from __future__ import annotations -from typing import Union, Iterable, Optional -from typing_extensions import Required, TypeAlias, TypedDict +from typing import Optional +from typing_extensions import Required, TypedDict -__all__ = ["TrustedDomainCreateParams", "EmailSecurityCreateTrustedDomain", "Variant1", "Variant1Body"] +__all__ = ["TrustedDomainCreateParams"] -class EmailSecurityCreateTrustedDomain(TypedDict, total=False): +class TrustedDomainCreateParams(TypedDict, total=False): account_id: Required[str] - """Account Identifier""" + """Identifier.""" is_recent: Required[bool] """ @@ -29,33 +29,3 @@ class EmailSecurityCreateTrustedDomain(TypedDict, total=False): pattern: Required[str] comments: Optional[str] - - -class Variant1(TypedDict, total=False): - account_id: Required[str] - """Account Identifier""" - - body: Required[Iterable[Variant1Body]] - - -class Variant1Body(TypedDict, total=False): - is_recent: Required[bool] - """ - Select to prevent recently registered domains from triggering a Suspicious or - Malicious disposition. - """ - - is_regex: Required[bool] - - is_similarity: Required[bool] - """ - Select for partner or other approved domains that have similar spelling to your - connected domains. Prevents listed domains from triggering a Spoof disposition. - """ - - pattern: Required[str] - - comments: Optional[str] - - -TrustedDomainCreateParams: TypeAlias = Union[EmailSecurityCreateTrustedDomain, Variant1] diff --git a/src/cloudflare/types/email_security/settings/trusted_domain_create_response.py b/src/cloudflare/types/email_security/settings/trusted_domain_create_response.py index 1dfe56cf075..33b7cc18fdf 100644 --- a/src/cloudflare/types/email_security/settings/trusted_domain_create_response.py +++ b/src/cloudflare/types/email_security/settings/trusted_domain_create_response.py @@ -1,66 +1,40 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union, Optional +from typing import Optional from datetime import datetime -from typing_extensions import TypeAlias from ...._models import BaseModel -__all__ = ["TrustedDomainCreateResponse", "EmailSecurityTrustedDomain", "UnionMember1"] +__all__ = ["TrustedDomainCreateResponse"] -class EmailSecurityTrustedDomain(BaseModel): - id: int - """The unique identifier for the trusted domain.""" +class TrustedDomainCreateResponse(BaseModel): + """A trusted email domain""" - created_at: datetime - - is_recent: bool - """ - Select to prevent recently registered domains from triggering a Suspicious or - Malicious disposition. - """ - - is_regex: bool - - is_similarity: bool - """ - Select for partner or other approved domains that have similar spelling to your - connected domains. Prevents listed domains from triggering a Spoof disposition. - """ - - last_modified: datetime - - pattern: str + id: Optional[str] = None + """Trusted domain identifier""" comments: Optional[str] = None + created_at: Optional[datetime] = None -class UnionMember1(BaseModel): - id: int - """The unique identifier for the trusted domain.""" - - created_at: datetime - - is_recent: bool + is_recent: Optional[bool] = None """ Select to prevent recently registered domains from triggering a Suspicious or Malicious disposition. """ - is_regex: bool + is_regex: Optional[bool] = None - is_similarity: bool + is_similarity: Optional[bool] = None """ Select for partner or other approved domains that have similar spelling to your connected domains. Prevents listed domains from triggering a Spoof disposition. """ - last_modified: datetime - - pattern: str - - comments: Optional[str] = None + last_modified: Optional[datetime] = None + """Deprecated, use `modified_at` instead. End of life: November 1, 2026.""" + modified_at: Optional[datetime] = None -TrustedDomainCreateResponse: TypeAlias = Union[EmailSecurityTrustedDomain, List[UnionMember1]] + pattern: Optional[str] = None diff --git a/src/cloudflare/types/email_security/settings/trusted_domain_delete_response.py b/src/cloudflare/types/email_security/settings/trusted_domain_delete_response.py index 9c5251946fd..ca3b3afd980 100644 --- a/src/cloudflare/types/email_security/settings/trusted_domain_delete_response.py +++ b/src/cloudflare/types/email_security/settings/trusted_domain_delete_response.py @@ -6,5 +6,5 @@ class TrustedDomainDeleteResponse(BaseModel): - id: int - """The unique identifier for the trusted domain.""" + id: str + """Trusted domain identifier""" diff --git a/src/cloudflare/types/email_security/settings/trusted_domain_edit_params.py b/src/cloudflare/types/email_security/settings/trusted_domain_edit_params.py index 90d1acfc7c0..a96de6dc005 100644 --- a/src/cloudflare/types/email_security/settings/trusted_domain_edit_params.py +++ b/src/cloudflare/types/email_security/settings/trusted_domain_edit_params.py @@ -2,6 +2,7 @@ from __future__ import annotations +from typing import Optional from typing_extensions import Required, TypedDict __all__ = ["TrustedDomainEditParams"] @@ -9,9 +10,9 @@ class TrustedDomainEditParams(TypedDict, total=False): account_id: Required[str] - """Account Identifier""" + """Identifier.""" - comments: str + comments: Optional[str] is_recent: bool """ diff --git a/src/cloudflare/types/email_security/settings/trusted_domain_edit_response.py b/src/cloudflare/types/email_security/settings/trusted_domain_edit_response.py index eb86a0bfebc..2e3b8aa0427 100644 --- a/src/cloudflare/types/email_security/settings/trusted_domain_edit_response.py +++ b/src/cloudflare/types/email_security/settings/trusted_domain_edit_response.py @@ -9,27 +9,32 @@ class TrustedDomainEditResponse(BaseModel): - id: int - """The unique identifier for the trusted domain.""" + """A trusted email domain""" - created_at: datetime + id: Optional[str] = None + """Trusted domain identifier""" - is_recent: bool + comments: Optional[str] = None + + created_at: Optional[datetime] = None + + is_recent: Optional[bool] = None """ Select to prevent recently registered domains from triggering a Suspicious or Malicious disposition. """ - is_regex: bool + is_regex: Optional[bool] = None - is_similarity: bool + is_similarity: Optional[bool] = None """ Select for partner or other approved domains that have similar spelling to your connected domains. Prevents listed domains from triggering a Spoof disposition. """ - last_modified: datetime + last_modified: Optional[datetime] = None + """Deprecated, use `modified_at` instead. End of life: November 1, 2026.""" - pattern: str + modified_at: Optional[datetime] = None - comments: Optional[str] = None + pattern: Optional[str] = None diff --git a/src/cloudflare/types/email_security/settings/trusted_domain_get_response.py b/src/cloudflare/types/email_security/settings/trusted_domain_get_response.py index 23b217fa8d7..dc31ef66b43 100644 --- a/src/cloudflare/types/email_security/settings/trusted_domain_get_response.py +++ b/src/cloudflare/types/email_security/settings/trusted_domain_get_response.py @@ -9,27 +9,32 @@ class TrustedDomainGetResponse(BaseModel): - id: int - """The unique identifier for the trusted domain.""" + """A trusted email domain""" - created_at: datetime + id: Optional[str] = None + """Trusted domain identifier""" - is_recent: bool + comments: Optional[str] = None + + created_at: Optional[datetime] = None + + is_recent: Optional[bool] = None """ Select to prevent recently registered domains from triggering a Suspicious or Malicious disposition. """ - is_regex: bool + is_regex: Optional[bool] = None - is_similarity: bool + is_similarity: Optional[bool] = None """ Select for partner or other approved domains that have similar spelling to your connected domains. Prevents listed domains from triggering a Spoof disposition. """ - last_modified: datetime + last_modified: Optional[datetime] = None + """Deprecated, use `modified_at` instead. End of life: November 1, 2026.""" - pattern: str + modified_at: Optional[datetime] = None - comments: Optional[str] = None + pattern: Optional[str] = None diff --git a/src/cloudflare/types/email_security/settings/trusted_domain_list_params.py b/src/cloudflare/types/email_security/settings/trusted_domain_list_params.py index b9446971853..5036cc37986 100644 --- a/src/cloudflare/types/email_security/settings/trusted_domain_list_params.py +++ b/src/cloudflare/types/email_security/settings/trusted_domain_list_params.py @@ -9,29 +9,33 @@ class TrustedDomainListParams(TypedDict, total=False): account_id: Required[str] - """Account Identifier""" + """Identifier.""" direction: Literal["asc", "desc"] """The sorting direction.""" is_recent: bool + """ + Filter to show only recently registered domains that are trusted to prevent + triggering Suspicious or Malicious dispositions. + """ is_similarity: bool + """ + Filter to show only proximity domains (partner or approved domains with similar + spelling to connected domains) that prevent Spoof dispositions. + """ order: Literal["pattern", "created_at"] - """The field to sort by.""" + """Field to sort by.""" page: int - """The page number of paginated results.""" + """Current page within paginated list of results.""" pattern: str per_page: int - """The number of results per page.""" + """The number of results per page. Maximum value is 1000.""" search: str - """ - Allows searching in multiple properties of a record simultaneously. This - parameter is intended for human users, not automation. Its exact behavior is - intentionally left unspecified and is subject to change in the future. - """ + """Search term for filtering records. Behavior may change.""" diff --git a/src/cloudflare/types/email_security/settings/trusted_domain_list_response.py b/src/cloudflare/types/email_security/settings/trusted_domain_list_response.py index 42e7eec4fed..c7643df7860 100644 --- a/src/cloudflare/types/email_security/settings/trusted_domain_list_response.py +++ b/src/cloudflare/types/email_security/settings/trusted_domain_list_response.py @@ -9,27 +9,32 @@ class TrustedDomainListResponse(BaseModel): - id: int - """The unique identifier for the trusted domain.""" + """A trusted email domain""" - created_at: datetime + id: Optional[str] = None + """Trusted domain identifier""" - is_recent: bool + comments: Optional[str] = None + + created_at: Optional[datetime] = None + + is_recent: Optional[bool] = None """ Select to prevent recently registered domains from triggering a Suspicious or Malicious disposition. """ - is_regex: bool + is_regex: Optional[bool] = None - is_similarity: bool + is_similarity: Optional[bool] = None """ Select for partner or other approved domains that have similar spelling to your connected domains. Prevents listed domains from triggering a Spoof disposition. """ - last_modified: datetime + last_modified: Optional[datetime] = None + """Deprecated, use `modified_at` instead. End of life: November 1, 2026.""" - pattern: str + modified_at: Optional[datetime] = None - comments: Optional[str] = None + pattern: Optional[str] = None diff --git a/src/cloudflare/types/email_security/submission_list_params.py b/src/cloudflare/types/email_security/submission_list_params.py index 225fb097290..b333cbd18b4 100644 --- a/src/cloudflare/types/email_security/submission_list_params.py +++ b/src/cloudflare/types/email_security/submission_list_params.py @@ -13,32 +13,27 @@ class SubmissionListParams(TypedDict, total=False): account_id: Required[str] - """Account Identifier""" - - customer_status: Literal["escalated", "reviewed", "unreviewed"] + """Identifier.""" end: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """The end of the search date range. Defaults to `now` if not provided.""" + """The end of the search date range. Defaults to `now`.""" original_disposition: Literal["MALICIOUS", "SUSPICIOUS", "SPOOF", "SPAM", "BULK", "NONE"] outcome_disposition: Literal["MALICIOUS", "SUSPICIOUS", "SPOOF", "SPAM", "BULK", "NONE"] page: int - """The page number of paginated results.""" + """Current page within paginated list of results.""" per_page: int - """The number of results per page.""" + """The number of results per page. Maximum value is 1000.""" query: Optional[str] requested_disposition: Literal["MALICIOUS", "SUSPICIOUS", "SPOOF", "SPAM", "BULK", "NONE"] start: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """ - The beginning of the search date range. Defaults to `now - 30 days` if not - provided. - """ + """The beginning of the search date range. Defaults to `now - 30 days`.""" status: str diff --git a/src/cloudflare/types/email_security/submission_list_response.py b/src/cloudflare/types/email_security/submission_list_response.py index 6e48024d27d..d3b3f17014f 100644 --- a/src/cloudflare/types/email_security/submission_list_response.py +++ b/src/cloudflare/types/email_security/submission_list_response.py @@ -10,27 +10,14 @@ class SubmissionListResponse(BaseModel): - requested_ts: datetime - """deprecated as of 2026-04-01, use `requested_at` instead.""" + requested_at: datetime + """When the submission was requested (UTC).""" submission_id: str customer_status: Optional[Literal["escalated", "reviewed", "unreviewed"]] = None - escalated_as: Optional[ - Literal[ - "MALICIOUS", - "MALICIOUS-BEC", - "SUSPICIOUS", - "SPOOF", - "SPAM", - "BULK", - "ENCRYPTED", - "EXTERNAL", - "UNKNOWN", - "NONE", - ] - ] = None + escalated_as: Optional[Literal["MALICIOUS", "SUSPICIOUS", "SPOOF", "SPAM", "BULK", "NONE"]] = None escalated_at: Optional[datetime] = None @@ -38,63 +25,27 @@ class SubmissionListResponse(BaseModel): escalated_submission_id: Optional[str] = None - original_disposition: Optional[ - Literal[ - "MALICIOUS", - "MALICIOUS-BEC", - "SUSPICIOUS", - "SPOOF", - "SPAM", - "BULK", - "ENCRYPTED", - "EXTERNAL", - "UNKNOWN", - "NONE", - ] - ] = None + original_disposition: Optional[Literal["MALICIOUS", "SUSPICIOUS", "SPOOF", "SPAM", "BULK", "NONE"]] = None original_edf_hash: Optional[str] = None original_postfix_id: Optional[str] = None + """The postfix ID of the original message that was submitted""" outcome: Optional[str] = None - outcome_disposition: Optional[ - Literal[ - "MALICIOUS", - "MALICIOUS-BEC", - "SUSPICIOUS", - "SPOOF", - "SPAM", - "BULK", - "ENCRYPTED", - "EXTERNAL", - "UNKNOWN", - "NONE", - ] - ] = None - - requested_at: Optional[datetime] = None + outcome_disposition: Optional[Literal["MALICIOUS", "SUSPICIOUS", "SPOOF", "SPAM", "BULK", "NONE"]] = None requested_by: Optional[str] = None - requested_disposition: Optional[ - Literal[ - "MALICIOUS", - "MALICIOUS-BEC", - "SUSPICIOUS", - "SPOOF", - "SPAM", - "BULK", - "ENCRYPTED", - "EXTERNAL", - "UNKNOWN", - "NONE", - ] - ] = None + requested_disposition: Optional[Literal["MALICIOUS", "SUSPICIOUS", "SPOOF", "SPAM", "BULK", "NONE"]] = None + + requested_ts: Optional[str] = None + """Deprecated, use `requested_at` instead""" status: Optional[str] = None subject: Optional[str] = None - type: Optional[str] = None + type: Optional[Literal["Team", "User"]] = None + """Whether the submission was created by a team member or an end user.""" diff --git a/src/cloudflare/types/r2/buckets/domains/custom_create_response.py b/src/cloudflare/types/r2/buckets/domains/custom_create_response.py index 88a05be4d0e..9fc563d3f10 100644 --- a/src/cloudflare/types/r2/buckets/domains/custom_create_response.py +++ b/src/cloudflare/types/r2/buckets/domains/custom_create_response.py @@ -17,6 +17,9 @@ class CustomCreateResponse(BaseModel): enabled: bool """Whether this bucket is publicly accessible at the specified custom domain.""" + zone_id: str = FieldInfo(alias="zoneId") + """Zone ID of the custom domain.""" + ciphers: Optional[List[str]] = None """An allowlist of ciphers for TLS termination. diff --git a/src/cloudflare/types/workers/beta/workers/version.py b/src/cloudflare/types/workers/beta/workers/version.py index 708a27dd244..4aaab999555 100644 --- a/src/cloudflare/types/workers/beta/workers/version.py +++ b/src/cloudflare/types/workers/beta/workers/version.py @@ -424,6 +424,13 @@ class BindingWorkersBindingKindRatelimitSimple(BaseModel): period: int """The period in seconds.""" + mitigation_timeout: Optional[int] = None + """ + Duration in seconds to apply the mitigation action after the rate limit is + exceeded. Valid values are 0 (disabled), 10, or multiples of 60 up to 86400. + Must be greater than or equal to the period when non-zero. + """ + class BindingWorkersBindingKindRatelimit(BaseModel): name: str diff --git a/src/cloudflare/types/workers/beta/workers/version_create_params.py b/src/cloudflare/types/workers/beta/workers/version_create_params.py index 9f4b87ffba3..0267fb27bc0 100644 --- a/src/cloudflare/types/workers/beta/workers/version_create_params.py +++ b/src/cloudflare/types/workers/beta/workers/version_create_params.py @@ -509,6 +509,13 @@ class BindingWorkersBindingKindRatelimitSimple(TypedDict, total=False): period: Required[int] """The period in seconds.""" + mitigation_timeout: int + """ + Duration in seconds to apply the mitigation action after the rate limit is + exceeded. Valid values are 0 (disabled), 10, or multiples of 60 up to 86400. + Must be greater than or equal to the period when non-zero. + """ + class BindingWorkersBindingKindRatelimit(TypedDict, total=False): name: Required[str] diff --git a/src/cloudflare/types/workers/observability/telemetry_keys_params.py b/src/cloudflare/types/workers/observability/telemetry_keys_params.py index 275b94b0c97..0f9c75cd0e3 100644 --- a/src/cloudflare/types/workers/observability/telemetry_keys_params.py +++ b/src/cloudflare/types/workers/observability/telemetry_keys_params.py @@ -12,6 +12,9 @@ "TelemetryKeysParams", "Filter", "FilterUnionMember0", + "FilterUnionMember0Filter", + "FilterUnionMember0FilterUnionMember0", + "FilterUnionMember0FilterWorkersObservabilityFilterLeaf", "FilterWorkersObservabilityFilterLeaf", "KeyNeedle", "Needle", @@ -50,7 +53,7 @@ class TelemetryKeysParams(TypedDict, total=False): to: float -class FilterUnionMember0(TypedDict, total=False): +class FilterUnionMember0FilterUnionMember0(TypedDict, total=False): filter_combination: Required[Annotated[Literal["and", "or", "AND", "OR"], PropertyInfo(alias="filterCombination")]] filters: Required[Iterable[object]] @@ -58,17 +61,106 @@ class FilterUnionMember0(TypedDict, total=False): kind: Required[Literal["group"]] -class FilterWorkersObservabilityFilterLeaf(TypedDict, total=False): +class FilterUnionMember0FilterWorkersObservabilityFilterLeaf(TypedDict, total=False): + """A filter condition applied to query results. + + Use the keys and values endpoints to discover available fields and their values before constructing filters. """ - Filtering best practices: use observability_keys and observability_values to confirm available fields and values. If searching for errors, filter for $metadata.error exists. + + key: Required[str] + """Filter field name. + + Use verified keys from previous query results or the keys endpoint. Common keys + include $metadata.service, $metadata.origin, $metadata.trigger, + $metadata.message, and $metadata.error. + """ + + operation: Required[ + Literal[ + "includes", + "not_includes", + "starts_with", + "regex", + "exists", + "is_null", + "in", + "not_in", + "eq", + "neq", + "gt", + "gte", + "lt", + "lte", + "=", + "!=", + ">", + ">=", + "<", + "<=", + "INCLUDES", + "DOES_NOT_INCLUDE", + "MATCH_REGEX", + "EXISTS", + "DOES_NOT_EXIST", + "IN", + "NOT_IN", + "STARTS_WITH", + ] + ] + """Comparison operator. + + String operators: includes, not_includes, starts_with, regex. Existence: exists, + is_null. Set membership: in, not_in (comma-separated values). Numeric: eq, neq, + gt, gte, lt, lte. + """ + + type: Required[Literal["string", "number", "boolean"]] + """Data type of the filter field. + + Must match the actual type of the key being filtered. + """ + + kind: Literal["filter"] + """Discriminator for leaf filter nodes. + + Always 'filter' when present; may be omitted. + """ + + value: Union[str, float, bool] + """Comparison value. + + Must match actual values in your data — verify with the values endpoint. Ensure + the value type (string/number/boolean) matches the field type. String + comparisons are case-sensitive. Regex uses RE2 syntax (no + lookaheads/lookbehinds). + """ + + +FilterUnionMember0Filter: TypeAlias = Union[ + FilterUnionMember0FilterUnionMember0, FilterUnionMember0FilterWorkersObservabilityFilterLeaf +] + + +class FilterUnionMember0(TypedDict, total=False): + filter_combination: Required[Annotated[Literal["and", "or", "AND", "OR"], PropertyInfo(alias="filterCombination")]] + + filters: Required[Iterable[FilterUnionMember0Filter]] + + kind: Required[Literal["group"]] + + +class FilterWorkersObservabilityFilterLeaf(TypedDict, total=False): + """A filter condition applied to query results. + + Use the keys and values endpoints to discover available fields and their values before constructing filters. """ key: Required[str] """Filter field name. - IMPORTANT: do not guess keys. Always use verified keys from previous query - results or the observability_keys response. Preferred keys: $metadata.service, - $metadata.origin, $metadata.trigger, $metadata.message, $metadata.error. + Use verified keys from previous query results or the keys endpoint. Common keys + include $metadata.service, $metadata.origin, $metadata.trigger, + $metadata.message, and $metadata.error. """ operation: Required[ @@ -103,19 +195,32 @@ class FilterWorkersObservabilityFilterLeaf(TypedDict, total=False): "STARTS_WITH", ] ] + """Comparison operator. + + String operators: includes, not_includes, starts_with, regex. Existence: exists, + is_null. Set membership: in, not_in (comma-separated values). Numeric: eq, neq, + gt, gte, lt, lte. + """ type: Required[Literal["string", "number", "boolean"]] + """Data type of the filter field. + + Must match the actual type of the key being filtered. + """ kind: Literal["filter"] + """Discriminator for leaf filter nodes. + + Always 'filter' when present; may be omitted. + """ value: Union[str, float, bool] - """Filter comparison value. + """Comparison value. - IMPORTANT: must match actual values in your logs. Verify using previous query - results or the /values endpoint. Ensure value type matches the field type. - String comparisons are case-sensitive unless using specific operations. Regex - uses ClickHouse RE2 syntax (no lookaheads/lookbehinds); examples: ^5\\dd{2}$ for - HTTP 5xx, \bERROR\b for word boundary. + Must match actual values in your data — verify with the values endpoint. Ensure + the value type (string/number/boolean) matches the field type. String + comparisons are case-sensitive. Regex uses RE2 syntax (no + lookaheads/lookbehinds). """ @@ -129,17 +234,23 @@ class KeyNeedle(TypedDict, total=False): """ value: Required[Union[str, float, bool]] + """The text or pattern to search for.""" is_regex: Annotated[bool, PropertyInfo(alias="isRegex")] + """When true, treats the value as a regular expression (RE2 syntax).""" match_case: Annotated[bool, PropertyInfo(alias="matchCase")] + """When true, performs a case-sensitive search. Defaults to case-insensitive.""" class Needle(TypedDict, total=False): """Search for a specific substring in any of the events""" value: Required[Union[str, float, bool]] + """The text or pattern to search for.""" is_regex: Annotated[bool, PropertyInfo(alias="isRegex")] + """When true, treats the value as a regular expression (RE2 syntax).""" match_case: Annotated[bool, PropertyInfo(alias="matchCase")] + """When true, performs a case-sensitive search. Defaults to case-insensitive.""" diff --git a/src/cloudflare/types/workers/observability/telemetry_query_params.py b/src/cloudflare/types/workers/observability/telemetry_query_params.py index 6430ea3f9fb..c328f89aad2 100644 --- a/src/cloudflare/types/workers/observability/telemetry_query_params.py +++ b/src/cloudflare/types/workers/observability/telemetry_query_params.py @@ -15,6 +15,9 @@ "ParametersCalculation", "ParametersFilter", "ParametersFilterUnionMember0", + "ParametersFilterUnionMember0Filter", + "ParametersFilterUnionMember0FilterUnionMember0", + "ParametersFilterUnionMember0FilterWorkersObservabilityFilterLeaf", "ParametersFilterWorkersObservabilityFilterLeaf", "ParametersGroupBy", "ParametersHaving", @@ -27,66 +30,83 @@ class TelemetryQueryParams(TypedDict, total=False): account_id: Required[str] query_id: Required[Annotated[str, PropertyInfo(alias="queryId")]] - """Unique identifier for the query to execute""" + """Identifier for the query. + + When parameters are omitted, this ID is used to load a previously saved query's + parameters. When providing parameters inline, pass any identifier (e.g. an + ad-hoc ID). + """ timeframe: Required[Timeframe] - """Timeframe for your query using Unix timestamps in milliseconds. + """Timeframe for the query using Unix timestamps in milliseconds. - Provide from/to epoch ms; narrower timeframes provide faster responses and more - specific results. + Narrower timeframes produce faster responses and more specific results. """ chart: bool - """Whether to include timeseties data in the response""" + """When true, includes time-series data in the response.""" compare: bool - """Whether to include comparison data with previous time periods""" + """ + When true, includes a comparison dataset from the previous time period of equal + length. + """ dry: bool - """Whether to perform a dry run without saving the results of the query. + """When true, executes the query without persisting the results. - Useful for validation + Useful for validation or previewing. """ granularity: float - """This is only used when the view is calculations. + """Number of time-series buckets. - Leaving it empty lets Workers Observability detect the correct granularity. + Only used when view is 'calculations'. Omit to let the system auto-detect an + appropriate granularity. """ ignore_series: Annotated[bool, PropertyInfo(alias="ignoreSeries")] """ - Whether to ignore time-series data in the results and return only aggregated - values + When true, omits time-series data from the response and returns only aggregated + values. Reduces response size when series are not needed. """ limit: float - """Use this limit to cap the number of events returned when the view is events.""" + """Maximum number of events to return when view is 'events'. + + Also controls the number of group-by rows when view is 'calculations'. + """ offset: str - """Cursor pagination for event/trace/invocation views. + """Cursor for pagination in event, trace, and invocation views. - Pass the last item's $metadata.id as the next offset. + Pass the $metadata.id of the last returned item to fetch the next page. """ offset_by: Annotated[float, PropertyInfo(alias="offsetBy")] - """Numeric offset for pattern results (top-N list). + """Numeric offset for paginating grouped/pattern results (top-N lists). - Use with limit to page pattern groups; not used by cursor pagination. + Use together with limit. Not used by cursor-based pagination. """ offset_direction: Annotated[str, PropertyInfo(alias="offsetDirection")] - """Direction for offset-based pagination (e.g., 'next', 'prev')""" + """Pagination direction: 'next' for forward, 'prev' for backward.""" parameters: Parameters - """Optional parameters to pass to the query execution""" + """ + Query parameters defining what data to retrieve — filters, calculations, + group-bys, and ordering. In practice this should always be provided for ad-hoc + queries. Only omit when executing a previously saved query by queryId. Use the + keys and values endpoints to discover available fields before building filters. + """ view: Literal["traces", "events", "calculations", "invocations", "requests", "agents"] - """Examples by view type. + """Controls the shape of the response. - Events: show errors for a worker in the last 30 minutes. Calculations: p99 of - wall time or count by status code. Invocations: find a specific request that - resulted in a 500. + 'events': individual log lines matching the query. 'calculations': aggregated + metrics (count, avg, p99, etc.) with optional group-by breakdowns and + time-series. 'invocations': events grouped by request ID. 'traces': distributed + trace summaries. 'agents': Durable Object agent summaries. """ @@ -100,9 +120,9 @@ class TelemetryQueryParams(TypedDict, total=False): class Timeframe(_TimeframeReservedKeywords, total=False): - """Timeframe for your query using Unix timestamps in milliseconds. + """Timeframe for the query using Unix timestamps in milliseconds. - Provide from/to epoch ms; narrower timeframes provide faster responses and more specific results. + Narrower timeframes produce faster responses and more specific results. """ to: Required[float] @@ -152,20 +172,32 @@ class ParametersCalculation(TypedDict, total=False): "VARIANCE", ] ] + """Aggregation operator to apply. + + Examples: count, avg, sum, min, max, p50, p90, p95, p99, uniq, stddev, variance. + """ alias: str + """Custom label for this calculation in the results. + + Useful for distinguishing multiple calculations. + """ key: str - """The key to use for the calculation. + """Field name to calculate over. - This key must exist in the logs. Use the observability_keys response to confirm. - Do not guess keys. + Must exist in the data — verify with the keys endpoint. Omit for operators that + don't require a key (e.g. count). """ key_type: Annotated[Literal["string", "number", "boolean"], PropertyInfo(alias="keyType")] + """Data type of the key. + Required when key is provided to ensure correct aggregation. + """ -class ParametersFilterUnionMember0(TypedDict, total=False): + +class ParametersFilterUnionMember0FilterUnionMember0(TypedDict, total=False): filter_combination: Required[Annotated[Literal["and", "or", "AND", "OR"], PropertyInfo(alias="filterCombination")]] filters: Required[Iterable[object]] @@ -173,17 +205,106 @@ class ParametersFilterUnionMember0(TypedDict, total=False): kind: Required[Literal["group"]] -class ParametersFilterWorkersObservabilityFilterLeaf(TypedDict, total=False): +class ParametersFilterUnionMember0FilterWorkersObservabilityFilterLeaf(TypedDict, total=False): + """A filter condition applied to query results. + + Use the keys and values endpoints to discover available fields and their values before constructing filters. + """ + + key: Required[str] + """Filter field name. + + Use verified keys from previous query results or the keys endpoint. Common keys + include $metadata.service, $metadata.origin, $metadata.trigger, + $metadata.message, and $metadata.error. """ - Filtering best practices: use observability_keys and observability_values to confirm available fields and values. If searching for errors, filter for $metadata.error exists. + + operation: Required[ + Literal[ + "includes", + "not_includes", + "starts_with", + "regex", + "exists", + "is_null", + "in", + "not_in", + "eq", + "neq", + "gt", + "gte", + "lt", + "lte", + "=", + "!=", + ">", + ">=", + "<", + "<=", + "INCLUDES", + "DOES_NOT_INCLUDE", + "MATCH_REGEX", + "EXISTS", + "DOES_NOT_EXIST", + "IN", + "NOT_IN", + "STARTS_WITH", + ] + ] + """Comparison operator. + + String operators: includes, not_includes, starts_with, regex. Existence: exists, + is_null. Set membership: in, not_in (comma-separated values). Numeric: eq, neq, + gt, gte, lt, lte. + """ + + type: Required[Literal["string", "number", "boolean"]] + """Data type of the filter field. + + Must match the actual type of the key being filtered. + """ + + kind: Literal["filter"] + """Discriminator for leaf filter nodes. + + Always 'filter' when present; may be omitted. + """ + + value: Union[str, float, bool] + """Comparison value. + + Must match actual values in your data — verify with the values endpoint. Ensure + the value type (string/number/boolean) matches the field type. String + comparisons are case-sensitive. Regex uses RE2 syntax (no + lookaheads/lookbehinds). + """ + + +ParametersFilterUnionMember0Filter: TypeAlias = Union[ + ParametersFilterUnionMember0FilterUnionMember0, ParametersFilterUnionMember0FilterWorkersObservabilityFilterLeaf +] + + +class ParametersFilterUnionMember0(TypedDict, total=False): + filter_combination: Required[Annotated[Literal["and", "or", "AND", "OR"], PropertyInfo(alias="filterCombination")]] + + filters: Required[Iterable[ParametersFilterUnionMember0Filter]] + + kind: Required[Literal["group"]] + + +class ParametersFilterWorkersObservabilityFilterLeaf(TypedDict, total=False): + """A filter condition applied to query results. + + Use the keys and values endpoints to discover available fields and their values before constructing filters. """ key: Required[str] """Filter field name. - IMPORTANT: do not guess keys. Always use verified keys from previous query - results or the observability_keys response. Preferred keys: $metadata.service, - $metadata.origin, $metadata.trigger, $metadata.message, $metadata.error. + Use verified keys from previous query results or the keys endpoint. Common keys + include $metadata.service, $metadata.origin, $metadata.trigger, + $metadata.message, and $metadata.error. """ operation: Required[ @@ -218,19 +339,32 @@ class ParametersFilterWorkersObservabilityFilterLeaf(TypedDict, total=False): "STARTS_WITH", ] ] + """Comparison operator. + + String operators: includes, not_includes, starts_with, regex. Existence: exists, + is_null. Set membership: in, not_in (comma-separated values). Numeric: eq, neq, + gt, gte, lt, lte. + """ type: Required[Literal["string", "number", "boolean"]] + """Data type of the filter field. + + Must match the actual type of the key being filtered. + """ kind: Literal["filter"] + """Discriminator for leaf filter nodes. + + Always 'filter' when present; may be omitted. + """ value: Union[str, float, bool] - """Filter comparison value. + """Comparison value. - IMPORTANT: must match actual values in your logs. Verify using previous query - results or the /values endpoint. Ensure value type matches the field type. - String comparisons are case-sensitive unless using specific operations. Regex - uses ClickHouse RE2 syntax (no lookaheads/lookbehinds); examples: ^5\\dd{2}$ for - HTTP 5xx, \bERROR\b for word boundary. + Must match actual values in your data — verify with the values endpoint. Ensure + the value type (string/number/boolean) matches the field type. String + comparisons are case-sensitive. Regex uses RE2 syntax (no + lookaheads/lookbehinds). """ @@ -239,67 +373,110 @@ class ParametersFilterWorkersObservabilityFilterLeaf(TypedDict, total=False): class ParametersGroupBy(TypedDict, total=False): type: Required[Literal["string", "number", "boolean"]] + """Data type of the group-by field.""" value: Required[str] + """Field name to group results by (e.g. $metadata.service, $metadata.statusCode).""" class ParametersHaving(TypedDict, total=False): key: Required[str] + """Calculation alias or operator to filter on after aggregation.""" operation: Required[Literal["eq", "neq", "gt", "gte", "lt", "lte"]] + """Numeric comparison operator: eq, neq, gt, gte, lt, lte.""" value: Required[float] + """Threshold value to compare the calculation result against.""" class ParametersNeedle(TypedDict, total=False): - """Define an expression to search using full-text search.""" + """Full-text search expression applied across all event fields. + + Matches events containing the specified text. + """ value: Required[Union[str, float, bool]] + """The text or pattern to search for.""" is_regex: Annotated[bool, PropertyInfo(alias="isRegex")] + """When true, treats the value as a regular expression (RE2 syntax).""" match_case: Annotated[bool, PropertyInfo(alias="matchCase")] + """When true, performs a case-sensitive search. Defaults to case-insensitive.""" class ParametersOrderBy(TypedDict, total=False): - """Configure the order of the results returned by the query.""" + """Ordering for grouped calculation results. + + Only effective when a group-by is present. + """ value: Required[str] - """Configure which Calculation to order the results by.""" + """Alias of the calculation to order results by. + + Must match the alias (or operator) of a calculation in the query. + """ order: Literal["asc", "desc"] - """Set the order of the results""" + """Sort direction: 'asc' for ascending, 'desc' for descending.""" class Parameters(TypedDict, total=False): - """Optional parameters to pass to the query execution""" + """ + Query parameters defining what data to retrieve — filters, calculations, group-bys, and ordering. In practice this should always be provided for ad-hoc queries. Only omit when executing a previously saved query by queryId. Use the keys and values endpoints to discover available fields before building filters. + """ calculations: Iterable[ParametersCalculation] - """Create Calculations to compute as part of the query.""" + """Aggregation calculations to compute (e.g. + + count, avg, p99). Each calculation produces aggregate values and optional + time-series data. + """ datasets: SequenceNotStr[str] - """Set the Datasets to query. Leave it empty to query all the datasets.""" + """Datasets to query. Leave empty to query all available datasets.""" filter_combination: Annotated[Literal["and", "or", "AND", "OR"], PropertyInfo(alias="filterCombination")] - """Set a Flag to describe how to combine the filters on the query.""" + """ + Logical operator for combining top-level filters: 'and' (all must match) or 'or' + (any must match). Defaults to 'and'. + """ filters: Iterable[ParametersFilter] - """Configure the Filters to apply to the query. + """Filters to narrow query results. - Supports nested groups via kind: 'group'. Maximum nesting depth is 4. + Use the keys and values endpoints to discover available fields before building + filters. Supports nested groups via kind: 'group'. Maximum nesting depth is 4. """ group_bys: Annotated[Iterable[ParametersGroupBy], PropertyInfo(alias="groupBys")] - """Define how to group the results of the query.""" + """Fields to group calculation results by. + + Only applicable when the query view is 'calculations'. Produces per-group + aggregate values. + """ havings: Iterable[ParametersHaving] - """Configure the Having clauses that filter on calculations in the query result.""" + """Post-aggregation filters applied to calculation results. + + Use to filter groups after aggregation (e.g. only groups where count > 100). + """ limit: int - """Set a limit on the number of results / records returned by the query""" + """Maximum number of group-by rows to return in calculation results. + + A value of 10 is a sensible default for most use cases. + """ needle: ParametersNeedle - """Define an expression to search using full-text search.""" + """Full-text search expression applied across all event fields. + + Matches events containing the specified text. + """ order_by: Annotated[ParametersOrderBy, PropertyInfo(alias="orderBy")] - """Configure the order of the results returned by the query.""" + """Ordering for grouped calculation results. + + Only effective when a group-by is present. + """ diff --git a/src/cloudflare/types/workers/observability/telemetry_query_response.py b/src/cloudflare/types/workers/observability/telemetry_query_response.py index 27fe10fc78d..6ec793c152f 100644 --- a/src/cloudflare/types/workers/observability/telemetry_query_response.py +++ b/src/cloudflare/types/workers/observability/telemetry_query_response.py @@ -120,16 +120,17 @@ class RunQueryParametersFilterUnionMember0(BaseModel): class RunQueryParametersFilterWorkersObservabilityFilterLeaf(BaseModel): - """ - Filtering best practices: use observability_keys and observability_values to confirm available fields and values. If searching for errors, filter for $metadata.error exists. + """A filter condition applied to query results. + + Use the keys and values endpoints to discover available fields and their values before constructing filters. """ key: str """Filter field name. - IMPORTANT: do not guess keys. Always use verified keys from previous query - results or the observability_keys response. Preferred keys: $metadata.service, - $metadata.origin, $metadata.trigger, $metadata.message, $metadata.error. + Use verified keys from previous query results or the keys endpoint. Common keys + include $metadata.service, $metadata.origin, $metadata.trigger, + $metadata.message, and $metadata.error. """ operation: Literal[ @@ -162,19 +163,32 @@ class RunQueryParametersFilterWorkersObservabilityFilterLeaf(BaseModel): "NOT_IN", "STARTS_WITH", ] + """Comparison operator. + + String operators: includes, not_includes, starts_with, regex. Existence: exists, + is_null. Set membership: in, not_in (comma-separated values). Numeric: eq, neq, + gt, gte, lt, lte. + """ type: Literal["string", "number", "boolean"] + """Data type of the filter field. + + Must match the actual type of the key being filtered. + """ kind: Optional[Literal["filter"]] = None + """Discriminator for leaf filter nodes. + + Always 'filter' when present; may be omitted. + """ value: Union[str, float, bool, None] = None - """Filter comparison value. + """Comparison value. - IMPORTANT: must match actual values in your logs. Verify using previous query - results or the /values endpoint. Ensure value type matches the field type. - String comparisons are case-sensitive unless using specific operations. Regex - uses ClickHouse RE2 syntax (no lookaheads/lookbehinds); examples: ^5\\dd{2}$ for - HTTP 5xx, \bERROR\b for word boundary. + Must match actual values in your data — verify with the values endpoint. Ensure + the value type (string/number/boolean) matches the field type. String + comparisons are case-sensitive. Regex uses RE2 syntax (no + lookaheads/lookbehinds). """ @@ -254,6 +268,10 @@ class RunQueryParameters(BaseModel): class RunQuery(BaseModel): + """ + A saved query definition with its parameters, metadata, and ownership information. + """ + id: str adhoc: bool @@ -286,6 +304,10 @@ class RunTimeframe(BaseModel): class RunStatistics(BaseModel): + """ + Query performance statistics from the database (does not include network latency). + """ + bytes_read: float """Number of uncompressed bytes read from the table.""" @@ -303,35 +325,57 @@ class RunStatistics(BaseModel): class Run(BaseModel): - """A Workers Observability Query Object""" + """ + The query run metadata including the query definition, execution status, and timeframe. + """ id: str + """Unique identifier for this query run.""" account_id: str = FieldInfo(alias="accountId") + """Cloudflare account ID that owns this query run.""" dry: bool + """Whether this was a dry run (results not persisted).""" granularity: float + """Number of time-series buckets used for the query. + + Higher values produce more detailed series data. + """ query: RunQuery + """ + A saved query definition with its parameters, metadata, and ownership + information. + """ status: Literal["STARTED", "COMPLETED"] + """Current execution status of the query run.""" timeframe: RunTimeframe """Time range for the query execution""" user_id: str = FieldInfo(alias="userId") + """ID of the user who initiated the query run.""" created: Optional[str] = None + """ISO-8601 timestamp when the query run was created.""" statistics: Optional[RunStatistics] = None + """ + Query performance statistics from the database (does not include network + latency). + """ updated: Optional[str] = None + """ISO-8601 timestamp when the query run was last updated.""" class Statistics(BaseModel): - """ - The statistics object contains information about query performance from the database, it does not include any network latency + """Query performance statistics from the database. + + Includes execution time, rows scanned, and bytes read. Does not include network latency. """ bytes_read: float @@ -352,20 +396,31 @@ class Statistics(BaseModel): class Agent(BaseModel): agent_class: str = FieldInfo(alias="agentClass") + """Class name of the Durable Object agent.""" event_type_counts: Dict[str, float] = FieldInfo(alias="eventTypeCounts") + """Breakdown of event counts by event type.""" first_event_ms: float = FieldInfo(alias="firstEventMs") + """ + Timestamp of the earliest event from this agent in the queried window (Unix + epoch ms). + """ has_errors: bool = FieldInfo(alias="hasErrors") + """Whether the agent emitted any error events in the queried window.""" last_event_ms: float = FieldInfo(alias="lastEventMs") + """Timestamp of the most recent event from this agent (Unix epoch ms).""" namespace: str + """Durable Object namespace the agent belongs to.""" service: str + """Worker service name that hosts this agent.""" total_events: float = FieldInfo(alias="totalEvents") + """Total number of events emitted by this agent in the queried window.""" class CalculationAggregateGroup(BaseModel): @@ -481,68 +536,103 @@ class Compare(BaseModel): class EventsEventMetadata(BaseModel): + """Structured metadata extracted from the event. + + These fields are indexed and available for filtering and aggregation. + """ + id: str - """Unique event ID. Use as the cursor for offset-based pagination.""" + """Unique event ID. Use as the cursor value for offset-based pagination.""" account: Optional[str] = None + """Cloudflare account identifier.""" cloud_service: Optional[str] = FieldInfo(alias="cloudService", default=None) + """Cloudflare product that generated this event (e.g. workers, pages).""" cold_start: Optional[int] = FieldInfo(alias="coldStart", default=None) + """Whether this was a cold start (1) or warm invocation (0).""" cost: Optional[int] = None + """Estimated cost units for this invocation.""" duration: Optional[int] = None + """Span duration in milliseconds.""" end_time: Optional[int] = FieldInfo(alias="endTime", default=None) + """Span end time as a Unix epoch in milliseconds.""" error: Optional[str] = None + """Error message, present when the log represents an error.""" error_template: Optional[str] = FieldInfo(alias="errorTemplate", default=None) + """Templatized version of the error message used for grouping similar errors.""" fingerprint: Optional[str] = None + """Content-based fingerprint used to group similar events.""" level: Optional[str] = None + """Log level (e.g. log, debug, info, warn, error).""" message: Optional[str] = None + """Log message text.""" message_template: Optional[str] = FieldInfo(alias="messageTemplate", default=None) + """Templatized version of the log message used for grouping similar messages.""" metric_name: Optional[str] = FieldInfo(alias="metricName", default=None) + """Metric name when the event represents a metric data point.""" origin: Optional[str] = None + """Origin of the event (e.g. fetch, scheduled, queue).""" parent_span_id: Optional[str] = FieldInfo(alias="parentSpanId", default=None) + """Span ID of the parent span in the trace hierarchy.""" provider: Optional[str] = None + """Infrastructure provider identifier.""" region: Optional[str] = None + """Cloudflare data center / region that handled the request.""" request_id: Optional[str] = FieldInfo(alias="requestId", default=None) + """Cloudflare request ID that ties all logs from a single invocation together.""" service: Optional[str] = None + """Worker script name that produced this event.""" span_id: Optional[str] = FieldInfo(alias="spanId", default=None) + """Span ID for this individual unit of work within a trace.""" span_name: Optional[str] = FieldInfo(alias="spanName", default=None) + """Human-readable name for this span.""" stack_id: Optional[str] = FieldInfo(alias="stackId", default=None) + """Stack / deployment identifier.""" start_time: Optional[int] = FieldInfo(alias="startTime", default=None) + """Span start time as a Unix epoch in milliseconds.""" status_code: Optional[int] = FieldInfo(alias="statusCode", default=None) + """HTTP response status code returned by the Worker.""" trace_duration: Optional[int] = FieldInfo(alias="traceDuration", default=None) + """Total duration of the entire trace in milliseconds.""" trace_id: Optional[str] = FieldInfo(alias="traceId", default=None) + """Distributed trace ID linking spans across services.""" transaction_name: Optional[str] = FieldInfo(alias="transactionName", default=None) + """Logical transaction name for this request.""" trigger: Optional[str] = None + """What triggered the invocation (e.g. GET /users, POST /orders, queue message).""" type: Optional[str] = None + """Event type classifier (e.g. cf-worker-event, cf-worker-log).""" url: Optional[str] = None + """Request URL that triggered the Worker invocation.""" class EventsEventWorkersUnionMember0ScriptVersion(BaseModel): @@ -576,6 +666,10 @@ class EventsEventWorkersUnionMember0(BaseModel): alias="scriptVersion", default=None ) + span_id: Optional[str] = FieldInfo(alias="spanId", default=None) + + trace_id: Optional[str] = FieldInfo(alias="traceId", default=None) + truncated: Optional[bool] = None @@ -628,6 +722,10 @@ class EventsEventWorkersUnionMember1(BaseModel): alias="scriptVersion", default=None ) + span_id: Optional[str] = FieldInfo(alias="spanId", default=None) + + trace_id: Optional[str] = FieldInfo(alias="traceId", default=None) + truncated: Optional[bool] = None @@ -635,33 +733,47 @@ class EventsEventWorkersUnionMember1(BaseModel): class EventsEvent(BaseModel): - """The data structure of a telemetry event""" + """ + A single telemetry event representing a log line, span, or metric data point emitted by a Worker. + """ metadata: EventsEventMetadata = FieldInfo(alias="$metadata") + """Structured metadata extracted from the event. + + These fields are indexed and available for filtering and aggregation. + """ dataset: str + """The dataset this event belongs to (e.g. cloudflare-workers).""" source: Union[str, object] + """Raw log payload. + + May be a string or a structured object depending on how the log was emitted. + """ timestamp: int + """Event timestamp as a Unix epoch in milliseconds.""" containers: Optional[object] = FieldInfo(alias="$containers", default=None) """ - Cloudflare Containers event information enriches your logs so you can easily - identify and debug issues. + Cloudflare Containers event information that enriches your logs for identifying + and debugging issues. """ workers: Optional[EventsEventWorkers] = FieldInfo(alias="$workers", default=None) """ - Cloudflare Workers event information enriches your logs so you can easily - identify and debug issues. + Cloudflare Workers event information that enriches your logs for identifying and + debugging issues. """ class EventsField(BaseModel): key: str + """Field name present in the matched events.""" type: str + """Data type of the field (string, number, or boolean).""" class EventsSeriesDataAggregates(BaseModel): @@ -698,78 +810,128 @@ class EventsSeries(BaseModel): class Events(BaseModel): + """Individual event results. + + Present when the query view is 'events'. Contains the matching log lines and their metadata. + """ + count: Optional[float] = None + """ + Total number of events matching the query (may exceed the number returned due to + limits). + """ events: Optional[List[EventsEvent]] = None + """List of individual telemetry events matching the query.""" fields: Optional[List[EventsField]] = None + """List of fields discovered in the matched events. + + Useful for building dynamic UIs. + """ series: Optional[List[EventsSeries]] = None + """Time-series data for the matched events, bucketed by the query granularity.""" class InvocationMetadata(BaseModel): + """Structured metadata extracted from the event. + + These fields are indexed and available for filtering and aggregation. + """ + id: str - """Unique event ID. Use as the cursor for offset-based pagination.""" + """Unique event ID. Use as the cursor value for offset-based pagination.""" account: Optional[str] = None + """Cloudflare account identifier.""" cloud_service: Optional[str] = FieldInfo(alias="cloudService", default=None) + """Cloudflare product that generated this event (e.g. workers, pages).""" cold_start: Optional[int] = FieldInfo(alias="coldStart", default=None) + """Whether this was a cold start (1) or warm invocation (0).""" cost: Optional[int] = None + """Estimated cost units for this invocation.""" duration: Optional[int] = None + """Span duration in milliseconds.""" end_time: Optional[int] = FieldInfo(alias="endTime", default=None) + """Span end time as a Unix epoch in milliseconds.""" error: Optional[str] = None + """Error message, present when the log represents an error.""" error_template: Optional[str] = FieldInfo(alias="errorTemplate", default=None) + """Templatized version of the error message used for grouping similar errors.""" fingerprint: Optional[str] = None + """Content-based fingerprint used to group similar events.""" level: Optional[str] = None + """Log level (e.g. log, debug, info, warn, error).""" message: Optional[str] = None + """Log message text.""" message_template: Optional[str] = FieldInfo(alias="messageTemplate", default=None) + """Templatized version of the log message used for grouping similar messages.""" metric_name: Optional[str] = FieldInfo(alias="metricName", default=None) + """Metric name when the event represents a metric data point.""" origin: Optional[str] = None + """Origin of the event (e.g. fetch, scheduled, queue).""" parent_span_id: Optional[str] = FieldInfo(alias="parentSpanId", default=None) + """Span ID of the parent span in the trace hierarchy.""" provider: Optional[str] = None + """Infrastructure provider identifier.""" region: Optional[str] = None + """Cloudflare data center / region that handled the request.""" request_id: Optional[str] = FieldInfo(alias="requestId", default=None) + """Cloudflare request ID that ties all logs from a single invocation together.""" service: Optional[str] = None + """Worker script name that produced this event.""" span_id: Optional[str] = FieldInfo(alias="spanId", default=None) + """Span ID for this individual unit of work within a trace.""" span_name: Optional[str] = FieldInfo(alias="spanName", default=None) + """Human-readable name for this span.""" stack_id: Optional[str] = FieldInfo(alias="stackId", default=None) + """Stack / deployment identifier.""" start_time: Optional[int] = FieldInfo(alias="startTime", default=None) + """Span start time as a Unix epoch in milliseconds.""" status_code: Optional[int] = FieldInfo(alias="statusCode", default=None) + """HTTP response status code returned by the Worker.""" trace_duration: Optional[int] = FieldInfo(alias="traceDuration", default=None) + """Total duration of the entire trace in milliseconds.""" trace_id: Optional[str] = FieldInfo(alias="traceId", default=None) + """Distributed trace ID linking spans across services.""" transaction_name: Optional[str] = FieldInfo(alias="transactionName", default=None) + """Logical transaction name for this request.""" trigger: Optional[str] = None + """What triggered the invocation (e.g. GET /users, POST /orders, queue message).""" type: Optional[str] = None + """Event type classifier (e.g. cf-worker-event, cf-worker-log).""" url: Optional[str] = None + """Request URL that triggered the Worker invocation.""" class InvocationWorkersUnionMember0ScriptVersion(BaseModel): @@ -803,6 +965,10 @@ class InvocationWorkersUnionMember0(BaseModel): alias="scriptVersion", default=None ) + span_id: Optional[str] = FieldInfo(alias="spanId", default=None) + + trace_id: Optional[str] = FieldInfo(alias="traceId", default=None) + truncated: Optional[bool] = None @@ -855,6 +1021,10 @@ class InvocationWorkersUnionMember1(BaseModel): alias="scriptVersion", default=None ) + span_id: Optional[str] = FieldInfo(alias="spanId", default=None) + + trace_id: Optional[str] = FieldInfo(alias="traceId", default=None) + truncated: Optional[bool] = None @@ -862,67 +1032,126 @@ class InvocationWorkersUnionMember1(BaseModel): class Invocation(BaseModel): - """The data structure of a telemetry event""" + """ + A single telemetry event representing a log line, span, or metric data point emitted by a Worker. + """ metadata: InvocationMetadata = FieldInfo(alias="$metadata") + """Structured metadata extracted from the event. + + These fields are indexed and available for filtering and aggregation. + """ dataset: str + """The dataset this event belongs to (e.g. cloudflare-workers).""" source: Union[str, object] + """Raw log payload. + + May be a string or a structured object depending on how the log was emitted. + """ timestamp: int + """Event timestamp as a Unix epoch in milliseconds.""" containers: Optional[object] = FieldInfo(alias="$containers", default=None) """ - Cloudflare Containers event information enriches your logs so you can easily - identify and debug issues. + Cloudflare Containers event information that enriches your logs for identifying + and debugging issues. """ workers: Optional[InvocationWorkers] = FieldInfo(alias="$workers", default=None) """ - Cloudflare Workers event information enriches your logs so you can easily - identify and debug issues. + Cloudflare Workers event information that enriches your logs for identifying and + debugging issues. """ class Trace(BaseModel): root_span_name: str = FieldInfo(alias="rootSpanName") + """Name of the root span that initiated the trace.""" root_transaction_name: str = FieldInfo(alias="rootTransactionName") + """Logical transaction name for the root span.""" service: List[str] + """List of Worker services involved in the trace.""" spans: float + """Total number of spans in the trace.""" trace_duration_ms: float = FieldInfo(alias="traceDurationMs") + """Total duration of the trace in milliseconds.""" trace_end_ms: float = FieldInfo(alias="traceEndMs") + """Trace end time as a Unix epoch in milliseconds.""" trace_id: str = FieldInfo(alias="traceId") + """Unique identifier for the distributed trace.""" trace_start_ms: float = FieldInfo(alias="traceStartMs") + """Trace start time as a Unix epoch in milliseconds.""" errors: Optional[List[str]] = None + """Error messages encountered during the trace, if any.""" class TelemetryQueryResponse(BaseModel): + """Complete results of a query run. + + The populated fields depend on the requested view type (events, calculations, invocations, traces, or agents). + """ + run: Run - """A Workers Observability Query Object""" + """ + The query run metadata including the query definition, execution status, and + timeframe. + """ statistics: Statistics - """ - The statistics object contains information about query performance from the - database, it does not include any network latency + """Query performance statistics from the database. + + Includes execution time, rows scanned, and bytes read. Does not include network + latency. """ agents: Optional[List[Agent]] = None + """Durable Object agent summaries. + + Present when the query view is 'agents'. Each entry represents an agent with its + event counts and status. + """ calculations: Optional[List[Calculation]] = None + """Aggregated calculation results. + + Present when the query view is 'calculations'. Contains computed metrics (count, + avg, p99, etc.) with optional group-by breakdowns and time-series data. + """ compare: Optional[List[Compare]] = None + """Comparison calculation results from the previous time period. + + Present when the compare option is enabled. Same structure as calculations. + """ events: Optional[Events] = None + """Individual event results. + + Present when the query view is 'events'. Contains the matching log lines and + their metadata. + """ invocations: Optional[Dict[str, List[Invocation]]] = None + """Events grouped by invocation (request ID). + + Present when the query view is 'invocations'. Each key is a request ID mapping + to all events from that invocation. + """ traces: Optional[List[Trace]] = None + """Trace summaries matching the query. + + Present when the query view is 'traces'. Each entry represents a distributed + trace with its spans, duration, and services involved. + """ diff --git a/src/cloudflare/types/workers/observability/telemetry_values_params.py b/src/cloudflare/types/workers/observability/telemetry_values_params.py index 9451743e295..a42192593ea 100644 --- a/src/cloudflare/types/workers/observability/telemetry_values_params.py +++ b/src/cloudflare/types/workers/observability/telemetry_values_params.py @@ -13,6 +13,9 @@ "Timeframe", "Filter", "FilterUnionMember0", + "FilterUnionMember0Filter", + "FilterUnionMember0FilterUnionMember0", + "FilterUnionMember0FilterWorkersObservabilityFilterLeaf", "FilterWorkersObservabilityFilterLeaf", "Needle", ] @@ -39,7 +42,10 @@ class TelemetryValuesParams(TypedDict, total=False): limit: float needle: Needle - """Search for a specific substring in the event.""" + """ + Full-text search expression to match events containing the specified text or + pattern. + """ _TimeframeReservedKeywords = TypedDict( @@ -55,7 +61,7 @@ class Timeframe(_TimeframeReservedKeywords, total=False): to: Required[float] -class FilterUnionMember0(TypedDict, total=False): +class FilterUnionMember0FilterUnionMember0(TypedDict, total=False): filter_combination: Required[Annotated[Literal["and", "or", "AND", "OR"], PropertyInfo(alias="filterCombination")]] filters: Required[Iterable[object]] @@ -63,17 +69,106 @@ class FilterUnionMember0(TypedDict, total=False): kind: Required[Literal["group"]] -class FilterWorkersObservabilityFilterLeaf(TypedDict, total=False): +class FilterUnionMember0FilterWorkersObservabilityFilterLeaf(TypedDict, total=False): + """A filter condition applied to query results. + + Use the keys and values endpoints to discover available fields and their values before constructing filters. """ - Filtering best practices: use observability_keys and observability_values to confirm available fields and values. If searching for errors, filter for $metadata.error exists. + + key: Required[str] + """Filter field name. + + Use verified keys from previous query results or the keys endpoint. Common keys + include $metadata.service, $metadata.origin, $metadata.trigger, + $metadata.message, and $metadata.error. + """ + + operation: Required[ + Literal[ + "includes", + "not_includes", + "starts_with", + "regex", + "exists", + "is_null", + "in", + "not_in", + "eq", + "neq", + "gt", + "gte", + "lt", + "lte", + "=", + "!=", + ">", + ">=", + "<", + "<=", + "INCLUDES", + "DOES_NOT_INCLUDE", + "MATCH_REGEX", + "EXISTS", + "DOES_NOT_EXIST", + "IN", + "NOT_IN", + "STARTS_WITH", + ] + ] + """Comparison operator. + + String operators: includes, not_includes, starts_with, regex. Existence: exists, + is_null. Set membership: in, not_in (comma-separated values). Numeric: eq, neq, + gt, gte, lt, lte. + """ + + type: Required[Literal["string", "number", "boolean"]] + """Data type of the filter field. + + Must match the actual type of the key being filtered. + """ + + kind: Literal["filter"] + """Discriminator for leaf filter nodes. + + Always 'filter' when present; may be omitted. + """ + + value: Union[str, float, bool] + """Comparison value. + + Must match actual values in your data — verify with the values endpoint. Ensure + the value type (string/number/boolean) matches the field type. String + comparisons are case-sensitive. Regex uses RE2 syntax (no + lookaheads/lookbehinds). + """ + + +FilterUnionMember0Filter: TypeAlias = Union[ + FilterUnionMember0FilterUnionMember0, FilterUnionMember0FilterWorkersObservabilityFilterLeaf +] + + +class FilterUnionMember0(TypedDict, total=False): + filter_combination: Required[Annotated[Literal["and", "or", "AND", "OR"], PropertyInfo(alias="filterCombination")]] + + filters: Required[Iterable[FilterUnionMember0Filter]] + + kind: Required[Literal["group"]] + + +class FilterWorkersObservabilityFilterLeaf(TypedDict, total=False): + """A filter condition applied to query results. + + Use the keys and values endpoints to discover available fields and their values before constructing filters. """ key: Required[str] """Filter field name. - IMPORTANT: do not guess keys. Always use verified keys from previous query - results or the observability_keys response. Preferred keys: $metadata.service, - $metadata.origin, $metadata.trigger, $metadata.message, $metadata.error. + Use verified keys from previous query results or the keys endpoint. Common keys + include $metadata.service, $metadata.origin, $metadata.trigger, + $metadata.message, and $metadata.error. """ operation: Required[ @@ -108,19 +203,32 @@ class FilterWorkersObservabilityFilterLeaf(TypedDict, total=False): "STARTS_WITH", ] ] + """Comparison operator. + + String operators: includes, not_includes, starts_with, regex. Existence: exists, + is_null. Set membership: in, not_in (comma-separated values). Numeric: eq, neq, + gt, gte, lt, lte. + """ type: Required[Literal["string", "number", "boolean"]] + """Data type of the filter field. + + Must match the actual type of the key being filtered. + """ kind: Literal["filter"] + """Discriminator for leaf filter nodes. + + Always 'filter' when present; may be omitted. + """ value: Union[str, float, bool] - """Filter comparison value. + """Comparison value. - IMPORTANT: must match actual values in your logs. Verify using previous query - results or the /values endpoint. Ensure value type matches the field type. - String comparisons are case-sensitive unless using specific operations. Regex - uses ClickHouse RE2 syntax (no lookaheads/lookbehinds); examples: ^5\\dd{2}$ for - HTTP 5xx, \bERROR\b for word boundary. + Must match actual values in your data — verify with the values endpoint. Ensure + the value type (string/number/boolean) matches the field type. String + comparisons are case-sensitive. Regex uses RE2 syntax (no + lookaheads/lookbehinds). """ @@ -128,10 +236,15 @@ class FilterWorkersObservabilityFilterLeaf(TypedDict, total=False): class Needle(TypedDict, total=False): - """Search for a specific substring in the event.""" + """ + Full-text search expression to match events containing the specified text or pattern. + """ value: Required[Union[str, float, bool]] + """The text or pattern to search for.""" is_regex: Annotated[bool, PropertyInfo(alias="isRegex")] + """When true, treats the value as a regular expression (RE2 syntax).""" match_case: Annotated[bool, PropertyInfo(alias="matchCase")] + """When true, performs a case-sensitive search. Defaults to case-insensitive.""" diff --git a/src/cloudflare/types/workers/script_update_params.py b/src/cloudflare/types/workers/script_update_params.py index fab83dc8675..87d31dee903 100644 --- a/src/cloudflare/types/workers/script_update_params.py +++ b/src/cloudflare/types/workers/script_update_params.py @@ -462,6 +462,13 @@ class MetadataBindingWorkersBindingKindRatelimitSimple(TypedDict, total=False): period: Required[int] """The period in seconds.""" + mitigation_timeout: int + """ + Duration in seconds to apply the mitigation action after the rate limit is + exceeded. Valid values are 0 (disabled), 10, or multiples of 60 up to 86400. + Must be greater than or equal to the period when non-zero. + """ + class MetadataBindingWorkersBindingKindRatelimit(TypedDict, total=False): name: Required[str] diff --git a/src/cloudflare/types/workers/scripts/script_and_version_setting_edit_params.py b/src/cloudflare/types/workers/scripts/script_and_version_setting_edit_params.py index 4307e6a11f3..6429f45ae6e 100644 --- a/src/cloudflare/types/workers/scripts/script_and_version_setting_edit_params.py +++ b/src/cloudflare/types/workers/scripts/script_and_version_setting_edit_params.py @@ -394,6 +394,13 @@ class SettingsBindingWorkersBindingKindRatelimitSimple(TypedDict, total=False): period: Required[int] """The period in seconds.""" + mitigation_timeout: int + """ + Duration in seconds to apply the mitigation action after the rate limit is + exceeded. Valid values are 0 (disabled), 10, or multiples of 60 up to 86400. + Must be greater than or equal to the period when non-zero. + """ + class SettingsBindingWorkersBindingKindRatelimit(TypedDict, total=False): name: Required[str] diff --git a/src/cloudflare/types/workers/scripts/script_and_version_setting_edit_response.py b/src/cloudflare/types/workers/scripts/script_and_version_setting_edit_response.py index 0e750e5f8d3..067b2732892 100644 --- a/src/cloudflare/types/workers/scripts/script_and_version_setting_edit_response.py +++ b/src/cloudflare/types/workers/scripts/script_and_version_setting_edit_response.py @@ -391,6 +391,13 @@ class BindingWorkersBindingKindRatelimitSimple(BaseModel): period: int """The period in seconds.""" + mitigation_timeout: Optional[int] = None + """ + Duration in seconds to apply the mitigation action after the rate limit is + exceeded. Valid values are 0 (disabled), 10, or multiples of 60 up to 86400. + Must be greater than or equal to the period when non-zero. + """ + class BindingWorkersBindingKindRatelimit(BaseModel): name: str diff --git a/src/cloudflare/types/workers/scripts/script_and_version_setting_get_response.py b/src/cloudflare/types/workers/scripts/script_and_version_setting_get_response.py index 5349c407900..0ef9c3aa1d2 100644 --- a/src/cloudflare/types/workers/scripts/script_and_version_setting_get_response.py +++ b/src/cloudflare/types/workers/scripts/script_and_version_setting_get_response.py @@ -391,6 +391,13 @@ class BindingWorkersBindingKindRatelimitSimple(BaseModel): period: int """The period in seconds.""" + mitigation_timeout: Optional[int] = None + """ + Duration in seconds to apply the mitigation action after the rate limit is + exceeded. Valid values are 0 (disabled), 10, or multiples of 60 up to 86400. + Must be greater than or equal to the period when non-zero. + """ + class BindingWorkersBindingKindRatelimit(BaseModel): name: str diff --git a/src/cloudflare/types/workers/scripts/version_create_params.py b/src/cloudflare/types/workers/scripts/version_create_params.py index 1d985b2f937..0e8a9292025 100644 --- a/src/cloudflare/types/workers/scripts/version_create_params.py +++ b/src/cloudflare/types/workers/scripts/version_create_params.py @@ -389,6 +389,13 @@ class MetadataBindingWorkersBindingKindRatelimitSimple(TypedDict, total=False): period: Required[int] """The period in seconds.""" + mitigation_timeout: int + """ + Duration in seconds to apply the mitigation action after the rate limit is + exceeded. Valid values are 0 (disabled), 10, or multiples of 60 up to 86400. + Must be greater than or equal to the period when non-zero. + """ + class MetadataBindingWorkersBindingKindRatelimit(TypedDict, total=False): name: Required[str] diff --git a/src/cloudflare/types/workers/scripts/version_create_response.py b/src/cloudflare/types/workers/scripts/version_create_response.py index 005dc5468ea..19a0770d43f 100644 --- a/src/cloudflare/types/workers/scripts/version_create_response.py +++ b/src/cloudflare/types/workers/scripts/version_create_response.py @@ -356,6 +356,13 @@ class ResourcesBindingWorkersBindingKindRatelimitSimple(BaseModel): period: int """The period in seconds.""" + mitigation_timeout: Optional[int] = None + """ + Duration in seconds to apply the mitigation action after the rate limit is + exceeded. Valid values are 0 (disabled), 10, or multiples of 60 up to 86400. + Must be greater than or equal to the period when non-zero. + """ + class ResourcesBindingWorkersBindingKindRatelimit(BaseModel): name: str diff --git a/src/cloudflare/types/workers/scripts/version_get_response.py b/src/cloudflare/types/workers/scripts/version_get_response.py index 3174e861c13..6dd42eceb0d 100644 --- a/src/cloudflare/types/workers/scripts/version_get_response.py +++ b/src/cloudflare/types/workers/scripts/version_get_response.py @@ -356,6 +356,13 @@ class ResourcesBindingWorkersBindingKindRatelimitSimple(BaseModel): period: int """The period in seconds.""" + mitigation_timeout: Optional[int] = None + """ + Duration in seconds to apply the mitigation action after the rate limit is + exceeded. Valid values are 0 (disabled), 10, or multiples of 60 up to 86400. + Must be greater than or equal to the period when non-zero. + """ + class ResourcesBindingWorkersBindingKindRatelimit(BaseModel): name: str diff --git a/src/cloudflare/types/workers_for_platforms/dispatch/namespaces/script_update_params.py b/src/cloudflare/types/workers_for_platforms/dispatch/namespaces/script_update_params.py index ff2bf226887..1ee5fdc4238 100644 --- a/src/cloudflare/types/workers_for_platforms/dispatch/namespaces/script_update_params.py +++ b/src/cloudflare/types/workers_for_platforms/dispatch/namespaces/script_update_params.py @@ -453,6 +453,13 @@ class MetadataBindingWorkersBindingKindRatelimitSimple(TypedDict, total=False): period: Required[int] """The period in seconds.""" + mitigation_timeout: int + """ + Duration in seconds to apply the mitigation action after the rate limit is + exceeded. Valid values are 0 (disabled), 10, or multiples of 60 up to 86400. + Must be greater than or equal to the period when non-zero. + """ + class MetadataBindingWorkersBindingKindRatelimit(TypedDict, total=False): name: Required[str] diff --git a/src/cloudflare/types/workers_for_platforms/dispatch/namespaces/scripts/binding_get_response.py b/src/cloudflare/types/workers_for_platforms/dispatch/namespaces/scripts/binding_get_response.py index 6b3ccd16c1b..a6d931b6a1b 100644 --- a/src/cloudflare/types/workers_for_platforms/dispatch/namespaces/scripts/binding_get_response.py +++ b/src/cloudflare/types/workers_for_platforms/dispatch/namespaces/scripts/binding_get_response.py @@ -349,6 +349,13 @@ class WorkersBindingKindRatelimitSimple(BaseModel): period: int """The period in seconds.""" + mitigation_timeout: Optional[int] = None + """ + Duration in seconds to apply the mitigation action after the rate limit is + exceeded. Valid values are 0 (disabled), 10, or multiples of 60 up to 86400. + Must be greater than or equal to the period when non-zero. + """ + class WorkersBindingKindRatelimit(BaseModel): name: str diff --git a/src/cloudflare/types/workers_for_platforms/dispatch/namespaces/scripts/setting_edit_params.py b/src/cloudflare/types/workers_for_platforms/dispatch/namespaces/scripts/setting_edit_params.py index f11ee4e853d..949f1600882 100644 --- a/src/cloudflare/types/workers_for_platforms/dispatch/namespaces/scripts/setting_edit_params.py +++ b/src/cloudflare/types/workers_for_platforms/dispatch/namespaces/scripts/setting_edit_params.py @@ -387,6 +387,13 @@ class SettingsBindingWorkersBindingKindRatelimitSimple(TypedDict, total=False): period: Required[int] """The period in seconds.""" + mitigation_timeout: int + """ + Duration in seconds to apply the mitigation action after the rate limit is + exceeded. Valid values are 0 (disabled), 10, or multiples of 60 up to 86400. + Must be greater than or equal to the period when non-zero. + """ + class SettingsBindingWorkersBindingKindRatelimit(TypedDict, total=False): name: Required[str] diff --git a/src/cloudflare/types/workers_for_platforms/dispatch/namespaces/scripts/setting_edit_response.py b/src/cloudflare/types/workers_for_platforms/dispatch/namespaces/scripts/setting_edit_response.py index 260a281de41..e6df38c5dce 100644 --- a/src/cloudflare/types/workers_for_platforms/dispatch/namespaces/scripts/setting_edit_response.py +++ b/src/cloudflare/types/workers_for_platforms/dispatch/namespaces/scripts/setting_edit_response.py @@ -371,6 +371,13 @@ class BindingWorkersBindingKindRatelimitSimple(BaseModel): period: int """The period in seconds.""" + mitigation_timeout: Optional[int] = None + """ + Duration in seconds to apply the mitigation action after the rate limit is + exceeded. Valid values are 0 (disabled), 10, or multiples of 60 up to 86400. + Must be greater than or equal to the period when non-zero. + """ + class BindingWorkersBindingKindRatelimit(BaseModel): name: str diff --git a/src/cloudflare/types/workers_for_platforms/dispatch/namespaces/scripts/setting_get_response.py b/src/cloudflare/types/workers_for_platforms/dispatch/namespaces/scripts/setting_get_response.py index d4ac77f860a..071d860cc89 100644 --- a/src/cloudflare/types/workers_for_platforms/dispatch/namespaces/scripts/setting_get_response.py +++ b/src/cloudflare/types/workers_for_platforms/dispatch/namespaces/scripts/setting_get_response.py @@ -371,6 +371,13 @@ class BindingWorkersBindingKindRatelimitSimple(BaseModel): period: int """The period in seconds.""" + mitigation_timeout: Optional[int] = None + """ + Duration in seconds to apply the mitigation action after the rate limit is + exceeded. Valid values are 0 (disabled), 10, or multiples of 60 up to 86400. + Must be greater than or equal to the period when non-zero. + """ + class BindingWorkersBindingKindRatelimit(BaseModel): name: str diff --git a/tests/api_resources/email_security/investigate/test_detections.py b/tests/api_resources/email_security/investigate/test_detections.py deleted file mode 100644 index b9a5059538d..00000000000 --- a/tests/api_resources/email_security/investigate/test_detections.py +++ /dev/null @@ -1,120 +0,0 @@ -# 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 pytest - -from cloudflare import Cloudflare, AsyncCloudflare -from tests.utils import assert_matches_type -from cloudflare.types.email_security.investigate import DetectionGetResponse - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestDetections: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_get(self, client: Cloudflare) -> None: - detection = client.email_security.investigate.detections.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - assert_matches_type(DetectionGetResponse, detection, path=["response"]) - - @parametrize - def test_raw_response_get(self, client: Cloudflare) -> None: - response = client.email_security.investigate.detections.with_raw_response.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - detection = response.parse() - assert_matches_type(DetectionGetResponse, detection, path=["response"]) - - @parametrize - def test_streaming_response_get(self, client: Cloudflare) -> None: - with client.email_security.investigate.detections.with_streaming_response.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - detection = response.parse() - assert_matches_type(DetectionGetResponse, detection, 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.email_security.investigate.detections.with_raw_response.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `postfix_id` but received ''"): - client.email_security.investigate.detections.with_raw_response.get( - postfix_id="", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - - -class TestAsyncDetections: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_get(self, async_client: AsyncCloudflare) -> None: - detection = await async_client.email_security.investigate.detections.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - assert_matches_type(DetectionGetResponse, detection, path=["response"]) - - @parametrize - async def test_raw_response_get(self, async_client: AsyncCloudflare) -> None: - response = await async_client.email_security.investigate.detections.with_raw_response.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - detection = await response.parse() - assert_matches_type(DetectionGetResponse, detection, path=["response"]) - - @parametrize - async def test_streaming_response_get(self, async_client: AsyncCloudflare) -> None: - async with async_client.email_security.investigate.detections.with_streaming_response.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - detection = await response.parse() - assert_matches_type(DetectionGetResponse, detection, 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.email_security.investigate.detections.with_raw_response.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `postfix_id` but received ''"): - await async_client.email_security.investigate.detections.with_raw_response.get( - postfix_id="", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) diff --git a/tests/api_resources/email_security/investigate/test_move.py b/tests/api_resources/email_security/investigate/test_move.py index 141f729f76e..bfdd6cc4a7a 100644 --- a/tests/api_resources/email_security/investigate/test_move.py +++ b/tests/api_resources/email_security/investigate/test_move.py @@ -10,10 +10,7 @@ from cloudflare import Cloudflare, AsyncCloudflare from tests.utils import assert_matches_type from cloudflare.pagination import SyncSinglePage, AsyncSinglePage -from cloudflare.types.email_security.investigate import ( - MoveBulkResponse, - MoveCreateResponse, -) +from cloudflare.types.email_security.investigate import MoveBulkResponse base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -21,69 +18,6 @@ class TestMove: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - @parametrize - def test_method_create(self, client: Cloudflare) -> None: - move = client.email_security.investigate.move.create( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - destination="Inbox", - ) - assert_matches_type(MoveCreateResponse, move, path=["response"]) - - @parametrize - def test_method_create_with_all_params(self, client: Cloudflare) -> None: - move = client.email_security.investigate.move.create( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - destination="Inbox", - submission=True, - ) - assert_matches_type(MoveCreateResponse, move, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: Cloudflare) -> None: - response = client.email_security.investigate.move.with_raw_response.create( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - destination="Inbox", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - move = response.parse() - assert_matches_type(MoveCreateResponse, move, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: Cloudflare) -> None: - with client.email_security.investigate.move.with_streaming_response.create( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - destination="Inbox", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - move = response.parse() - assert_matches_type(MoveCreateResponse, move, 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.email_security.investigate.move.with_raw_response.create( - postfix_id="4Njp3P0STMz2c02Q", - account_id="", - destination="Inbox", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `postfix_id` but received ''"): - client.email_security.investigate.move.with_raw_response.create( - postfix_id="", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - destination="Inbox", - ) - @parametrize def test_method_bulk(self, client: Cloudflare) -> None: move = client.email_security.investigate.move.bulk( @@ -97,7 +31,7 @@ def test_method_bulk_with_all_params(self, client: Cloudflare) -> None: move = client.email_security.investigate.move.bulk( account_id="023e105f4ecef8ad9ca31a8372d0c353", destination="Inbox", - ids=["string"], + ids=["4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678"], postfix_ids=["4Njp3P0STMz2c02Q"], ) assert_matches_type(SyncSinglePage[MoveBulkResponse], move, path=["response"]) @@ -142,69 +76,6 @@ class TestAsyncMove: "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] ) - @parametrize - async def test_method_create(self, async_client: AsyncCloudflare) -> None: - move = await async_client.email_security.investigate.move.create( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - destination="Inbox", - ) - assert_matches_type(MoveCreateResponse, move, path=["response"]) - - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncCloudflare) -> None: - move = await async_client.email_security.investigate.move.create( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - destination="Inbox", - submission=True, - ) - assert_matches_type(MoveCreateResponse, move, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncCloudflare) -> None: - response = await async_client.email_security.investigate.move.with_raw_response.create( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - destination="Inbox", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - move = await response.parse() - assert_matches_type(MoveCreateResponse, move, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncCloudflare) -> None: - async with async_client.email_security.investigate.move.with_streaming_response.create( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - destination="Inbox", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - move = await response.parse() - assert_matches_type(MoveCreateResponse, move, 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.email_security.investigate.move.with_raw_response.create( - postfix_id="4Njp3P0STMz2c02Q", - account_id="", - destination="Inbox", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `postfix_id` but received ''"): - await async_client.email_security.investigate.move.with_raw_response.create( - postfix_id="", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - destination="Inbox", - ) - @parametrize async def test_method_bulk(self, async_client: AsyncCloudflare) -> None: move = await async_client.email_security.investigate.move.bulk( @@ -218,7 +89,7 @@ async def test_method_bulk_with_all_params(self, async_client: AsyncCloudflare) move = await async_client.email_security.investigate.move.bulk( account_id="023e105f4ecef8ad9ca31a8372d0c353", destination="Inbox", - ids=["string"], + ids=["4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678"], postfix_ids=["4Njp3P0STMz2c02Q"], ) assert_matches_type(AsyncSinglePage[MoveBulkResponse], move, path=["response"]) diff --git a/tests/api_resources/email_security/investigate/test_preview.py b/tests/api_resources/email_security/investigate/test_preview.py index 0d0cfa1bdac..81c32fc4583 100644 --- a/tests/api_resources/email_security/investigate/test_preview.py +++ b/tests/api_resources/email_security/investigate/test_preview.py @@ -9,7 +9,7 @@ from cloudflare import Cloudflare, AsyncCloudflare from tests.utils import assert_matches_type -from cloudflare.types.email_security.investigate import PreviewGetResponse, PreviewCreateResponse +from cloudflare.types.email_security.investigate import PreviewCreateResponse base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -25,15 +25,6 @@ def test_method_create(self, client: Cloudflare) -> None: ) assert_matches_type(PreviewCreateResponse, preview, path=["response"]) - @parametrize - def test_method_create_with_all_params(self, client: Cloudflare) -> None: - preview = client.email_security.investigate.preview.create( - account_id="023e105f4ecef8ad9ca31a8372d0c353", - postfix_id="4Njp3P0STMz2c02Q", - submission=True, - ) - assert_matches_type(PreviewCreateResponse, preview, path=["response"]) - @parametrize def test_raw_response_create(self, client: Cloudflare) -> None: response = client.email_security.investigate.preview.with_raw_response.create( @@ -68,54 +59,6 @@ def test_path_params_create(self, client: Cloudflare) -> None: postfix_id="4Njp3P0STMz2c02Q", ) - @parametrize - def test_method_get(self, client: Cloudflare) -> None: - preview = client.email_security.investigate.preview.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - assert_matches_type(PreviewGetResponse, preview, path=["response"]) - - @parametrize - def test_raw_response_get(self, client: Cloudflare) -> None: - response = client.email_security.investigate.preview.with_raw_response.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - preview = response.parse() - assert_matches_type(PreviewGetResponse, preview, path=["response"]) - - @parametrize - def test_streaming_response_get(self, client: Cloudflare) -> None: - with client.email_security.investigate.preview.with_streaming_response.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - preview = response.parse() - assert_matches_type(PreviewGetResponse, preview, 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.email_security.investigate.preview.with_raw_response.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `postfix_id` but received ''"): - client.email_security.investigate.preview.with_raw_response.get( - postfix_id="", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - class TestAsyncPreview: parametrize = pytest.mark.parametrize( @@ -130,15 +73,6 @@ async def test_method_create(self, async_client: AsyncCloudflare) -> None: ) assert_matches_type(PreviewCreateResponse, preview, path=["response"]) - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncCloudflare) -> None: - preview = await async_client.email_security.investigate.preview.create( - account_id="023e105f4ecef8ad9ca31a8372d0c353", - postfix_id="4Njp3P0STMz2c02Q", - submission=True, - ) - assert_matches_type(PreviewCreateResponse, preview, path=["response"]) - @parametrize async def test_raw_response_create(self, async_client: AsyncCloudflare) -> None: response = await async_client.email_security.investigate.preview.with_raw_response.create( @@ -172,51 +106,3 @@ async def test_path_params_create(self, async_client: AsyncCloudflare) -> None: account_id="", postfix_id="4Njp3P0STMz2c02Q", ) - - @parametrize - async def test_method_get(self, async_client: AsyncCloudflare) -> None: - preview = await async_client.email_security.investigate.preview.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - assert_matches_type(PreviewGetResponse, preview, path=["response"]) - - @parametrize - async def test_raw_response_get(self, async_client: AsyncCloudflare) -> None: - response = await async_client.email_security.investigate.preview.with_raw_response.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - preview = await response.parse() - assert_matches_type(PreviewGetResponse, preview, path=["response"]) - - @parametrize - async def test_streaming_response_get(self, async_client: AsyncCloudflare) -> None: - async with async_client.email_security.investigate.preview.with_streaming_response.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - preview = await response.parse() - assert_matches_type(PreviewGetResponse, preview, 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.email_security.investigate.preview.with_raw_response.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `postfix_id` but received ''"): - await async_client.email_security.investigate.preview.with_raw_response.get( - postfix_id="", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) diff --git a/tests/api_resources/email_security/investigate/test_raw.py b/tests/api_resources/email_security/investigate/test_raw.py deleted file mode 100644 index 204fbb63f6b..00000000000 --- a/tests/api_resources/email_security/investigate/test_raw.py +++ /dev/null @@ -1,120 +0,0 @@ -# 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 pytest - -from cloudflare import Cloudflare, AsyncCloudflare -from tests.utils import assert_matches_type -from cloudflare.types.email_security.investigate import RawGetResponse - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestRaw: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_get(self, client: Cloudflare) -> None: - raw = client.email_security.investigate.raw.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - assert_matches_type(RawGetResponse, raw, path=["response"]) - - @parametrize - def test_raw_response_get(self, client: Cloudflare) -> None: - response = client.email_security.investigate.raw.with_raw_response.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - raw = response.parse() - assert_matches_type(RawGetResponse, raw, path=["response"]) - - @parametrize - def test_streaming_response_get(self, client: Cloudflare) -> None: - with client.email_security.investigate.raw.with_streaming_response.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - raw = response.parse() - assert_matches_type(RawGetResponse, raw, 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.email_security.investigate.raw.with_raw_response.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `postfix_id` but received ''"): - client.email_security.investigate.raw.with_raw_response.get( - postfix_id="", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - - -class TestAsyncRaw: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_get(self, async_client: AsyncCloudflare) -> None: - raw = await async_client.email_security.investigate.raw.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - assert_matches_type(RawGetResponse, raw, path=["response"]) - - @parametrize - async def test_raw_response_get(self, async_client: AsyncCloudflare) -> None: - response = await async_client.email_security.investigate.raw.with_raw_response.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - raw = await response.parse() - assert_matches_type(RawGetResponse, raw, path=["response"]) - - @parametrize - async def test_streaming_response_get(self, async_client: AsyncCloudflare) -> None: - async with async_client.email_security.investigate.raw.with_streaming_response.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - raw = await response.parse() - assert_matches_type(RawGetResponse, raw, 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.email_security.investigate.raw.with_raw_response.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `postfix_id` but received ''"): - await async_client.email_security.investigate.raw.with_raw_response.get( - postfix_id="", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) diff --git a/tests/api_resources/email_security/investigate/test_reclassify.py b/tests/api_resources/email_security/investigate/test_reclassify.py deleted file mode 100644 index 00739cafa7f..00000000000 --- a/tests/api_resources/email_security/investigate/test_reclassify.py +++ /dev/null @@ -1,153 +0,0 @@ -# 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 pytest - -from cloudflare import Cloudflare, AsyncCloudflare -from tests.utils import assert_matches_type - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestReclassify: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: Cloudflare) -> None: - reclassify = client.email_security.investigate.reclassify.create( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - expected_disposition="NONE", - ) - assert_matches_type(object, reclassify, path=["response"]) - - @parametrize - def test_method_create_with_all_params(self, client: Cloudflare) -> None: - reclassify = client.email_security.investigate.reclassify.create( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - expected_disposition="NONE", - submission=True, - eml_content="eml_content", - escalated_submission_id="escalated_submission_id", - ) - assert_matches_type(object, reclassify, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: Cloudflare) -> None: - response = client.email_security.investigate.reclassify.with_raw_response.create( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - expected_disposition="NONE", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - reclassify = response.parse() - assert_matches_type(object, reclassify, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: Cloudflare) -> None: - with client.email_security.investigate.reclassify.with_streaming_response.create( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - expected_disposition="NONE", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - reclassify = response.parse() - assert_matches_type(object, reclassify, 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.email_security.investigate.reclassify.with_raw_response.create( - postfix_id="4Njp3P0STMz2c02Q", - account_id="", - expected_disposition="NONE", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `postfix_id` but received ''"): - client.email_security.investigate.reclassify.with_raw_response.create( - postfix_id="", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - expected_disposition="NONE", - ) - - -class TestAsyncReclassify: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncCloudflare) -> None: - reclassify = await async_client.email_security.investigate.reclassify.create( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - expected_disposition="NONE", - ) - assert_matches_type(object, reclassify, path=["response"]) - - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncCloudflare) -> None: - reclassify = await async_client.email_security.investigate.reclassify.create( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - expected_disposition="NONE", - submission=True, - eml_content="eml_content", - escalated_submission_id="escalated_submission_id", - ) - assert_matches_type(object, reclassify, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncCloudflare) -> None: - response = await async_client.email_security.investigate.reclassify.with_raw_response.create( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - expected_disposition="NONE", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - reclassify = await response.parse() - assert_matches_type(object, reclassify, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncCloudflare) -> None: - async with async_client.email_security.investigate.reclassify.with_streaming_response.create( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - expected_disposition="NONE", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - reclassify = await response.parse() - assert_matches_type(object, reclassify, 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.email_security.investigate.reclassify.with_raw_response.create( - postfix_id="4Njp3P0STMz2c02Q", - account_id="", - expected_disposition="NONE", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `postfix_id` but received ''"): - await async_client.email_security.investigate.reclassify.with_raw_response.create( - postfix_id="", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - expected_disposition="NONE", - ) diff --git a/tests/api_resources/email_security/investigate/test_release.py b/tests/api_resources/email_security/investigate/test_release.py index 44430b8c827..92555d31686 100644 --- a/tests/api_resources/email_security/investigate/test_release.py +++ b/tests/api_resources/email_security/investigate/test_release.py @@ -22,7 +22,7 @@ class TestRelease: def test_method_bulk(self, client: Cloudflare) -> None: release = client.email_security.investigate.release.bulk( account_id="023e105f4ecef8ad9ca31a8372d0c353", - body=["4Njp3P0STMz2c02Q"], + body=["4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678"], ) assert_matches_type(SyncSinglePage[ReleaseBulkResponse], release, path=["response"]) @@ -30,7 +30,7 @@ def test_method_bulk(self, client: Cloudflare) -> None: def test_raw_response_bulk(self, client: Cloudflare) -> None: response = client.email_security.investigate.release.with_raw_response.bulk( account_id="023e105f4ecef8ad9ca31a8372d0c353", - body=["4Njp3P0STMz2c02Q"], + body=["4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678"], ) assert response.is_closed is True @@ -42,7 +42,7 @@ def test_raw_response_bulk(self, client: Cloudflare) -> None: def test_streaming_response_bulk(self, client: Cloudflare) -> None: with client.email_security.investigate.release.with_streaming_response.bulk( account_id="023e105f4ecef8ad9ca31a8372d0c353", - body=["4Njp3P0STMz2c02Q"], + body=["4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678"], ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -57,7 +57,7 @@ def test_path_params_bulk(self, client: Cloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): client.email_security.investigate.release.with_raw_response.bulk( account_id="", - body=["4Njp3P0STMz2c02Q"], + body=["4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678"], ) @@ -70,7 +70,7 @@ class TestAsyncRelease: async def test_method_bulk(self, async_client: AsyncCloudflare) -> None: release = await async_client.email_security.investigate.release.bulk( account_id="023e105f4ecef8ad9ca31a8372d0c353", - body=["4Njp3P0STMz2c02Q"], + body=["4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678"], ) assert_matches_type(AsyncSinglePage[ReleaseBulkResponse], release, path=["response"]) @@ -78,7 +78,7 @@ async def test_method_bulk(self, async_client: AsyncCloudflare) -> None: async def test_raw_response_bulk(self, async_client: AsyncCloudflare) -> None: response = await async_client.email_security.investigate.release.with_raw_response.bulk( account_id="023e105f4ecef8ad9ca31a8372d0c353", - body=["4Njp3P0STMz2c02Q"], + body=["4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678"], ) assert response.is_closed is True @@ -90,7 +90,7 @@ async def test_raw_response_bulk(self, async_client: AsyncCloudflare) -> None: async def test_streaming_response_bulk(self, async_client: AsyncCloudflare) -> None: async with async_client.email_security.investigate.release.with_streaming_response.bulk( account_id="023e105f4ecef8ad9ca31a8372d0c353", - body=["4Njp3P0STMz2c02Q"], + body=["4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678"], ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -105,5 +105,5 @@ async def test_path_params_bulk(self, async_client: AsyncCloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): await async_client.email_security.investigate.release.with_raw_response.bulk( account_id="", - body=["4Njp3P0STMz2c02Q"], + body=["4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678"], ) diff --git a/tests/api_resources/email_security/investigate/test_trace.py b/tests/api_resources/email_security/investigate/test_trace.py deleted file mode 100644 index d674b118b10..00000000000 --- a/tests/api_resources/email_security/investigate/test_trace.py +++ /dev/null @@ -1,138 +0,0 @@ -# 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 pytest - -from cloudflare import Cloudflare, AsyncCloudflare -from tests.utils import assert_matches_type -from cloudflare.types.email_security.investigate import TraceGetResponse - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestTrace: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_get(self, client: Cloudflare) -> None: - trace = client.email_security.investigate.trace.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - assert_matches_type(TraceGetResponse, trace, path=["response"]) - - @parametrize - def test_method_get_with_all_params(self, client: Cloudflare) -> None: - trace = client.email_security.investigate.trace.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - submission=True, - ) - assert_matches_type(TraceGetResponse, trace, path=["response"]) - - @parametrize - def test_raw_response_get(self, client: Cloudflare) -> None: - response = client.email_security.investigate.trace.with_raw_response.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - trace = response.parse() - assert_matches_type(TraceGetResponse, trace, path=["response"]) - - @parametrize - def test_streaming_response_get(self, client: Cloudflare) -> None: - with client.email_security.investigate.trace.with_streaming_response.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - trace = response.parse() - assert_matches_type(TraceGetResponse, trace, 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.email_security.investigate.trace.with_raw_response.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `postfix_id` but received ''"): - client.email_security.investigate.trace.with_raw_response.get( - postfix_id="", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - - -class TestAsyncTrace: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_get(self, async_client: AsyncCloudflare) -> None: - trace = await async_client.email_security.investigate.trace.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - assert_matches_type(TraceGetResponse, trace, path=["response"]) - - @parametrize - async def test_method_get_with_all_params(self, async_client: AsyncCloudflare) -> None: - trace = await async_client.email_security.investigate.trace.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - submission=True, - ) - assert_matches_type(TraceGetResponse, trace, path=["response"]) - - @parametrize - async def test_raw_response_get(self, async_client: AsyncCloudflare) -> None: - response = await async_client.email_security.investigate.trace.with_raw_response.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - trace = await response.parse() - assert_matches_type(TraceGetResponse, trace, path=["response"]) - - @parametrize - async def test_streaming_response_get(self, async_client: AsyncCloudflare) -> None: - async with async_client.email_security.investigate.trace.with_streaming_response.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - trace = await response.parse() - assert_matches_type(TraceGetResponse, trace, 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.email_security.investigate.trace.with_raw_response.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `postfix_id` but received ''"): - await async_client.email_security.investigate.trace.with_raw_response.get( - postfix_id="", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) diff --git a/tests/api_resources/email_security/settings/test_allow_policies.py b/tests/api_resources/email_security/settings/test_allow_policies.py index 9957ba139f1..7ddd322bd03 100644 --- a/tests/api_resources/email_security/settings/test_allow_policies.py +++ b/tests/api_resources/email_security/settings/test_allow_policies.py @@ -3,7 +3,7 @@ from __future__ import annotations import os -from typing import Any, cast +from typing import Any, Optional, cast import pytest @@ -36,7 +36,7 @@ def test_method_create(self, client: Cloudflare) -> None: pattern_type="EMAIL", verify_sender=True, ) - assert_matches_type(AllowPolicyCreateResponse, allow_policy, path=["response"]) + assert_matches_type(Optional[AllowPolicyCreateResponse], allow_policy, path=["response"]) @parametrize def test_method_create_with_all_params(self, client: Cloudflare) -> None: @@ -54,7 +54,7 @@ def test_method_create_with_all_params(self, client: Cloudflare) -> None: is_sender=True, is_spoof=False, ) - assert_matches_type(AllowPolicyCreateResponse, allow_policy, path=["response"]) + assert_matches_type(Optional[AllowPolicyCreateResponse], allow_policy, path=["response"]) @parametrize def test_raw_response_create(self, client: Cloudflare) -> None: @@ -72,7 +72,7 @@ def test_raw_response_create(self, client: Cloudflare) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" allow_policy = response.parse() - assert_matches_type(AllowPolicyCreateResponse, allow_policy, path=["response"]) + assert_matches_type(Optional[AllowPolicyCreateResponse], allow_policy, path=["response"]) @parametrize def test_streaming_response_create(self, client: Cloudflare) -> None: @@ -90,7 +90,7 @@ def test_streaming_response_create(self, client: Cloudflare) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" allow_policy = response.parse() - assert_matches_type(AllowPolicyCreateResponse, allow_policy, path=["response"]) + assert_matches_type(Optional[AllowPolicyCreateResponse], allow_policy, path=["response"]) assert cast(Any, response.is_closed) is True @@ -122,15 +122,12 @@ def test_method_list_with_all_params(self, client: Cloudflare) -> None: direction="asc", is_acceptable_sender=True, is_exempt_recipient=True, - is_recipient=True, - is_sender=True, - is_spoof=True, is_trusted_sender=True, order="pattern", page=1, pattern="pattern", pattern_type="EMAIL", - per_page=1, + per_page=20, search="search", verify_sender=True, ) @@ -170,34 +167,34 @@ def test_path_params_list(self, client: Cloudflare) -> None: @parametrize def test_method_delete(self, client: Cloudflare) -> None: allow_policy = client.email_security.settings.allow_policies.delete( - policy_id=2401, + policy_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) - assert_matches_type(AllowPolicyDeleteResponse, allow_policy, path=["response"]) + assert_matches_type(Optional[AllowPolicyDeleteResponse], allow_policy, path=["response"]) @parametrize def test_raw_response_delete(self, client: Cloudflare) -> None: response = client.email_security.settings.allow_policies.with_raw_response.delete( - policy_id=2401, + policy_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" allow_policy = response.parse() - assert_matches_type(AllowPolicyDeleteResponse, allow_policy, path=["response"]) + assert_matches_type(Optional[AllowPolicyDeleteResponse], allow_policy, path=["response"]) @parametrize def test_streaming_response_delete(self, client: Cloudflare) -> None: with client.email_security.settings.allow_policies.with_streaming_response.delete( - policy_id=2401, + policy_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" allow_policy = response.parse() - assert_matches_type(AllowPolicyDeleteResponse, allow_policy, path=["response"]) + assert_matches_type(Optional[AllowPolicyDeleteResponse], allow_policy, path=["response"]) assert cast(Any, response.is_closed) is True @@ -205,57 +202,66 @@ def test_streaming_response_delete(self, client: Cloudflare) -> None: def test_path_params_delete(self, client: Cloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): client.email_security.settings.allow_policies.with_raw_response.delete( - policy_id=2401, + policy_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="", ) + with pytest.raises(ValueError, match=r"Expected a non-empty value for `policy_id` but received ''"): + client.email_security.settings.allow_policies.with_raw_response.delete( + policy_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + @parametrize def test_method_edit(self, client: Cloudflare) -> None: allow_policy = client.email_security.settings.allow_policies.edit( - policy_id=2401, + policy_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) - assert_matches_type(AllowPolicyEditResponse, allow_policy, path=["response"]) + assert_matches_type(Optional[AllowPolicyEditResponse], allow_policy, path=["response"]) @parametrize def test_method_edit_with_all_params(self, client: Cloudflare) -> None: allow_policy = client.email_security.settings.allow_policies.edit( - policy_id=2401, + policy_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", - comments="comments", - is_acceptable_sender=True, - is_exempt_recipient=True, - is_regex=True, + comments="Trust all messages send from test@example.com", + is_acceptable_sender=False, + is_exempt_recipient=False, + is_recipient=False, + is_regex=False, + is_sender=True, + is_spoof=False, is_trusted_sender=True, - pattern="x", + pattern="test@example.com", pattern_type="EMAIL", verify_sender=True, ) - assert_matches_type(AllowPolicyEditResponse, allow_policy, path=["response"]) + assert_matches_type(Optional[AllowPolicyEditResponse], allow_policy, path=["response"]) @parametrize def test_raw_response_edit(self, client: Cloudflare) -> None: response = client.email_security.settings.allow_policies.with_raw_response.edit( - policy_id=2401, + policy_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" allow_policy = response.parse() - assert_matches_type(AllowPolicyEditResponse, allow_policy, path=["response"]) + assert_matches_type(Optional[AllowPolicyEditResponse], allow_policy, path=["response"]) @parametrize def test_streaming_response_edit(self, client: Cloudflare) -> None: with client.email_security.settings.allow_policies.with_streaming_response.edit( - policy_id=2401, + policy_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" allow_policy = response.parse() - assert_matches_type(AllowPolicyEditResponse, allow_policy, path=["response"]) + assert_matches_type(Optional[AllowPolicyEditResponse], allow_policy, path=["response"]) assert cast(Any, response.is_closed) is True @@ -263,41 +269,47 @@ def test_streaming_response_edit(self, client: Cloudflare) -> None: def test_path_params_edit(self, client: Cloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): client.email_security.settings.allow_policies.with_raw_response.edit( - policy_id=2401, + policy_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="", ) + with pytest.raises(ValueError, match=r"Expected a non-empty value for `policy_id` but received ''"): + client.email_security.settings.allow_policies.with_raw_response.edit( + policy_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + @parametrize def test_method_get(self, client: Cloudflare) -> None: allow_policy = client.email_security.settings.allow_policies.get( - policy_id=2401, + policy_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) - assert_matches_type(AllowPolicyGetResponse, allow_policy, path=["response"]) + assert_matches_type(Optional[AllowPolicyGetResponse], allow_policy, path=["response"]) @parametrize def test_raw_response_get(self, client: Cloudflare) -> None: response = client.email_security.settings.allow_policies.with_raw_response.get( - policy_id=2401, + policy_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" allow_policy = response.parse() - assert_matches_type(AllowPolicyGetResponse, allow_policy, path=["response"]) + assert_matches_type(Optional[AllowPolicyGetResponse], allow_policy, path=["response"]) @parametrize def test_streaming_response_get(self, client: Cloudflare) -> None: with client.email_security.settings.allow_policies.with_streaming_response.get( - policy_id=2401, + policy_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" allow_policy = response.parse() - assert_matches_type(AllowPolicyGetResponse, allow_policy, path=["response"]) + assert_matches_type(Optional[AllowPolicyGetResponse], allow_policy, path=["response"]) assert cast(Any, response.is_closed) is True @@ -305,10 +317,16 @@ def test_streaming_response_get(self, client: Cloudflare) -> None: 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.email_security.settings.allow_policies.with_raw_response.get( - policy_id=2401, + policy_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="", ) + with pytest.raises(ValueError, match=r"Expected a non-empty value for `policy_id` but received ''"): + client.email_security.settings.allow_policies.with_raw_response.get( + policy_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + class TestAsyncAllowPolicies: parametrize = pytest.mark.parametrize( @@ -327,7 +345,7 @@ async def test_method_create(self, async_client: AsyncCloudflare) -> None: pattern_type="EMAIL", verify_sender=True, ) - assert_matches_type(AllowPolicyCreateResponse, allow_policy, path=["response"]) + assert_matches_type(Optional[AllowPolicyCreateResponse], allow_policy, path=["response"]) @parametrize async def test_method_create_with_all_params(self, async_client: AsyncCloudflare) -> None: @@ -345,7 +363,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncCloudflare is_sender=True, is_spoof=False, ) - assert_matches_type(AllowPolicyCreateResponse, allow_policy, path=["response"]) + assert_matches_type(Optional[AllowPolicyCreateResponse], allow_policy, path=["response"]) @parametrize async def test_raw_response_create(self, async_client: AsyncCloudflare) -> None: @@ -363,7 +381,7 @@ async def test_raw_response_create(self, async_client: AsyncCloudflare) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" allow_policy = await response.parse() - assert_matches_type(AllowPolicyCreateResponse, allow_policy, path=["response"]) + assert_matches_type(Optional[AllowPolicyCreateResponse], allow_policy, path=["response"]) @parametrize async def test_streaming_response_create(self, async_client: AsyncCloudflare) -> None: @@ -381,7 +399,7 @@ async def test_streaming_response_create(self, async_client: AsyncCloudflare) -> assert response.http_request.headers.get("X-Stainless-Lang") == "python" allow_policy = await response.parse() - assert_matches_type(AllowPolicyCreateResponse, allow_policy, path=["response"]) + assert_matches_type(Optional[AllowPolicyCreateResponse], allow_policy, path=["response"]) assert cast(Any, response.is_closed) is True @@ -413,15 +431,12 @@ async def test_method_list_with_all_params(self, async_client: AsyncCloudflare) direction="asc", is_acceptable_sender=True, is_exempt_recipient=True, - is_recipient=True, - is_sender=True, - is_spoof=True, is_trusted_sender=True, order="pattern", page=1, pattern="pattern", pattern_type="EMAIL", - per_page=1, + per_page=20, search="search", verify_sender=True, ) @@ -461,34 +476,34 @@ async def test_path_params_list(self, async_client: AsyncCloudflare) -> None: @parametrize async def test_method_delete(self, async_client: AsyncCloudflare) -> None: allow_policy = await async_client.email_security.settings.allow_policies.delete( - policy_id=2401, + policy_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) - assert_matches_type(AllowPolicyDeleteResponse, allow_policy, path=["response"]) + assert_matches_type(Optional[AllowPolicyDeleteResponse], allow_policy, path=["response"]) @parametrize async def test_raw_response_delete(self, async_client: AsyncCloudflare) -> None: response = await async_client.email_security.settings.allow_policies.with_raw_response.delete( - policy_id=2401, + policy_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" allow_policy = await response.parse() - assert_matches_type(AllowPolicyDeleteResponse, allow_policy, path=["response"]) + assert_matches_type(Optional[AllowPolicyDeleteResponse], allow_policy, path=["response"]) @parametrize async def test_streaming_response_delete(self, async_client: AsyncCloudflare) -> None: async with async_client.email_security.settings.allow_policies.with_streaming_response.delete( - policy_id=2401, + policy_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" allow_policy = await response.parse() - assert_matches_type(AllowPolicyDeleteResponse, allow_policy, path=["response"]) + assert_matches_type(Optional[AllowPolicyDeleteResponse], allow_policy, path=["response"]) assert cast(Any, response.is_closed) is True @@ -496,57 +511,66 @@ async def test_streaming_response_delete(self, async_client: AsyncCloudflare) -> async def test_path_params_delete(self, async_client: AsyncCloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): await async_client.email_security.settings.allow_policies.with_raw_response.delete( - policy_id=2401, + policy_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="", ) + with pytest.raises(ValueError, match=r"Expected a non-empty value for `policy_id` but received ''"): + await async_client.email_security.settings.allow_policies.with_raw_response.delete( + policy_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + @parametrize async def test_method_edit(self, async_client: AsyncCloudflare) -> None: allow_policy = await async_client.email_security.settings.allow_policies.edit( - policy_id=2401, + policy_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) - assert_matches_type(AllowPolicyEditResponse, allow_policy, path=["response"]) + assert_matches_type(Optional[AllowPolicyEditResponse], allow_policy, path=["response"]) @parametrize async def test_method_edit_with_all_params(self, async_client: AsyncCloudflare) -> None: allow_policy = await async_client.email_security.settings.allow_policies.edit( - policy_id=2401, + policy_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", - comments="comments", - is_acceptable_sender=True, - is_exempt_recipient=True, - is_regex=True, + comments="Trust all messages send from test@example.com", + is_acceptable_sender=False, + is_exempt_recipient=False, + is_recipient=False, + is_regex=False, + is_sender=True, + is_spoof=False, is_trusted_sender=True, - pattern="x", + pattern="test@example.com", pattern_type="EMAIL", verify_sender=True, ) - assert_matches_type(AllowPolicyEditResponse, allow_policy, path=["response"]) + assert_matches_type(Optional[AllowPolicyEditResponse], allow_policy, path=["response"]) @parametrize async def test_raw_response_edit(self, async_client: AsyncCloudflare) -> None: response = await async_client.email_security.settings.allow_policies.with_raw_response.edit( - policy_id=2401, + policy_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" allow_policy = await response.parse() - assert_matches_type(AllowPolicyEditResponse, allow_policy, path=["response"]) + assert_matches_type(Optional[AllowPolicyEditResponse], allow_policy, path=["response"]) @parametrize async def test_streaming_response_edit(self, async_client: AsyncCloudflare) -> None: async with async_client.email_security.settings.allow_policies.with_streaming_response.edit( - policy_id=2401, + policy_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" allow_policy = await response.parse() - assert_matches_type(AllowPolicyEditResponse, allow_policy, path=["response"]) + assert_matches_type(Optional[AllowPolicyEditResponse], allow_policy, path=["response"]) assert cast(Any, response.is_closed) is True @@ -554,41 +578,47 @@ async def test_streaming_response_edit(self, async_client: AsyncCloudflare) -> N async def test_path_params_edit(self, async_client: AsyncCloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): await async_client.email_security.settings.allow_policies.with_raw_response.edit( - policy_id=2401, + policy_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="", ) + with pytest.raises(ValueError, match=r"Expected a non-empty value for `policy_id` but received ''"): + await async_client.email_security.settings.allow_policies.with_raw_response.edit( + policy_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + @parametrize async def test_method_get(self, async_client: AsyncCloudflare) -> None: allow_policy = await async_client.email_security.settings.allow_policies.get( - policy_id=2401, + policy_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) - assert_matches_type(AllowPolicyGetResponse, allow_policy, path=["response"]) + assert_matches_type(Optional[AllowPolicyGetResponse], allow_policy, path=["response"]) @parametrize async def test_raw_response_get(self, async_client: AsyncCloudflare) -> None: response = await async_client.email_security.settings.allow_policies.with_raw_response.get( - policy_id=2401, + policy_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" allow_policy = await response.parse() - assert_matches_type(AllowPolicyGetResponse, allow_policy, path=["response"]) + assert_matches_type(Optional[AllowPolicyGetResponse], allow_policy, path=["response"]) @parametrize async def test_streaming_response_get(self, async_client: AsyncCloudflare) -> None: async with async_client.email_security.settings.allow_policies.with_streaming_response.get( - policy_id=2401, + policy_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" allow_policy = await response.parse() - assert_matches_type(AllowPolicyGetResponse, allow_policy, path=["response"]) + assert_matches_type(Optional[AllowPolicyGetResponse], allow_policy, path=["response"]) assert cast(Any, response.is_closed) is True @@ -596,6 +626,12 @@ async def test_streaming_response_get(self, async_client: AsyncCloudflare) -> No 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.email_security.settings.allow_policies.with_raw_response.get( - policy_id=2401, + policy_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="", ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `policy_id` but received ''"): + await async_client.email_security.settings.allow_policies.with_raw_response.get( + policy_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) diff --git a/tests/api_resources/email_security/settings/test_block_senders.py b/tests/api_resources/email_security/settings/test_block_senders.py index f2611adf7dd..aa4176eef0b 100644 --- a/tests/api_resources/email_security/settings/test_block_senders.py +++ b/tests/api_resources/email_security/settings/test_block_senders.py @@ -3,7 +3,7 @@ from __future__ import annotations import os -from typing import Any, cast +from typing import Any, Optional, cast import pytest @@ -32,7 +32,7 @@ def test_method_create(self, client: Cloudflare) -> None: pattern="test@example.com", pattern_type="EMAIL", ) - assert_matches_type(BlockSenderCreateResponse, block_sender, path=["response"]) + assert_matches_type(Optional[BlockSenderCreateResponse], block_sender, path=["response"]) @parametrize def test_method_create_with_all_params(self, client: Cloudflare) -> None: @@ -41,9 +41,9 @@ def test_method_create_with_all_params(self, client: Cloudflare) -> None: is_regex=False, pattern="test@example.com", pattern_type="EMAIL", - comments="block sender with email test@example.com", + comments="Block sender with email test@example.com", ) - assert_matches_type(BlockSenderCreateResponse, block_sender, path=["response"]) + assert_matches_type(Optional[BlockSenderCreateResponse], block_sender, path=["response"]) @parametrize def test_raw_response_create(self, client: Cloudflare) -> None: @@ -57,7 +57,7 @@ def test_raw_response_create(self, client: Cloudflare) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" block_sender = response.parse() - assert_matches_type(BlockSenderCreateResponse, block_sender, path=["response"]) + assert_matches_type(Optional[BlockSenderCreateResponse], block_sender, path=["response"]) @parametrize def test_streaming_response_create(self, client: Cloudflare) -> None: @@ -71,7 +71,7 @@ def test_streaming_response_create(self, client: Cloudflare) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" block_sender = response.parse() - assert_matches_type(BlockSenderCreateResponse, block_sender, path=["response"]) + assert_matches_type(Optional[BlockSenderCreateResponse], block_sender, path=["response"]) assert cast(Any, response.is_closed) is True @@ -101,7 +101,7 @@ def test_method_list_with_all_params(self, client: Cloudflare) -> None: page=1, pattern="pattern", pattern_type="EMAIL", - per_page=1, + per_page=20, search="search", ) assert_matches_type(SyncV4PagePaginationArray[BlockSenderListResponse], block_sender, path=["response"]) @@ -140,34 +140,34 @@ def test_path_params_list(self, client: Cloudflare) -> None: @parametrize def test_method_delete(self, client: Cloudflare) -> None: block_sender = client.email_security.settings.block_senders.delete( - pattern_id=2402, + pattern_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) - assert_matches_type(BlockSenderDeleteResponse, block_sender, path=["response"]) + assert_matches_type(Optional[BlockSenderDeleteResponse], block_sender, path=["response"]) @parametrize def test_raw_response_delete(self, client: Cloudflare) -> None: response = client.email_security.settings.block_senders.with_raw_response.delete( - pattern_id=2402, + pattern_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" block_sender = response.parse() - assert_matches_type(BlockSenderDeleteResponse, block_sender, path=["response"]) + assert_matches_type(Optional[BlockSenderDeleteResponse], block_sender, path=["response"]) @parametrize def test_streaming_response_delete(self, client: Cloudflare) -> None: with client.email_security.settings.block_senders.with_streaming_response.delete( - pattern_id=2402, + pattern_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" block_sender = response.parse() - assert_matches_type(BlockSenderDeleteResponse, block_sender, path=["response"]) + assert_matches_type(Optional[BlockSenderDeleteResponse], block_sender, path=["response"]) assert cast(Any, response.is_closed) is True @@ -175,53 +175,59 @@ def test_streaming_response_delete(self, client: Cloudflare) -> None: def test_path_params_delete(self, client: Cloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): client.email_security.settings.block_senders.with_raw_response.delete( - pattern_id=2402, + pattern_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="", ) + with pytest.raises(ValueError, match=r"Expected a non-empty value for `pattern_id` but received ''"): + client.email_security.settings.block_senders.with_raw_response.delete( + pattern_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + @parametrize def test_method_edit(self, client: Cloudflare) -> None: block_sender = client.email_security.settings.block_senders.edit( - pattern_id=2402, + pattern_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) - assert_matches_type(BlockSenderEditResponse, block_sender, path=["response"]) + assert_matches_type(Optional[BlockSenderEditResponse], block_sender, path=["response"]) @parametrize def test_method_edit_with_all_params(self, client: Cloudflare) -> None: block_sender = client.email_security.settings.block_senders.edit( - pattern_id=2402, + pattern_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", - comments="comments", - is_regex=True, - pattern="x", + comments="Block sender with email test@example.com", + is_regex=False, + pattern="test@example.com", pattern_type="EMAIL", ) - assert_matches_type(BlockSenderEditResponse, block_sender, path=["response"]) + assert_matches_type(Optional[BlockSenderEditResponse], block_sender, path=["response"]) @parametrize def test_raw_response_edit(self, client: Cloudflare) -> None: response = client.email_security.settings.block_senders.with_raw_response.edit( - pattern_id=2402, + pattern_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" block_sender = response.parse() - assert_matches_type(BlockSenderEditResponse, block_sender, path=["response"]) + assert_matches_type(Optional[BlockSenderEditResponse], block_sender, path=["response"]) @parametrize def test_streaming_response_edit(self, client: Cloudflare) -> None: with client.email_security.settings.block_senders.with_streaming_response.edit( - pattern_id=2402, + pattern_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" block_sender = response.parse() - assert_matches_type(BlockSenderEditResponse, block_sender, path=["response"]) + assert_matches_type(Optional[BlockSenderEditResponse], block_sender, path=["response"]) assert cast(Any, response.is_closed) is True @@ -229,41 +235,47 @@ def test_streaming_response_edit(self, client: Cloudflare) -> None: def test_path_params_edit(self, client: Cloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): client.email_security.settings.block_senders.with_raw_response.edit( - pattern_id=2402, + pattern_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="", ) + with pytest.raises(ValueError, match=r"Expected a non-empty value for `pattern_id` but received ''"): + client.email_security.settings.block_senders.with_raw_response.edit( + pattern_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + @parametrize def test_method_get(self, client: Cloudflare) -> None: block_sender = client.email_security.settings.block_senders.get( - pattern_id=2402, + pattern_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) - assert_matches_type(BlockSenderGetResponse, block_sender, path=["response"]) + assert_matches_type(Optional[BlockSenderGetResponse], block_sender, path=["response"]) @parametrize def test_raw_response_get(self, client: Cloudflare) -> None: response = client.email_security.settings.block_senders.with_raw_response.get( - pattern_id=2402, + pattern_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" block_sender = response.parse() - assert_matches_type(BlockSenderGetResponse, block_sender, path=["response"]) + assert_matches_type(Optional[BlockSenderGetResponse], block_sender, path=["response"]) @parametrize def test_streaming_response_get(self, client: Cloudflare) -> None: with client.email_security.settings.block_senders.with_streaming_response.get( - pattern_id=2402, + pattern_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" block_sender = response.parse() - assert_matches_type(BlockSenderGetResponse, block_sender, path=["response"]) + assert_matches_type(Optional[BlockSenderGetResponse], block_sender, path=["response"]) assert cast(Any, response.is_closed) is True @@ -271,10 +283,16 @@ def test_streaming_response_get(self, client: Cloudflare) -> None: 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.email_security.settings.block_senders.with_raw_response.get( - pattern_id=2402, + pattern_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="", ) + with pytest.raises(ValueError, match=r"Expected a non-empty value for `pattern_id` but received ''"): + client.email_security.settings.block_senders.with_raw_response.get( + pattern_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + class TestAsyncBlockSenders: parametrize = pytest.mark.parametrize( @@ -289,7 +307,7 @@ async def test_method_create(self, async_client: AsyncCloudflare) -> None: pattern="test@example.com", pattern_type="EMAIL", ) - assert_matches_type(BlockSenderCreateResponse, block_sender, path=["response"]) + assert_matches_type(Optional[BlockSenderCreateResponse], block_sender, path=["response"]) @parametrize async def test_method_create_with_all_params(self, async_client: AsyncCloudflare) -> None: @@ -298,9 +316,9 @@ async def test_method_create_with_all_params(self, async_client: AsyncCloudflare is_regex=False, pattern="test@example.com", pattern_type="EMAIL", - comments="block sender with email test@example.com", + comments="Block sender with email test@example.com", ) - assert_matches_type(BlockSenderCreateResponse, block_sender, path=["response"]) + assert_matches_type(Optional[BlockSenderCreateResponse], block_sender, path=["response"]) @parametrize async def test_raw_response_create(self, async_client: AsyncCloudflare) -> None: @@ -314,7 +332,7 @@ async def test_raw_response_create(self, async_client: AsyncCloudflare) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" block_sender = await response.parse() - assert_matches_type(BlockSenderCreateResponse, block_sender, path=["response"]) + assert_matches_type(Optional[BlockSenderCreateResponse], block_sender, path=["response"]) @parametrize async def test_streaming_response_create(self, async_client: AsyncCloudflare) -> None: @@ -328,7 +346,7 @@ async def test_streaming_response_create(self, async_client: AsyncCloudflare) -> assert response.http_request.headers.get("X-Stainless-Lang") == "python" block_sender = await response.parse() - assert_matches_type(BlockSenderCreateResponse, block_sender, path=["response"]) + assert_matches_type(Optional[BlockSenderCreateResponse], block_sender, path=["response"]) assert cast(Any, response.is_closed) is True @@ -358,7 +376,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncCloudflare) page=1, pattern="pattern", pattern_type="EMAIL", - per_page=1, + per_page=20, search="search", ) assert_matches_type(AsyncV4PagePaginationArray[BlockSenderListResponse], block_sender, path=["response"]) @@ -397,34 +415,34 @@ async def test_path_params_list(self, async_client: AsyncCloudflare) -> None: @parametrize async def test_method_delete(self, async_client: AsyncCloudflare) -> None: block_sender = await async_client.email_security.settings.block_senders.delete( - pattern_id=2402, + pattern_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) - assert_matches_type(BlockSenderDeleteResponse, block_sender, path=["response"]) + assert_matches_type(Optional[BlockSenderDeleteResponse], block_sender, path=["response"]) @parametrize async def test_raw_response_delete(self, async_client: AsyncCloudflare) -> None: response = await async_client.email_security.settings.block_senders.with_raw_response.delete( - pattern_id=2402, + pattern_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" block_sender = await response.parse() - assert_matches_type(BlockSenderDeleteResponse, block_sender, path=["response"]) + assert_matches_type(Optional[BlockSenderDeleteResponse], block_sender, path=["response"]) @parametrize async def test_streaming_response_delete(self, async_client: AsyncCloudflare) -> None: async with async_client.email_security.settings.block_senders.with_streaming_response.delete( - pattern_id=2402, + pattern_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" block_sender = await response.parse() - assert_matches_type(BlockSenderDeleteResponse, block_sender, path=["response"]) + assert_matches_type(Optional[BlockSenderDeleteResponse], block_sender, path=["response"]) assert cast(Any, response.is_closed) is True @@ -432,53 +450,59 @@ async def test_streaming_response_delete(self, async_client: AsyncCloudflare) -> async def test_path_params_delete(self, async_client: AsyncCloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): await async_client.email_security.settings.block_senders.with_raw_response.delete( - pattern_id=2402, + pattern_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="", ) + with pytest.raises(ValueError, match=r"Expected a non-empty value for `pattern_id` but received ''"): + await async_client.email_security.settings.block_senders.with_raw_response.delete( + pattern_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + @parametrize async def test_method_edit(self, async_client: AsyncCloudflare) -> None: block_sender = await async_client.email_security.settings.block_senders.edit( - pattern_id=2402, + pattern_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) - assert_matches_type(BlockSenderEditResponse, block_sender, path=["response"]) + assert_matches_type(Optional[BlockSenderEditResponse], block_sender, path=["response"]) @parametrize async def test_method_edit_with_all_params(self, async_client: AsyncCloudflare) -> None: block_sender = await async_client.email_security.settings.block_senders.edit( - pattern_id=2402, + pattern_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", - comments="comments", - is_regex=True, - pattern="x", + comments="Block sender with email test@example.com", + is_regex=False, + pattern="test@example.com", pattern_type="EMAIL", ) - assert_matches_type(BlockSenderEditResponse, block_sender, path=["response"]) + assert_matches_type(Optional[BlockSenderEditResponse], block_sender, path=["response"]) @parametrize async def test_raw_response_edit(self, async_client: AsyncCloudflare) -> None: response = await async_client.email_security.settings.block_senders.with_raw_response.edit( - pattern_id=2402, + pattern_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" block_sender = await response.parse() - assert_matches_type(BlockSenderEditResponse, block_sender, path=["response"]) + assert_matches_type(Optional[BlockSenderEditResponse], block_sender, path=["response"]) @parametrize async def test_streaming_response_edit(self, async_client: AsyncCloudflare) -> None: async with async_client.email_security.settings.block_senders.with_streaming_response.edit( - pattern_id=2402, + pattern_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" block_sender = await response.parse() - assert_matches_type(BlockSenderEditResponse, block_sender, path=["response"]) + assert_matches_type(Optional[BlockSenderEditResponse], block_sender, path=["response"]) assert cast(Any, response.is_closed) is True @@ -486,41 +510,47 @@ async def test_streaming_response_edit(self, async_client: AsyncCloudflare) -> N async def test_path_params_edit(self, async_client: AsyncCloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): await async_client.email_security.settings.block_senders.with_raw_response.edit( - pattern_id=2402, + pattern_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="", ) + with pytest.raises(ValueError, match=r"Expected a non-empty value for `pattern_id` but received ''"): + await async_client.email_security.settings.block_senders.with_raw_response.edit( + pattern_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + @parametrize async def test_method_get(self, async_client: AsyncCloudflare) -> None: block_sender = await async_client.email_security.settings.block_senders.get( - pattern_id=2402, + pattern_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) - assert_matches_type(BlockSenderGetResponse, block_sender, path=["response"]) + assert_matches_type(Optional[BlockSenderGetResponse], block_sender, path=["response"]) @parametrize async def test_raw_response_get(self, async_client: AsyncCloudflare) -> None: response = await async_client.email_security.settings.block_senders.with_raw_response.get( - pattern_id=2402, + pattern_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" block_sender = await response.parse() - assert_matches_type(BlockSenderGetResponse, block_sender, path=["response"]) + assert_matches_type(Optional[BlockSenderGetResponse], block_sender, path=["response"]) @parametrize async def test_streaming_response_get(self, async_client: AsyncCloudflare) -> None: async with async_client.email_security.settings.block_senders.with_streaming_response.get( - pattern_id=2402, + pattern_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" block_sender = await response.parse() - assert_matches_type(BlockSenderGetResponse, block_sender, path=["response"]) + assert_matches_type(Optional[BlockSenderGetResponse], block_sender, path=["response"]) assert cast(Any, response.is_closed) is True @@ -528,6 +558,12 @@ async def test_streaming_response_get(self, async_client: AsyncCloudflare) -> No 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.email_security.settings.block_senders.with_raw_response.get( - pattern_id=2402, + pattern_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="", ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `pattern_id` but received ''"): + await async_client.email_security.settings.block_senders.with_raw_response.get( + pattern_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) diff --git a/tests/api_resources/email_security/settings/test_domains.py b/tests/api_resources/email_security/settings/test_domains.py index f7a0c73a988..2336b6321de 100644 --- a/tests/api_resources/email_security/settings/test_domains.py +++ b/tests/api_resources/email_security/settings/test_domains.py @@ -3,19 +3,18 @@ from __future__ import annotations import os -from typing import Any, cast +from typing import Any, Optional, cast import pytest from cloudflare import Cloudflare, AsyncCloudflare from tests.utils import assert_matches_type -from cloudflare.pagination import SyncSinglePage, AsyncSinglePage, SyncV4PagePaginationArray, AsyncV4PagePaginationArray +from cloudflare.pagination import SyncV4PagePaginationArray, AsyncV4PagePaginationArray from cloudflare.types.email_security.settings import ( DomainGetResponse, DomainEditResponse, DomainListResponse, DomainDeleteResponse, - DomainBulkDeleteResponse, ) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -42,8 +41,9 @@ def test_method_list_with_all_params(self, client: Cloudflare) -> None: integration_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", order="domain", page=1, - per_page=1, + per_page=20, search="search", + status="pending", ) assert_matches_type(SyncV4PagePaginationArray[DomainListResponse], domain, path=["response"]) @@ -81,34 +81,34 @@ def test_path_params_list(self, client: Cloudflare) -> None: @parametrize def test_method_delete(self, client: Cloudflare) -> None: domain = client.email_security.settings.domains.delete( - domain_id=2400, + domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) - assert_matches_type(DomainDeleteResponse, domain, path=["response"]) + assert_matches_type(Optional[DomainDeleteResponse], domain, path=["response"]) @parametrize def test_raw_response_delete(self, client: Cloudflare) -> None: response = client.email_security.settings.domains.with_raw_response.delete( - domain_id=2400, + domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" domain = response.parse() - assert_matches_type(DomainDeleteResponse, domain, path=["response"]) + assert_matches_type(Optional[DomainDeleteResponse], domain, path=["response"]) @parametrize def test_streaming_response_delete(self, client: Cloudflare) -> None: with client.email_security.settings.domains.with_streaming_response.delete( - domain_id=2400, + domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" domain = response.parse() - assert_matches_type(DomainDeleteResponse, domain, path=["response"]) + assert_matches_type(Optional[DomainDeleteResponse], domain, path=["response"]) assert cast(Any, response.is_closed) is True @@ -116,101 +116,66 @@ def test_streaming_response_delete(self, client: Cloudflare) -> None: def test_path_params_delete(self, client: Cloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): client.email_security.settings.domains.with_raw_response.delete( - domain_id=2400, + domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="", ) - @parametrize - def test_method_bulk_delete(self, client: Cloudflare) -> None: - domain = client.email_security.settings.domains.bulk_delete( - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - assert_matches_type(SyncSinglePage[DomainBulkDeleteResponse], domain, path=["response"]) - - @parametrize - def test_raw_response_bulk_delete(self, client: Cloudflare) -> None: - response = client.email_security.settings.domains.with_raw_response.bulk_delete( - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - domain = response.parse() - assert_matches_type(SyncSinglePage[DomainBulkDeleteResponse], domain, path=["response"]) - - @parametrize - def test_streaming_response_bulk_delete(self, client: Cloudflare) -> None: - with client.email_security.settings.domains.with_streaming_response.bulk_delete( - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - domain = response.parse() - assert_matches_type(SyncSinglePage[DomainBulkDeleteResponse], domain, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_bulk_delete(self, client: Cloudflare) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): - client.email_security.settings.domains.with_raw_response.bulk_delete( - account_id="", + with pytest.raises(ValueError, match=r"Expected a non-empty value for `domain_id` but received ''"): + client.email_security.settings.domains.with_raw_response.delete( + domain_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", ) @parametrize def test_method_edit(self, client: Cloudflare) -> None: domain = client.email_security.settings.domains.edit( - domain_id=2400, + domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", - ip_restrictions=["192.0.2.0/24", "2001:db8::/32"], ) - assert_matches_type(DomainEditResponse, domain, path=["response"]) + assert_matches_type(Optional[DomainEditResponse], domain, path=["response"]) @parametrize def test_method_edit_with_all_params(self, client: Cloudflare) -> None: domain = client.email_security.settings.domains.edit( - domain_id=2400, + domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", - ip_restrictions=["192.0.2.0/24", "2001:db8::/32"], allowed_delivery_modes=["DIRECT"], domain="domain", drop_dispositions=["MALICIOUS"], folder="AllItems", integration_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ip_restrictions=["192.0.2.0/24", "2001:db8::/32"], lookback_hops=1, regions=["GLOBAL"], require_tls_inbound=True, require_tls_outbound=True, transport="transport", ) - assert_matches_type(DomainEditResponse, domain, path=["response"]) + assert_matches_type(Optional[DomainEditResponse], domain, path=["response"]) @parametrize def test_raw_response_edit(self, client: Cloudflare) -> None: response = client.email_security.settings.domains.with_raw_response.edit( - domain_id=2400, + domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", - ip_restrictions=["192.0.2.0/24", "2001:db8::/32"], ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" domain = response.parse() - assert_matches_type(DomainEditResponse, domain, path=["response"]) + assert_matches_type(Optional[DomainEditResponse], domain, path=["response"]) @parametrize def test_streaming_response_edit(self, client: Cloudflare) -> None: with client.email_security.settings.domains.with_streaming_response.edit( - domain_id=2400, + domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", - ip_restrictions=["192.0.2.0/24", "2001:db8::/32"], ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" domain = response.parse() - assert_matches_type(DomainEditResponse, domain, path=["response"]) + assert_matches_type(Optional[DomainEditResponse], domain, path=["response"]) assert cast(Any, response.is_closed) is True @@ -218,42 +183,47 @@ def test_streaming_response_edit(self, client: Cloudflare) -> None: def test_path_params_edit(self, client: Cloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): client.email_security.settings.domains.with_raw_response.edit( - domain_id=2400, + domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="", - ip_restrictions=["192.0.2.0/24", "2001:db8::/32"], + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `domain_id` but received ''"): + client.email_security.settings.domains.with_raw_response.edit( + domain_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", ) @parametrize def test_method_get(self, client: Cloudflare) -> None: domain = client.email_security.settings.domains.get( - domain_id=2400, + domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) - assert_matches_type(DomainGetResponse, domain, path=["response"]) + assert_matches_type(Optional[DomainGetResponse], domain, path=["response"]) @parametrize def test_raw_response_get(self, client: Cloudflare) -> None: response = client.email_security.settings.domains.with_raw_response.get( - domain_id=2400, + domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" domain = response.parse() - assert_matches_type(DomainGetResponse, domain, path=["response"]) + assert_matches_type(Optional[DomainGetResponse], domain, path=["response"]) @parametrize def test_streaming_response_get(self, client: Cloudflare) -> None: with client.email_security.settings.domains.with_streaming_response.get( - domain_id=2400, + domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" domain = response.parse() - assert_matches_type(DomainGetResponse, domain, path=["response"]) + assert_matches_type(Optional[DomainGetResponse], domain, path=["response"]) assert cast(Any, response.is_closed) is True @@ -261,10 +231,16 @@ def test_streaming_response_get(self, client: Cloudflare) -> None: 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.email_security.settings.domains.with_raw_response.get( - domain_id=2400, + domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="", ) + with pytest.raises(ValueError, match=r"Expected a non-empty value for `domain_id` but received ''"): + client.email_security.settings.domains.with_raw_response.get( + domain_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + class TestAsyncDomains: parametrize = pytest.mark.parametrize( @@ -289,8 +265,9 @@ async def test_method_list_with_all_params(self, async_client: AsyncCloudflare) integration_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", order="domain", page=1, - per_page=1, + per_page=20, search="search", + status="pending", ) assert_matches_type(AsyncV4PagePaginationArray[DomainListResponse], domain, path=["response"]) @@ -328,34 +305,34 @@ async def test_path_params_list(self, async_client: AsyncCloudflare) -> None: @parametrize async def test_method_delete(self, async_client: AsyncCloudflare) -> None: domain = await async_client.email_security.settings.domains.delete( - domain_id=2400, + domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) - assert_matches_type(DomainDeleteResponse, domain, path=["response"]) + assert_matches_type(Optional[DomainDeleteResponse], domain, path=["response"]) @parametrize async def test_raw_response_delete(self, async_client: AsyncCloudflare) -> None: response = await async_client.email_security.settings.domains.with_raw_response.delete( - domain_id=2400, + domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" domain = await response.parse() - assert_matches_type(DomainDeleteResponse, domain, path=["response"]) + assert_matches_type(Optional[DomainDeleteResponse], domain, path=["response"]) @parametrize async def test_streaming_response_delete(self, async_client: AsyncCloudflare) -> None: async with async_client.email_security.settings.domains.with_streaming_response.delete( - domain_id=2400, + domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" domain = await response.parse() - assert_matches_type(DomainDeleteResponse, domain, path=["response"]) + assert_matches_type(Optional[DomainDeleteResponse], domain, path=["response"]) assert cast(Any, response.is_closed) is True @@ -363,101 +340,66 @@ async def test_streaming_response_delete(self, async_client: AsyncCloudflare) -> async def test_path_params_delete(self, async_client: AsyncCloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): await async_client.email_security.settings.domains.with_raw_response.delete( - domain_id=2400, + domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="", ) - @parametrize - async def test_method_bulk_delete(self, async_client: AsyncCloudflare) -> None: - domain = await async_client.email_security.settings.domains.bulk_delete( - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - assert_matches_type(AsyncSinglePage[DomainBulkDeleteResponse], domain, path=["response"]) - - @parametrize - async def test_raw_response_bulk_delete(self, async_client: AsyncCloudflare) -> None: - response = await async_client.email_security.settings.domains.with_raw_response.bulk_delete( - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - domain = await response.parse() - assert_matches_type(AsyncSinglePage[DomainBulkDeleteResponse], domain, path=["response"]) - - @parametrize - async def test_streaming_response_bulk_delete(self, async_client: AsyncCloudflare) -> None: - async with async_client.email_security.settings.domains.with_streaming_response.bulk_delete( - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - domain = await response.parse() - assert_matches_type(AsyncSinglePage[DomainBulkDeleteResponse], domain, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_bulk_delete(self, async_client: AsyncCloudflare) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): - await async_client.email_security.settings.domains.with_raw_response.bulk_delete( - account_id="", + with pytest.raises(ValueError, match=r"Expected a non-empty value for `domain_id` but received ''"): + await async_client.email_security.settings.domains.with_raw_response.delete( + domain_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", ) @parametrize async def test_method_edit(self, async_client: AsyncCloudflare) -> None: domain = await async_client.email_security.settings.domains.edit( - domain_id=2400, + domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", - ip_restrictions=["192.0.2.0/24", "2001:db8::/32"], ) - assert_matches_type(DomainEditResponse, domain, path=["response"]) + assert_matches_type(Optional[DomainEditResponse], domain, path=["response"]) @parametrize async def test_method_edit_with_all_params(self, async_client: AsyncCloudflare) -> None: domain = await async_client.email_security.settings.domains.edit( - domain_id=2400, + domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", - ip_restrictions=["192.0.2.0/24", "2001:db8::/32"], allowed_delivery_modes=["DIRECT"], domain="domain", drop_dispositions=["MALICIOUS"], folder="AllItems", integration_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ip_restrictions=["192.0.2.0/24", "2001:db8::/32"], lookback_hops=1, regions=["GLOBAL"], require_tls_inbound=True, require_tls_outbound=True, transport="transport", ) - assert_matches_type(DomainEditResponse, domain, path=["response"]) + assert_matches_type(Optional[DomainEditResponse], domain, path=["response"]) @parametrize async def test_raw_response_edit(self, async_client: AsyncCloudflare) -> None: response = await async_client.email_security.settings.domains.with_raw_response.edit( - domain_id=2400, + domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", - ip_restrictions=["192.0.2.0/24", "2001:db8::/32"], ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" domain = await response.parse() - assert_matches_type(DomainEditResponse, domain, path=["response"]) + assert_matches_type(Optional[DomainEditResponse], domain, path=["response"]) @parametrize async def test_streaming_response_edit(self, async_client: AsyncCloudflare) -> None: async with async_client.email_security.settings.domains.with_streaming_response.edit( - domain_id=2400, + domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", - ip_restrictions=["192.0.2.0/24", "2001:db8::/32"], ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" domain = await response.parse() - assert_matches_type(DomainEditResponse, domain, path=["response"]) + assert_matches_type(Optional[DomainEditResponse], domain, path=["response"]) assert cast(Any, response.is_closed) is True @@ -465,42 +407,47 @@ async def test_streaming_response_edit(self, async_client: AsyncCloudflare) -> N async def test_path_params_edit(self, async_client: AsyncCloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): await async_client.email_security.settings.domains.with_raw_response.edit( - domain_id=2400, + domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="", - ip_restrictions=["192.0.2.0/24", "2001:db8::/32"], + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `domain_id` but received ''"): + await async_client.email_security.settings.domains.with_raw_response.edit( + domain_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", ) @parametrize async def test_method_get(self, async_client: AsyncCloudflare) -> None: domain = await async_client.email_security.settings.domains.get( - domain_id=2400, + domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) - assert_matches_type(DomainGetResponse, domain, path=["response"]) + assert_matches_type(Optional[DomainGetResponse], domain, path=["response"]) @parametrize async def test_raw_response_get(self, async_client: AsyncCloudflare) -> None: response = await async_client.email_security.settings.domains.with_raw_response.get( - domain_id=2400, + domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" domain = await response.parse() - assert_matches_type(DomainGetResponse, domain, path=["response"]) + assert_matches_type(Optional[DomainGetResponse], domain, path=["response"]) @parametrize async def test_streaming_response_get(self, async_client: AsyncCloudflare) -> None: async with async_client.email_security.settings.domains.with_streaming_response.get( - domain_id=2400, + domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" domain = await response.parse() - assert_matches_type(DomainGetResponse, domain, path=["response"]) + assert_matches_type(Optional[DomainGetResponse], domain, path=["response"]) assert cast(Any, response.is_closed) is True @@ -508,6 +455,12 @@ async def test_streaming_response_get(self, async_client: AsyncCloudflare) -> No 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.email_security.settings.domains.with_raw_response.get( - domain_id=2400, + domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="", ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `domain_id` but received ''"): + await async_client.email_security.settings.domains.with_raw_response.get( + domain_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) diff --git a/tests/api_resources/email_security/settings/test_impersonation_registry.py b/tests/api_resources/email_security/settings/test_impersonation_registry.py index 0d484d1724d..a8b5ad03e39 100644 --- a/tests/api_resources/email_security/settings/test_impersonation_registry.py +++ b/tests/api_resources/email_security/settings/test_impersonation_registry.py @@ -3,7 +3,7 @@ from __future__ import annotations import os -from typing import Any, cast +from typing import Any, Optional, cast import pytest @@ -11,11 +11,8 @@ from tests.utils import assert_matches_type from cloudflare.pagination import SyncV4PagePaginationArray, AsyncV4PagePaginationArray from cloudflare.types.email_security.settings import ( - ImpersonationRegistryGetResponse, - ImpersonationRegistryEditResponse, ImpersonationRegistryListResponse, ImpersonationRegistryCreateResponse, - ImpersonationRegistryDeleteResponse, ) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -28,39 +25,56 @@ class TestImpersonationRegistry: def test_method_create(self, client: Cloudflare) -> None: impersonation_registry = client.email_security.settings.impersonation_registry.create( account_id="023e105f4ecef8ad9ca31a8372d0c353", - email="email", - is_email_regex=True, - name="name", + email="john.doe@example.com", + is_email_regex=False, + name="John Doe", ) - assert_matches_type(ImpersonationRegistryCreateResponse, impersonation_registry, path=["response"]) + assert_matches_type(Optional[ImpersonationRegistryCreateResponse], impersonation_registry, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Cloudflare) -> None: + impersonation_registry = client.email_security.settings.impersonation_registry.create( + account_id="023e105f4ecef8ad9ca31a8372d0c353", + email="john.doe@example.com", + is_email_regex=False, + name="John Doe", + comments="comments", + directory_id=0, + directory_node_id=0, + external_directory_node_id="external_directory_node_id", + provenance="A1S_INTERNAL", + ) + assert_matches_type(Optional[ImpersonationRegistryCreateResponse], impersonation_registry, path=["response"]) @parametrize def test_raw_response_create(self, client: Cloudflare) -> None: response = client.email_security.settings.impersonation_registry.with_raw_response.create( account_id="023e105f4ecef8ad9ca31a8372d0c353", - email="email", - is_email_regex=True, - name="name", + email="john.doe@example.com", + is_email_regex=False, + name="John Doe", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" impersonation_registry = response.parse() - assert_matches_type(ImpersonationRegistryCreateResponse, impersonation_registry, path=["response"]) + assert_matches_type(Optional[ImpersonationRegistryCreateResponse], impersonation_registry, path=["response"]) @parametrize def test_streaming_response_create(self, client: Cloudflare) -> None: with client.email_security.settings.impersonation_registry.with_streaming_response.create( account_id="023e105f4ecef8ad9ca31a8372d0c353", - email="email", - is_email_regex=True, - name="name", + email="john.doe@example.com", + is_email_regex=False, + name="John Doe", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" impersonation_registry = response.parse() - assert_matches_type(ImpersonationRegistryCreateResponse, impersonation_registry, path=["response"]) + assert_matches_type( + Optional[ImpersonationRegistryCreateResponse], impersonation_registry, path=["response"] + ) assert cast(Any, response.is_closed) is True @@ -69,9 +83,9 @@ 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.email_security.settings.impersonation_registry.with_raw_response.create( account_id="", - email="email", - is_email_regex=True, - name="name", + email="john.doe@example.com", + is_email_regex=False, + name="John Doe", ) @parametrize @@ -90,7 +104,7 @@ def test_method_list_with_all_params(self, client: Cloudflare) -> None: direction="asc", order="name", page=1, - per_page=1, + per_page=20, provenance="A1S_INTERNAL", search="search", ) @@ -133,143 +147,6 @@ def test_path_params_list(self, client: Cloudflare) -> None: account_id="", ) - @parametrize - def test_method_delete(self, client: Cloudflare) -> None: - impersonation_registry = client.email_security.settings.impersonation_registry.delete( - display_name_id=2403, - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - assert_matches_type(ImpersonationRegistryDeleteResponse, impersonation_registry, path=["response"]) - - @parametrize - def test_raw_response_delete(self, client: Cloudflare) -> None: - response = client.email_security.settings.impersonation_registry.with_raw_response.delete( - display_name_id=2403, - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - impersonation_registry = response.parse() - assert_matches_type(ImpersonationRegistryDeleteResponse, impersonation_registry, path=["response"]) - - @parametrize - def test_streaming_response_delete(self, client: Cloudflare) -> None: - with client.email_security.settings.impersonation_registry.with_streaming_response.delete( - display_name_id=2403, - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - impersonation_registry = response.parse() - assert_matches_type(ImpersonationRegistryDeleteResponse, impersonation_registry, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_delete(self, client: Cloudflare) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): - client.email_security.settings.impersonation_registry.with_raw_response.delete( - display_name_id=2403, - account_id="", - ) - - @parametrize - def test_method_edit(self, client: Cloudflare) -> None: - impersonation_registry = client.email_security.settings.impersonation_registry.edit( - display_name_id=2403, - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - assert_matches_type(ImpersonationRegistryEditResponse, impersonation_registry, path=["response"]) - - @parametrize - def test_method_edit_with_all_params(self, client: Cloudflare) -> None: - impersonation_registry = client.email_security.settings.impersonation_registry.edit( - display_name_id=2403, - account_id="023e105f4ecef8ad9ca31a8372d0c353", - email="email", - is_email_regex=True, - name="name", - ) - assert_matches_type(ImpersonationRegistryEditResponse, impersonation_registry, path=["response"]) - - @parametrize - def test_raw_response_edit(self, client: Cloudflare) -> None: - response = client.email_security.settings.impersonation_registry.with_raw_response.edit( - display_name_id=2403, - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - impersonation_registry = response.parse() - assert_matches_type(ImpersonationRegistryEditResponse, impersonation_registry, path=["response"]) - - @parametrize - def test_streaming_response_edit(self, client: Cloudflare) -> None: - with client.email_security.settings.impersonation_registry.with_streaming_response.edit( - display_name_id=2403, - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - impersonation_registry = response.parse() - assert_matches_type(ImpersonationRegistryEditResponse, impersonation_registry, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_edit(self, client: Cloudflare) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): - client.email_security.settings.impersonation_registry.with_raw_response.edit( - display_name_id=2403, - account_id="", - ) - - @parametrize - def test_method_get(self, client: Cloudflare) -> None: - impersonation_registry = client.email_security.settings.impersonation_registry.get( - display_name_id=2403, - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - assert_matches_type(ImpersonationRegistryGetResponse, impersonation_registry, path=["response"]) - - @parametrize - def test_raw_response_get(self, client: Cloudflare) -> None: - response = client.email_security.settings.impersonation_registry.with_raw_response.get( - display_name_id=2403, - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - impersonation_registry = response.parse() - assert_matches_type(ImpersonationRegistryGetResponse, impersonation_registry, path=["response"]) - - @parametrize - def test_streaming_response_get(self, client: Cloudflare) -> None: - with client.email_security.settings.impersonation_registry.with_streaming_response.get( - display_name_id=2403, - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - impersonation_registry = response.parse() - assert_matches_type(ImpersonationRegistryGetResponse, impersonation_registry, 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.email_security.settings.impersonation_registry.with_raw_response.get( - display_name_id=2403, - account_id="", - ) - class TestAsyncImpersonationRegistry: parametrize = pytest.mark.parametrize( @@ -280,39 +157,56 @@ class TestAsyncImpersonationRegistry: async def test_method_create(self, async_client: AsyncCloudflare) -> None: impersonation_registry = await async_client.email_security.settings.impersonation_registry.create( account_id="023e105f4ecef8ad9ca31a8372d0c353", - email="email", - is_email_regex=True, - name="name", + email="john.doe@example.com", + is_email_regex=False, + name="John Doe", ) - assert_matches_type(ImpersonationRegistryCreateResponse, impersonation_registry, path=["response"]) + assert_matches_type(Optional[ImpersonationRegistryCreateResponse], impersonation_registry, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncCloudflare) -> None: + impersonation_registry = await async_client.email_security.settings.impersonation_registry.create( + account_id="023e105f4ecef8ad9ca31a8372d0c353", + email="john.doe@example.com", + is_email_regex=False, + name="John Doe", + comments="comments", + directory_id=0, + directory_node_id=0, + external_directory_node_id="external_directory_node_id", + provenance="A1S_INTERNAL", + ) + assert_matches_type(Optional[ImpersonationRegistryCreateResponse], impersonation_registry, path=["response"]) @parametrize async def test_raw_response_create(self, async_client: AsyncCloudflare) -> None: response = await async_client.email_security.settings.impersonation_registry.with_raw_response.create( account_id="023e105f4ecef8ad9ca31a8372d0c353", - email="email", - is_email_regex=True, - name="name", + email="john.doe@example.com", + is_email_regex=False, + name="John Doe", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" impersonation_registry = await response.parse() - assert_matches_type(ImpersonationRegistryCreateResponse, impersonation_registry, path=["response"]) + assert_matches_type(Optional[ImpersonationRegistryCreateResponse], impersonation_registry, path=["response"]) @parametrize async def test_streaming_response_create(self, async_client: AsyncCloudflare) -> None: async with async_client.email_security.settings.impersonation_registry.with_streaming_response.create( account_id="023e105f4ecef8ad9ca31a8372d0c353", - email="email", - is_email_regex=True, - name="name", + email="john.doe@example.com", + is_email_regex=False, + name="John Doe", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" impersonation_registry = await response.parse() - assert_matches_type(ImpersonationRegistryCreateResponse, impersonation_registry, path=["response"]) + assert_matches_type( + Optional[ImpersonationRegistryCreateResponse], impersonation_registry, path=["response"] + ) assert cast(Any, response.is_closed) is True @@ -321,9 +215,9 @@ 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.email_security.settings.impersonation_registry.with_raw_response.create( account_id="", - email="email", - is_email_regex=True, - name="name", + email="john.doe@example.com", + is_email_regex=False, + name="John Doe", ) @parametrize @@ -342,7 +236,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncCloudflare) direction="asc", order="name", page=1, - per_page=1, + per_page=20, provenance="A1S_INTERNAL", search="search", ) @@ -384,140 +278,3 @@ async def test_path_params_list(self, async_client: AsyncCloudflare) -> None: await async_client.email_security.settings.impersonation_registry.with_raw_response.list( account_id="", ) - - @parametrize - async def test_method_delete(self, async_client: AsyncCloudflare) -> None: - impersonation_registry = await async_client.email_security.settings.impersonation_registry.delete( - display_name_id=2403, - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - assert_matches_type(ImpersonationRegistryDeleteResponse, impersonation_registry, path=["response"]) - - @parametrize - async def test_raw_response_delete(self, async_client: AsyncCloudflare) -> None: - response = await async_client.email_security.settings.impersonation_registry.with_raw_response.delete( - display_name_id=2403, - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - impersonation_registry = await response.parse() - assert_matches_type(ImpersonationRegistryDeleteResponse, impersonation_registry, path=["response"]) - - @parametrize - async def test_streaming_response_delete(self, async_client: AsyncCloudflare) -> None: - async with async_client.email_security.settings.impersonation_registry.with_streaming_response.delete( - display_name_id=2403, - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - impersonation_registry = await response.parse() - assert_matches_type(ImpersonationRegistryDeleteResponse, impersonation_registry, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_delete(self, async_client: AsyncCloudflare) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): - await async_client.email_security.settings.impersonation_registry.with_raw_response.delete( - display_name_id=2403, - account_id="", - ) - - @parametrize - async def test_method_edit(self, async_client: AsyncCloudflare) -> None: - impersonation_registry = await async_client.email_security.settings.impersonation_registry.edit( - display_name_id=2403, - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - assert_matches_type(ImpersonationRegistryEditResponse, impersonation_registry, path=["response"]) - - @parametrize - async def test_method_edit_with_all_params(self, async_client: AsyncCloudflare) -> None: - impersonation_registry = await async_client.email_security.settings.impersonation_registry.edit( - display_name_id=2403, - account_id="023e105f4ecef8ad9ca31a8372d0c353", - email="email", - is_email_regex=True, - name="name", - ) - assert_matches_type(ImpersonationRegistryEditResponse, impersonation_registry, path=["response"]) - - @parametrize - async def test_raw_response_edit(self, async_client: AsyncCloudflare) -> None: - response = await async_client.email_security.settings.impersonation_registry.with_raw_response.edit( - display_name_id=2403, - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - impersonation_registry = await response.parse() - assert_matches_type(ImpersonationRegistryEditResponse, impersonation_registry, path=["response"]) - - @parametrize - async def test_streaming_response_edit(self, async_client: AsyncCloudflare) -> None: - async with async_client.email_security.settings.impersonation_registry.with_streaming_response.edit( - display_name_id=2403, - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - impersonation_registry = await response.parse() - assert_matches_type(ImpersonationRegistryEditResponse, impersonation_registry, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_edit(self, async_client: AsyncCloudflare) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): - await async_client.email_security.settings.impersonation_registry.with_raw_response.edit( - display_name_id=2403, - account_id="", - ) - - @parametrize - async def test_method_get(self, async_client: AsyncCloudflare) -> None: - impersonation_registry = await async_client.email_security.settings.impersonation_registry.get( - display_name_id=2403, - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - assert_matches_type(ImpersonationRegistryGetResponse, impersonation_registry, path=["response"]) - - @parametrize - async def test_raw_response_get(self, async_client: AsyncCloudflare) -> None: - response = await async_client.email_security.settings.impersonation_registry.with_raw_response.get( - display_name_id=2403, - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - impersonation_registry = await response.parse() - assert_matches_type(ImpersonationRegistryGetResponse, impersonation_registry, path=["response"]) - - @parametrize - async def test_streaming_response_get(self, async_client: AsyncCloudflare) -> None: - async with async_client.email_security.settings.impersonation_registry.with_streaming_response.get( - display_name_id=2403, - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - impersonation_registry = await response.parse() - assert_matches_type(ImpersonationRegistryGetResponse, impersonation_registry, 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.email_security.settings.impersonation_registry.with_raw_response.get( - display_name_id=2403, - account_id="", - ) diff --git a/tests/api_resources/email_security/settings/test_trusted_domains.py b/tests/api_resources/email_security/settings/test_trusted_domains.py index 57aa6fcd50d..9fef76ec686 100644 --- a/tests/api_resources/email_security/settings/test_trusted_domains.py +++ b/tests/api_resources/email_security/settings/test_trusted_domains.py @@ -3,7 +3,7 @@ from __future__ import annotations import os -from typing import Any, cast +from typing import Any, Optional, cast import pytest @@ -26,7 +26,7 @@ class TestTrustedDomains: @pytest.mark.skip(reason="TODO: investigate HTTP 422 errors on test suite") @parametrize - def test_method_create_overload_1(self, client: Cloudflare) -> None: + def test_method_create(self, client: Cloudflare) -> None: trusted_domain = client.email_security.settings.trusted_domains.create( account_id="023e105f4ecef8ad9ca31a8372d0c353", is_recent=True, @@ -34,24 +34,24 @@ def test_method_create_overload_1(self, client: Cloudflare) -> None: is_similarity=False, pattern="example.com", ) - assert_matches_type(TrustedDomainCreateResponse, trusted_domain, path=["response"]) + assert_matches_type(Optional[TrustedDomainCreateResponse], trusted_domain, path=["response"]) @pytest.mark.skip(reason="TODO: investigate HTTP 422 errors on test suite") @parametrize - def test_method_create_with_all_params_overload_1(self, client: Cloudflare) -> None: + def test_method_create_with_all_params(self, client: Cloudflare) -> None: trusted_domain = client.email_security.settings.trusted_domains.create( account_id="023e105f4ecef8ad9ca31a8372d0c353", is_recent=True, is_regex=False, is_similarity=False, pattern="example.com", - comments=None, + comments="Trusted partner domain", ) - assert_matches_type(TrustedDomainCreateResponse, trusted_domain, path=["response"]) + assert_matches_type(Optional[TrustedDomainCreateResponse], trusted_domain, path=["response"]) @pytest.mark.skip(reason="TODO: investigate HTTP 422 errors on test suite") @parametrize - def test_raw_response_create_overload_1(self, client: Cloudflare) -> None: + def test_raw_response_create(self, client: Cloudflare) -> None: response = client.email_security.settings.trusted_domains.with_raw_response.create( account_id="023e105f4ecef8ad9ca31a8372d0c353", is_recent=True, @@ -63,11 +63,11 @@ def test_raw_response_create_overload_1(self, client: Cloudflare) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" trusted_domain = response.parse() - assert_matches_type(TrustedDomainCreateResponse, trusted_domain, path=["response"]) + assert_matches_type(Optional[TrustedDomainCreateResponse], trusted_domain, path=["response"]) @pytest.mark.skip(reason="TODO: investigate HTTP 422 errors on test suite") @parametrize - def test_streaming_response_create_overload_1(self, client: Cloudflare) -> None: + def test_streaming_response_create(self, client: Cloudflare) -> None: with client.email_security.settings.trusted_domains.with_streaming_response.create( account_id="023e105f4ecef8ad9ca31a8372d0c353", is_recent=True, @@ -79,13 +79,13 @@ def test_streaming_response_create_overload_1(self, client: Cloudflare) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" trusted_domain = response.parse() - assert_matches_type(TrustedDomainCreateResponse, trusted_domain, path=["response"]) + assert_matches_type(Optional[TrustedDomainCreateResponse], trusted_domain, path=["response"]) assert cast(Any, response.is_closed) is True @pytest.mark.skip(reason="TODO: investigate HTTP 422 errors on test suite") @parametrize - def test_path_params_create_overload_1(self, client: Cloudflare) -> None: + 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.email_security.settings.trusted_domains.with_raw_response.create( account_id="", @@ -95,80 +95,6 @@ def test_path_params_create_overload_1(self, client: Cloudflare) -> None: pattern="example.com", ) - @pytest.mark.skip(reason="TODO: investigate HTTP 422 errors on test suite") - @parametrize - def test_method_create_overload_2(self, client: Cloudflare) -> None: - trusted_domain = client.email_security.settings.trusted_domains.create( - account_id="023e105f4ecef8ad9ca31a8372d0c353", - body=[ - { - "is_recent": True, - "is_regex": False, - "is_similarity": False, - "pattern": "example.com", - } - ], - ) - assert_matches_type(TrustedDomainCreateResponse, trusted_domain, path=["response"]) - - @pytest.mark.skip(reason="TODO: investigate HTTP 422 errors on test suite") - @parametrize - def test_raw_response_create_overload_2(self, client: Cloudflare) -> None: - response = client.email_security.settings.trusted_domains.with_raw_response.create( - account_id="023e105f4ecef8ad9ca31a8372d0c353", - body=[ - { - "is_recent": True, - "is_regex": False, - "is_similarity": False, - "pattern": "example.com", - } - ], - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - trusted_domain = response.parse() - assert_matches_type(TrustedDomainCreateResponse, trusted_domain, path=["response"]) - - @pytest.mark.skip(reason="TODO: investigate HTTP 422 errors on test suite") - @parametrize - def test_streaming_response_create_overload_2(self, client: Cloudflare) -> None: - with client.email_security.settings.trusted_domains.with_streaming_response.create( - account_id="023e105f4ecef8ad9ca31a8372d0c353", - body=[ - { - "is_recent": True, - "is_regex": False, - "is_similarity": False, - "pattern": "example.com", - } - ], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - trusted_domain = response.parse() - assert_matches_type(TrustedDomainCreateResponse, trusted_domain, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @pytest.mark.skip(reason="TODO: investigate HTTP 422 errors on test suite") - @parametrize - def test_path_params_create_overload_2(self, client: Cloudflare) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): - client.email_security.settings.trusted_domains.with_raw_response.create( - account_id="", - body=[ - { - "is_recent": True, - "is_regex": False, - "is_similarity": False, - "pattern": "example.com", - } - ], - ) - @parametrize def test_method_list(self, client: Cloudflare) -> None: trusted_domain = client.email_security.settings.trusted_domains.list( @@ -186,7 +112,7 @@ def test_method_list_with_all_params(self, client: Cloudflare) -> None: order="pattern", page=1, pattern="pattern", - per_page=1, + per_page=20, search="search", ) assert_matches_type(SyncV4PagePaginationArray[TrustedDomainListResponse], trusted_domain, path=["response"]) @@ -225,34 +151,34 @@ def test_path_params_list(self, client: Cloudflare) -> None: @parametrize def test_method_delete(self, client: Cloudflare) -> None: trusted_domain = client.email_security.settings.trusted_domains.delete( - trusted_domain_id=2401, + trusted_domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) - assert_matches_type(TrustedDomainDeleteResponse, trusted_domain, path=["response"]) + assert_matches_type(Optional[TrustedDomainDeleteResponse], trusted_domain, path=["response"]) @parametrize def test_raw_response_delete(self, client: Cloudflare) -> None: response = client.email_security.settings.trusted_domains.with_raw_response.delete( - trusted_domain_id=2401, + trusted_domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" trusted_domain = response.parse() - assert_matches_type(TrustedDomainDeleteResponse, trusted_domain, path=["response"]) + assert_matches_type(Optional[TrustedDomainDeleteResponse], trusted_domain, path=["response"]) @parametrize def test_streaming_response_delete(self, client: Cloudflare) -> None: with client.email_security.settings.trusted_domains.with_streaming_response.delete( - trusted_domain_id=2401, + trusted_domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" trusted_domain = response.parse() - assert_matches_type(TrustedDomainDeleteResponse, trusted_domain, path=["response"]) + assert_matches_type(Optional[TrustedDomainDeleteResponse], trusted_domain, path=["response"]) assert cast(Any, response.is_closed) is True @@ -260,54 +186,60 @@ def test_streaming_response_delete(self, client: Cloudflare) -> None: def test_path_params_delete(self, client: Cloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): client.email_security.settings.trusted_domains.with_raw_response.delete( - trusted_domain_id=2401, + trusted_domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="", ) + with pytest.raises(ValueError, match=r"Expected a non-empty value for `trusted_domain_id` but received ''"): + client.email_security.settings.trusted_domains.with_raw_response.delete( + trusted_domain_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + @parametrize def test_method_edit(self, client: Cloudflare) -> None: trusted_domain = client.email_security.settings.trusted_domains.edit( - trusted_domain_id=2401, + trusted_domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) - assert_matches_type(TrustedDomainEditResponse, trusted_domain, path=["response"]) + assert_matches_type(Optional[TrustedDomainEditResponse], trusted_domain, path=["response"]) @parametrize def test_method_edit_with_all_params(self, client: Cloudflare) -> None: trusted_domain = client.email_security.settings.trusted_domains.edit( - trusted_domain_id=2401, + trusted_domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", - comments="comments", + comments="Trusted partner domain", is_recent=True, - is_regex=True, - is_similarity=True, - pattern="x", + is_regex=False, + is_similarity=False, + pattern="example.com", ) - assert_matches_type(TrustedDomainEditResponse, trusted_domain, path=["response"]) + assert_matches_type(Optional[TrustedDomainEditResponse], trusted_domain, path=["response"]) @parametrize def test_raw_response_edit(self, client: Cloudflare) -> None: response = client.email_security.settings.trusted_domains.with_raw_response.edit( - trusted_domain_id=2401, + trusted_domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" trusted_domain = response.parse() - assert_matches_type(TrustedDomainEditResponse, trusted_domain, path=["response"]) + assert_matches_type(Optional[TrustedDomainEditResponse], trusted_domain, path=["response"]) @parametrize def test_streaming_response_edit(self, client: Cloudflare) -> None: with client.email_security.settings.trusted_domains.with_streaming_response.edit( - trusted_domain_id=2401, + trusted_domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" trusted_domain = response.parse() - assert_matches_type(TrustedDomainEditResponse, trusted_domain, path=["response"]) + assert_matches_type(Optional[TrustedDomainEditResponse], trusted_domain, path=["response"]) assert cast(Any, response.is_closed) is True @@ -315,41 +247,47 @@ def test_streaming_response_edit(self, client: Cloudflare) -> None: def test_path_params_edit(self, client: Cloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): client.email_security.settings.trusted_domains.with_raw_response.edit( - trusted_domain_id=2401, + trusted_domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="", ) + with pytest.raises(ValueError, match=r"Expected a non-empty value for `trusted_domain_id` but received ''"): + client.email_security.settings.trusted_domains.with_raw_response.edit( + trusted_domain_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + @parametrize def test_method_get(self, client: Cloudflare) -> None: trusted_domain = client.email_security.settings.trusted_domains.get( - trusted_domain_id=2401, + trusted_domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) - assert_matches_type(TrustedDomainGetResponse, trusted_domain, path=["response"]) + assert_matches_type(Optional[TrustedDomainGetResponse], trusted_domain, path=["response"]) @parametrize def test_raw_response_get(self, client: Cloudflare) -> None: response = client.email_security.settings.trusted_domains.with_raw_response.get( - trusted_domain_id=2401, + trusted_domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" trusted_domain = response.parse() - assert_matches_type(TrustedDomainGetResponse, trusted_domain, path=["response"]) + assert_matches_type(Optional[TrustedDomainGetResponse], trusted_domain, path=["response"]) @parametrize def test_streaming_response_get(self, client: Cloudflare) -> None: with client.email_security.settings.trusted_domains.with_streaming_response.get( - trusted_domain_id=2401, + trusted_domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" trusted_domain = response.parse() - assert_matches_type(TrustedDomainGetResponse, trusted_domain, path=["response"]) + assert_matches_type(Optional[TrustedDomainGetResponse], trusted_domain, path=["response"]) assert cast(Any, response.is_closed) is True @@ -357,10 +295,16 @@ def test_streaming_response_get(self, client: Cloudflare) -> None: 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.email_security.settings.trusted_domains.with_raw_response.get( - trusted_domain_id=2401, + trusted_domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="", ) + with pytest.raises(ValueError, match=r"Expected a non-empty value for `trusted_domain_id` but received ''"): + client.email_security.settings.trusted_domains.with_raw_response.get( + trusted_domain_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + class TestAsyncTrustedDomains: parametrize = pytest.mark.parametrize( @@ -369,7 +313,7 @@ class TestAsyncTrustedDomains: @pytest.mark.skip(reason="TODO: investigate HTTP 422 errors on test suite") @parametrize - async def test_method_create_overload_1(self, async_client: AsyncCloudflare) -> None: + async def test_method_create(self, async_client: AsyncCloudflare) -> None: trusted_domain = await async_client.email_security.settings.trusted_domains.create( account_id="023e105f4ecef8ad9ca31a8372d0c353", is_recent=True, @@ -377,24 +321,24 @@ async def test_method_create_overload_1(self, async_client: AsyncCloudflare) -> is_similarity=False, pattern="example.com", ) - assert_matches_type(TrustedDomainCreateResponse, trusted_domain, path=["response"]) + assert_matches_type(Optional[TrustedDomainCreateResponse], trusted_domain, path=["response"]) @pytest.mark.skip(reason="TODO: investigate HTTP 422 errors on test suite") @parametrize - async def test_method_create_with_all_params_overload_1(self, async_client: AsyncCloudflare) -> None: + async def test_method_create_with_all_params(self, async_client: AsyncCloudflare) -> None: trusted_domain = await async_client.email_security.settings.trusted_domains.create( account_id="023e105f4ecef8ad9ca31a8372d0c353", is_recent=True, is_regex=False, is_similarity=False, pattern="example.com", - comments=None, + comments="Trusted partner domain", ) - assert_matches_type(TrustedDomainCreateResponse, trusted_domain, path=["response"]) + assert_matches_type(Optional[TrustedDomainCreateResponse], trusted_domain, path=["response"]) @pytest.mark.skip(reason="TODO: investigate HTTP 422 errors on test suite") @parametrize - async def test_raw_response_create_overload_1(self, async_client: AsyncCloudflare) -> None: + async def test_raw_response_create(self, async_client: AsyncCloudflare) -> None: response = await async_client.email_security.settings.trusted_domains.with_raw_response.create( account_id="023e105f4ecef8ad9ca31a8372d0c353", is_recent=True, @@ -406,11 +350,11 @@ async def test_raw_response_create_overload_1(self, async_client: AsyncCloudflar assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" trusted_domain = await response.parse() - assert_matches_type(TrustedDomainCreateResponse, trusted_domain, path=["response"]) + assert_matches_type(Optional[TrustedDomainCreateResponse], trusted_domain, path=["response"]) @pytest.mark.skip(reason="TODO: investigate HTTP 422 errors on test suite") @parametrize - async def test_streaming_response_create_overload_1(self, async_client: AsyncCloudflare) -> None: + async def test_streaming_response_create(self, async_client: AsyncCloudflare) -> None: async with async_client.email_security.settings.trusted_domains.with_streaming_response.create( account_id="023e105f4ecef8ad9ca31a8372d0c353", is_recent=True, @@ -422,13 +366,13 @@ async def test_streaming_response_create_overload_1(self, async_client: AsyncClo assert response.http_request.headers.get("X-Stainless-Lang") == "python" trusted_domain = await response.parse() - assert_matches_type(TrustedDomainCreateResponse, trusted_domain, path=["response"]) + assert_matches_type(Optional[TrustedDomainCreateResponse], trusted_domain, path=["response"]) assert cast(Any, response.is_closed) is True @pytest.mark.skip(reason="TODO: investigate HTTP 422 errors on test suite") @parametrize - async def test_path_params_create_overload_1(self, async_client: AsyncCloudflare) -> None: + 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.email_security.settings.trusted_domains.with_raw_response.create( account_id="", @@ -438,80 +382,6 @@ async def test_path_params_create_overload_1(self, async_client: AsyncCloudflare pattern="example.com", ) - @pytest.mark.skip(reason="TODO: investigate HTTP 422 errors on test suite") - @parametrize - async def test_method_create_overload_2(self, async_client: AsyncCloudflare) -> None: - trusted_domain = await async_client.email_security.settings.trusted_domains.create( - account_id="023e105f4ecef8ad9ca31a8372d0c353", - body=[ - { - "is_recent": True, - "is_regex": False, - "is_similarity": False, - "pattern": "example.com", - } - ], - ) - assert_matches_type(TrustedDomainCreateResponse, trusted_domain, path=["response"]) - - @pytest.mark.skip(reason="TODO: investigate HTTP 422 errors on test suite") - @parametrize - async def test_raw_response_create_overload_2(self, async_client: AsyncCloudflare) -> None: - response = await async_client.email_security.settings.trusted_domains.with_raw_response.create( - account_id="023e105f4ecef8ad9ca31a8372d0c353", - body=[ - { - "is_recent": True, - "is_regex": False, - "is_similarity": False, - "pattern": "example.com", - } - ], - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - trusted_domain = await response.parse() - assert_matches_type(TrustedDomainCreateResponse, trusted_domain, path=["response"]) - - @pytest.mark.skip(reason="TODO: investigate HTTP 422 errors on test suite") - @parametrize - async def test_streaming_response_create_overload_2(self, async_client: AsyncCloudflare) -> None: - async with async_client.email_security.settings.trusted_domains.with_streaming_response.create( - account_id="023e105f4ecef8ad9ca31a8372d0c353", - body=[ - { - "is_recent": True, - "is_regex": False, - "is_similarity": False, - "pattern": "example.com", - } - ], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - trusted_domain = await response.parse() - assert_matches_type(TrustedDomainCreateResponse, trusted_domain, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @pytest.mark.skip(reason="TODO: investigate HTTP 422 errors on test suite") - @parametrize - async def test_path_params_create_overload_2(self, async_client: AsyncCloudflare) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): - await async_client.email_security.settings.trusted_domains.with_raw_response.create( - account_id="", - body=[ - { - "is_recent": True, - "is_regex": False, - "is_similarity": False, - "pattern": "example.com", - } - ], - ) - @parametrize async def test_method_list(self, async_client: AsyncCloudflare) -> None: trusted_domain = await async_client.email_security.settings.trusted_domains.list( @@ -529,7 +399,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncCloudflare) order="pattern", page=1, pattern="pattern", - per_page=1, + per_page=20, search="search", ) assert_matches_type(AsyncV4PagePaginationArray[TrustedDomainListResponse], trusted_domain, path=["response"]) @@ -570,34 +440,34 @@ async def test_path_params_list(self, async_client: AsyncCloudflare) -> None: @parametrize async def test_method_delete(self, async_client: AsyncCloudflare) -> None: trusted_domain = await async_client.email_security.settings.trusted_domains.delete( - trusted_domain_id=2401, + trusted_domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) - assert_matches_type(TrustedDomainDeleteResponse, trusted_domain, path=["response"]) + assert_matches_type(Optional[TrustedDomainDeleteResponse], trusted_domain, path=["response"]) @parametrize async def test_raw_response_delete(self, async_client: AsyncCloudflare) -> None: response = await async_client.email_security.settings.trusted_domains.with_raw_response.delete( - trusted_domain_id=2401, + trusted_domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" trusted_domain = await response.parse() - assert_matches_type(TrustedDomainDeleteResponse, trusted_domain, path=["response"]) + assert_matches_type(Optional[TrustedDomainDeleteResponse], trusted_domain, path=["response"]) @parametrize async def test_streaming_response_delete(self, async_client: AsyncCloudflare) -> None: async with async_client.email_security.settings.trusted_domains.with_streaming_response.delete( - trusted_domain_id=2401, + trusted_domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" trusted_domain = await response.parse() - assert_matches_type(TrustedDomainDeleteResponse, trusted_domain, path=["response"]) + assert_matches_type(Optional[TrustedDomainDeleteResponse], trusted_domain, path=["response"]) assert cast(Any, response.is_closed) is True @@ -605,54 +475,60 @@ async def test_streaming_response_delete(self, async_client: AsyncCloudflare) -> async def test_path_params_delete(self, async_client: AsyncCloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): await async_client.email_security.settings.trusted_domains.with_raw_response.delete( - trusted_domain_id=2401, + trusted_domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="", ) + with pytest.raises(ValueError, match=r"Expected a non-empty value for `trusted_domain_id` but received ''"): + await async_client.email_security.settings.trusted_domains.with_raw_response.delete( + trusted_domain_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + @parametrize async def test_method_edit(self, async_client: AsyncCloudflare) -> None: trusted_domain = await async_client.email_security.settings.trusted_domains.edit( - trusted_domain_id=2401, + trusted_domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) - assert_matches_type(TrustedDomainEditResponse, trusted_domain, path=["response"]) + assert_matches_type(Optional[TrustedDomainEditResponse], trusted_domain, path=["response"]) @parametrize async def test_method_edit_with_all_params(self, async_client: AsyncCloudflare) -> None: trusted_domain = await async_client.email_security.settings.trusted_domains.edit( - trusted_domain_id=2401, + trusted_domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", - comments="comments", + comments="Trusted partner domain", is_recent=True, - is_regex=True, - is_similarity=True, - pattern="x", + is_regex=False, + is_similarity=False, + pattern="example.com", ) - assert_matches_type(TrustedDomainEditResponse, trusted_domain, path=["response"]) + assert_matches_type(Optional[TrustedDomainEditResponse], trusted_domain, path=["response"]) @parametrize async def test_raw_response_edit(self, async_client: AsyncCloudflare) -> None: response = await async_client.email_security.settings.trusted_domains.with_raw_response.edit( - trusted_domain_id=2401, + trusted_domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" trusted_domain = await response.parse() - assert_matches_type(TrustedDomainEditResponse, trusted_domain, path=["response"]) + assert_matches_type(Optional[TrustedDomainEditResponse], trusted_domain, path=["response"]) @parametrize async def test_streaming_response_edit(self, async_client: AsyncCloudflare) -> None: async with async_client.email_security.settings.trusted_domains.with_streaming_response.edit( - trusted_domain_id=2401, + trusted_domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" trusted_domain = await response.parse() - assert_matches_type(TrustedDomainEditResponse, trusted_domain, path=["response"]) + assert_matches_type(Optional[TrustedDomainEditResponse], trusted_domain, path=["response"]) assert cast(Any, response.is_closed) is True @@ -660,41 +536,47 @@ async def test_streaming_response_edit(self, async_client: AsyncCloudflare) -> N async def test_path_params_edit(self, async_client: AsyncCloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): await async_client.email_security.settings.trusted_domains.with_raw_response.edit( - trusted_domain_id=2401, + trusted_domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="", ) + with pytest.raises(ValueError, match=r"Expected a non-empty value for `trusted_domain_id` but received ''"): + await async_client.email_security.settings.trusted_domains.with_raw_response.edit( + trusted_domain_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + @parametrize async def test_method_get(self, async_client: AsyncCloudflare) -> None: trusted_domain = await async_client.email_security.settings.trusted_domains.get( - trusted_domain_id=2401, + trusted_domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) - assert_matches_type(TrustedDomainGetResponse, trusted_domain, path=["response"]) + assert_matches_type(Optional[TrustedDomainGetResponse], trusted_domain, path=["response"]) @parametrize async def test_raw_response_get(self, async_client: AsyncCloudflare) -> None: response = await async_client.email_security.settings.trusted_domains.with_raw_response.get( - trusted_domain_id=2401, + trusted_domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" trusted_domain = await response.parse() - assert_matches_type(TrustedDomainGetResponse, trusted_domain, path=["response"]) + assert_matches_type(Optional[TrustedDomainGetResponse], trusted_domain, path=["response"]) @parametrize async def test_streaming_response_get(self, async_client: AsyncCloudflare) -> None: async with async_client.email_security.settings.trusted_domains.with_streaming_response.get( - trusted_domain_id=2401, + trusted_domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" trusted_domain = await response.parse() - assert_matches_type(TrustedDomainGetResponse, trusted_domain, path=["response"]) + assert_matches_type(Optional[TrustedDomainGetResponse], trusted_domain, path=["response"]) assert cast(Any, response.is_closed) is True @@ -702,6 +584,12 @@ async def test_streaming_response_get(self, async_client: AsyncCloudflare) -> No 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.email_security.settings.trusted_domains.with_raw_response.get( - trusted_domain_id=2401, + trusted_domain_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="", ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `trusted_domain_id` but received ''"): + await async_client.email_security.settings.trusted_domains.with_raw_response.get( + trusted_domain_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) diff --git a/tests/api_resources/email_security/test_investigate.py b/tests/api_resources/email_security/test_investigate.py index 0d74e6ae1d8..c9b051a9e22 100644 --- a/tests/api_resources/email_security/test_investigate.py +++ b/tests/api_resources/email_security/test_investigate.py @@ -11,10 +11,7 @@ from tests.utils import assert_matches_type from cloudflare._utils import parse_datetime from cloudflare.pagination import SyncV4PagePaginationArray, AsyncV4PagePaginationArray -from cloudflare.types.email_security import ( - InvestigateGetResponse, - InvestigateListResponse, -) +from cloudflare.types.email_security import InvestigateListResponse base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -39,19 +36,17 @@ def test_method_list_with_all_params(self, client: Cloudflare) -> None: detections_only=True, domain="domain", end=parse_datetime("2019-12-27T18:11:19.117Z"), - exact_subject="exact_subject", final_disposition="MALICIOUS", message_action="PREVIEW", message_id="message_id", metric="metric", page=1, - per_page=1, + per_page=20, query="query", recipient="recipient", sender="sender", start=parse_datetime("2019-12-27T18:11:19.117Z"), subject="subject", - submissions=True, ) assert_matches_type(SyncV4PagePaginationArray[InvestigateListResponse], investigate, path=["response"]) @@ -86,63 +81,6 @@ def test_path_params_list(self, client: Cloudflare) -> None: account_id="", ) - @parametrize - def test_method_get(self, client: Cloudflare) -> None: - investigate = client.email_security.investigate.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - assert_matches_type(InvestigateGetResponse, investigate, path=["response"]) - - @parametrize - def test_method_get_with_all_params(self, client: Cloudflare) -> None: - investigate = client.email_security.investigate.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - submission=True, - ) - assert_matches_type(InvestigateGetResponse, investigate, path=["response"]) - - @parametrize - def test_raw_response_get(self, client: Cloudflare) -> None: - response = client.email_security.investigate.with_raw_response.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - investigate = response.parse() - assert_matches_type(InvestigateGetResponse, investigate, path=["response"]) - - @parametrize - def test_streaming_response_get(self, client: Cloudflare) -> None: - with client.email_security.investigate.with_streaming_response.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - investigate = response.parse() - assert_matches_type(InvestigateGetResponse, investigate, 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.email_security.investigate.with_raw_response.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `postfix_id` but received ''"): - client.email_security.investigate.with_raw_response.get( - postfix_id="", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - class TestAsyncInvestigate: parametrize = pytest.mark.parametrize( @@ -166,19 +104,17 @@ async def test_method_list_with_all_params(self, async_client: AsyncCloudflare) detections_only=True, domain="domain", end=parse_datetime("2019-12-27T18:11:19.117Z"), - exact_subject="exact_subject", final_disposition="MALICIOUS", message_action="PREVIEW", message_id="message_id", metric="metric", page=1, - per_page=1, + per_page=20, query="query", recipient="recipient", sender="sender", start=parse_datetime("2019-12-27T18:11:19.117Z"), subject="subject", - submissions=True, ) assert_matches_type(AsyncV4PagePaginationArray[InvestigateListResponse], investigate, path=["response"]) @@ -212,60 +148,3 @@ async def test_path_params_list(self, async_client: AsyncCloudflare) -> None: await async_client.email_security.investigate.with_raw_response.list( account_id="", ) - - @parametrize - async def test_method_get(self, async_client: AsyncCloudflare) -> None: - investigate = await async_client.email_security.investigate.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - assert_matches_type(InvestigateGetResponse, investigate, path=["response"]) - - @parametrize - async def test_method_get_with_all_params(self, async_client: AsyncCloudflare) -> None: - investigate = await async_client.email_security.investigate.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - submission=True, - ) - assert_matches_type(InvestigateGetResponse, investigate, path=["response"]) - - @parametrize - async def test_raw_response_get(self, async_client: AsyncCloudflare) -> None: - response = await async_client.email_security.investigate.with_raw_response.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - investigate = await response.parse() - assert_matches_type(InvestigateGetResponse, investigate, path=["response"]) - - @parametrize - async def test_streaming_response_get(self, async_client: AsyncCloudflare) -> None: - async with async_client.email_security.investigate.with_streaming_response.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - investigate = await response.parse() - assert_matches_type(InvestigateGetResponse, investigate, 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.email_security.investigate.with_raw_response.get( - postfix_id="4Njp3P0STMz2c02Q", - account_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `postfix_id` but received ''"): - await async_client.email_security.investigate.with_raw_response.get( - postfix_id="", - account_id="023e105f4ecef8ad9ca31a8372d0c353", - ) diff --git a/tests/api_resources/email_security/test_submissions.py b/tests/api_resources/email_security/test_submissions.py index 5c6e59faee4..a3ccfcd375d 100644 --- a/tests/api_resources/email_security/test_submissions.py +++ b/tests/api_resources/email_security/test_submissions.py @@ -30,12 +30,11 @@ def test_method_list(self, client: Cloudflare) -> None: def test_method_list_with_all_params(self, client: Cloudflare) -> None: submission = client.email_security.submissions.list( account_id="023e105f4ecef8ad9ca31a8372d0c353", - customer_status="escalated", end=parse_datetime("2019-12-27T18:11:19.117Z"), original_disposition="MALICIOUS", outcome_disposition="MALICIOUS", page=1, - per_page=1, + per_page=20, query="query", requested_disposition="MALICIOUS", start=parse_datetime("2019-12-27T18:11:19.117Z"), @@ -93,12 +92,11 @@ async def test_method_list(self, async_client: AsyncCloudflare) -> None: async def test_method_list_with_all_params(self, async_client: AsyncCloudflare) -> None: submission = await async_client.email_security.submissions.list( account_id="023e105f4ecef8ad9ca31a8372d0c353", - customer_status="escalated", end=parse_datetime("2019-12-27T18:11:19.117Z"), original_disposition="MALICIOUS", outcome_disposition="MALICIOUS", page=1, - per_page=1, + per_page=20, query="query", requested_disposition="MALICIOUS", start=parse_datetime("2019-12-27T18:11:19.117Z"), diff --git a/tests/api_resources/workers/observability/test_telemetry.py b/tests/api_resources/workers/observability/test_telemetry.py index 2628834629b..f90311d998a 100644 --- a/tests/api_resources/workers/observability/test_telemetry.py +++ b/tests/api_resources/workers/observability/test_telemetry.py @@ -37,7 +37,13 @@ def test_method_keys_with_all_params(self, client: Cloudflare) -> None: filters=[ { "filter_combination": "and", - "filters": [{}], + "filters": [ + { + "filter_combination": "and", + "filters": [{}], + "kind": "group", + } + ], "kind": "group", } ], @@ -134,7 +140,13 @@ def test_method_query_with_all_params(self, client: Cloudflare) -> None: "filters": [ { "filter_combination": "and", - "filters": [{}], + "filters": [ + { + "filter_combination": "and", + "filters": [{}], + "kind": "group", + } + ], "kind": "group", } ], @@ -242,7 +254,13 @@ def test_method_values_with_all_params(self, client: Cloudflare) -> None: filters=[ { "filter_combination": "and", - "filters": [{}], + "filters": [ + { + "filter_combination": "and", + "filters": [{}], + "kind": "group", + } + ], "kind": "group", } ], @@ -328,7 +346,13 @@ async def test_method_keys_with_all_params(self, async_client: AsyncCloudflare) filters=[ { "filter_combination": "and", - "filters": [{}], + "filters": [ + { + "filter_combination": "and", + "filters": [{}], + "kind": "group", + } + ], "kind": "group", } ], @@ -425,7 +449,13 @@ async def test_method_query_with_all_params(self, async_client: AsyncCloudflare) "filters": [ { "filter_combination": "and", - "filters": [{}], + "filters": [ + { + "filter_combination": "and", + "filters": [{}], + "kind": "group", + } + ], "kind": "group", } ], @@ -533,7 +563,13 @@ async def test_method_values_with_all_params(self, async_client: AsyncCloudflare filters=[ { "filter_combination": "and", - "filters": [{}], + "filters": [ + { + "filter_combination": "and", + "filters": [{}], + "kind": "group", + } + ], "kind": "group", } ], From 3d8af2c385deb79b14873f94447ff004b7077018 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 27 Apr 2026 19:21:05 +0000 Subject: [PATCH 04/45] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index aae4f837354..31674404f01 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 2184 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a085fe9423a471ff6a541742d5f268cc73a5a641321c8a280eec22ad5745fa52.yml openapi_spec_hash: 8549e8a8242264b6668f327f37b307e6 -config_hash: a476425ca18fdfc75a509dd60a1461b7 +config_hash: 95239e8fc62638979bc21e538307bbe3 From cb19f09eb2d0cd9c460b59605c35f08c195f7cbf Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 28 Apr 2026 11:15:35 +0000 Subject: [PATCH 05/45] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 31674404f01..fa82f47bb9a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 2184 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a085fe9423a471ff6a541742d5f268cc73a5a641321c8a280eec22ad5745fa52.yml -openapi_spec_hash: 8549e8a8242264b6668f327f37b307e6 +openapi_spec_hash: 5f6c5dec8ec6dd1a8ce4353fdc161b06 config_hash: 95239e8fc62638979bc21e538307bbe3 From 5934108e8f6dc5bf10a36a55492a600983dabc09 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 28 Apr 2026 13:16:04 +0000 Subject: [PATCH 06/45] chore(api): update composite API spec --- .stats.yml | 2 +- .../resources/aisearch/instances/instances.py | 74 +++++++++---------- .../namespaces/instances/instances.py | 74 +++++++++---------- .../aisearch/namespaces/instances/items.py | 46 +++++++++++- .../types/aisearch/instance_list_params.py | 12 +-- .../namespaces/instance_list_params.py | 12 +-- .../instances/item_create_or_update_params.py | 9 +++ .../namespaces/instances/item_sync_params.py | 9 +++ .../instances/item_upload_params.py | 8 +- .../namespaces/instances/test_items.py | 48 ++++++++++++ .../aisearch/namespaces/test_instances.py | 4 +- .../api_resources/aisearch/test_instances.py | 4 +- 12 files changed, 204 insertions(+), 98 deletions(-) diff --git a/.stats.yml b/.stats.yml index fa82f47bb9a..28f3d3e4b06 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 2184 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a085fe9423a471ff6a541742d5f268cc73a5a641321c8a280eec22ad5745fa52.yml -openapi_spec_hash: 5f6c5dec8ec6dd1a8ce4353fdc161b06 +openapi_spec_hash: 5b2b657acd891857f1afe26418371a23 config_hash: 95239e8fc62638979bc21e538307bbe3 diff --git a/src/cloudflare/resources/aisearch/instances/instances.py b/src/cloudflare/resources/aisearch/instances/instances.py index 44e302e2e3e..0b4aa0f18c3 100644 --- a/src/cloudflare/resources/aisearch/instances/instances.py +++ b/src/cloudflare/resources/aisearch/instances/instances.py @@ -192,7 +192,7 @@ def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> InstanceCreateResponse: - """Create a new instances. + """Create a new instance. Args: id: AI Search instance ID. @@ -420,13 +420,10 @@ def update( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> InstanceUpdateResponse: - """Update instances. + """ + Update instance. Args: - id: AI Search instance ID. - - Lowercase alphanumeric, hyphens, and underscores. - index_method: Controls which storage backends are used during indexing. Defaults to vector-only. @@ -496,7 +493,7 @@ def list( self, *, account_id: str, - namespace: Optional[str] | Omit = omit, + namespace: str | Omit = omit, order_by: Literal["created_at"] | Omit = omit, order_by_direction: Literal["asc", "desc"] | Omit = omit, page: int | Omit = omit, @@ -513,11 +510,17 @@ def list( List instances. Args: - order_by: Order By Column Name + namespace: Filter by namespace. - order_by_direction: Order By Direction + order_by: Field to order results by. - search: Search by id + order_by_direction: Order direction. + + page: Page number (1-indexed). + + per_page: Number of results per page. + + search: Filter instances whose id contains this string (case-insensitive). extra_headers: Send extra headers @@ -564,13 +567,10 @@ def delete( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> InstanceDeleteResponse: - """Delete instances. + """ + Delete instance. Args: - id: AI Search instance ID. - - Lowercase alphanumeric, hyphens, and underscores. - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -693,13 +693,10 @@ def read( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> InstanceReadResponse: - """Read instances. + """ + Read instance. Args: - id: AI Search instance ID. - - Lowercase alphanumeric, hyphens, and underscores. - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -969,7 +966,7 @@ async def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> InstanceCreateResponse: - """Create a new instances. + """Create a new instance. Args: id: AI Search instance ID. @@ -1197,13 +1194,10 @@ async def update( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> InstanceUpdateResponse: - """Update instances. + """ + Update instance. Args: - id: AI Search instance ID. - - Lowercase alphanumeric, hyphens, and underscores. - index_method: Controls which storage backends are used during indexing. Defaults to vector-only. @@ -1273,7 +1267,7 @@ def list( self, *, account_id: str, - namespace: Optional[str] | Omit = omit, + namespace: str | Omit = omit, order_by: Literal["created_at"] | Omit = omit, order_by_direction: Literal["asc", "desc"] | Omit = omit, page: int | Omit = omit, @@ -1290,11 +1284,17 @@ def list( List instances. Args: - order_by: Order By Column Name + namespace: Filter by namespace. - order_by_direction: Order By Direction + order_by: Field to order results by. - search: Search by id + order_by_direction: Order direction. + + page: Page number (1-indexed). + + per_page: Number of results per page. + + search: Filter instances whose id contains this string (case-insensitive). extra_headers: Send extra headers @@ -1341,13 +1341,10 @@ async def delete( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> InstanceDeleteResponse: - """Delete instances. + """ + Delete instance. Args: - id: AI Search instance ID. - - Lowercase alphanumeric, hyphens, and underscores. - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -1470,13 +1467,10 @@ async def read( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> InstanceReadResponse: - """Read instances. + """ + Read instance. Args: - id: AI Search instance ID. - - Lowercase alphanumeric, hyphens, and underscores. - extra_headers: Send extra headers extra_query: Add additional query parameters to the request diff --git a/src/cloudflare/resources/aisearch/namespaces/instances/instances.py b/src/cloudflare/resources/aisearch/namespaces/instances/instances.py index 8618c213255..d13a23fec7b 100644 --- a/src/cloudflare/resources/aisearch/namespaces/instances/instances.py +++ b/src/cloudflare/resources/aisearch/namespaces/instances/instances.py @@ -205,7 +205,7 @@ def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> InstanceCreateResponse: - """Create a new instances. + """Create a new instance. Args: id: AI Search instance ID. @@ -438,13 +438,10 @@ def update( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> InstanceUpdateResponse: - """Update instances. + """ + Update instance. Args: - id: AI Search instance ID. - - Lowercase alphanumeric, hyphens, and underscores. - index_method: Controls which storage backends are used during indexing. Defaults to vector-only. @@ -522,7 +519,7 @@ def list( name: str, *, account_id: str, - namespace: Optional[str] | Omit = omit, + namespace: str | Omit = omit, order_by: Literal["created_at"] | Omit = omit, order_by_direction: Literal["asc", "desc"] | Omit = omit, page: int | Omit = omit, @@ -539,11 +536,17 @@ def list( List instances. Args: - order_by: Order By Column Name + namespace: Filter by namespace. - order_by_direction: Order By Direction + order_by: Field to order results by. - search: Search by id + order_by_direction: Order direction. + + page: Page number (1-indexed). + + per_page: Number of results per page. + + search: Filter instances whose id contains this string (case-insensitive). extra_headers: Send extra headers @@ -595,13 +598,10 @@ def delete( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> InstanceDeleteResponse: - """Delete instances. + """ + Delete instance. Args: - id: AI Search instance ID. - - Lowercase alphanumeric, hyphens, and underscores. - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -738,13 +738,10 @@ def read( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> InstanceReadResponse: - """Read instances. + """ + Read instance. Args: - id: AI Search instance ID. - - Lowercase alphanumeric, hyphens, and underscores. - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -1042,7 +1039,7 @@ async def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> InstanceCreateResponse: - """Create a new instances. + """Create a new instance. Args: id: AI Search instance ID. @@ -1275,13 +1272,10 @@ async def update( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> InstanceUpdateResponse: - """Update instances. + """ + Update instance. Args: - id: AI Search instance ID. - - Lowercase alphanumeric, hyphens, and underscores. - index_method: Controls which storage backends are used during indexing. Defaults to vector-only. @@ -1359,7 +1353,7 @@ def list( name: str, *, account_id: str, - namespace: Optional[str] | Omit = omit, + namespace: str | Omit = omit, order_by: Literal["created_at"] | Omit = omit, order_by_direction: Literal["asc", "desc"] | Omit = omit, page: int | Omit = omit, @@ -1376,11 +1370,17 @@ def list( List instances. Args: - order_by: Order By Column Name + namespace: Filter by namespace. - order_by_direction: Order By Direction + order_by: Field to order results by. - search: Search by id + order_by_direction: Order direction. + + page: Page number (1-indexed). + + per_page: Number of results per page. + + search: Filter instances whose id contains this string (case-insensitive). extra_headers: Send extra headers @@ -1432,13 +1432,10 @@ async def delete( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> InstanceDeleteResponse: - """Delete instances. + """ + Delete instance. Args: - id: AI Search instance ID. - - Lowercase alphanumeric, hyphens, and underscores. - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -1575,13 +1572,10 @@ async def read( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> InstanceReadResponse: - """Read instances. + """ + Read instance. Args: - id: AI Search instance ID. - - Lowercase alphanumeric, hyphens, and underscores. - extra_headers: Send extra headers extra_query: Add additional query parameters to the request diff --git a/src/cloudflare/resources/aisearch/namespaces/instances/items.py b/src/cloudflare/resources/aisearch/namespaces/instances/items.py index ecd58bba6a1..5fd2ac78d1b 100644 --- a/src/cloudflare/resources/aisearch/namespaces/instances/items.py +++ b/src/cloudflare/resources/aisearch/namespaces/instances/items.py @@ -280,6 +280,7 @@ def create_or_update( name: str, key: str, next_action: Literal["INDEX"], + wait_for_completion: bool | Omit = omit, # 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, @@ -295,6 +296,12 @@ def create_or_update( key: Item key / filename. Must not exceed 128 characters. + wait_for_completion: Wait for indexing to fully complete before responding. On RAGs with vector + indexing enabled, this additionally waits for Vectorize ingestion confirmation + (up to 40s) so the returned item reflects a queryable state. On timeout the item + is returned in `running` state and the background alarm continues polling. + Defaults to false. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -320,6 +327,7 @@ def create_or_update( { "key": key, "next_action": next_action, + "wait_for_completion": wait_for_completion, }, item_create_or_update_params.ItemCreateOrUpdateParams, ), @@ -510,6 +518,7 @@ def sync( name: str, id: str, next_action: Literal["INDEX"], + wait_for_completion: bool | Omit = omit, # 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, @@ -524,6 +533,12 @@ def sync( Lowercase alphanumeric, hyphens, and underscores. + wait_for_completion: Wait for indexing to fully complete before responding. On RAGs with vector + indexing enabled, this additionally waits for Vectorize ingestion confirmation + (up to 40s) so the returned item reflects a queryable state. On timeout the item + is returned in `running` state and the background alarm continues polling. + Defaults to false. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -548,7 +563,13 @@ def sync( id=id, item_id=item_id, ), - body=maybe_transform({"next_action": next_action}, item_sync_params.ItemSyncParams), + body=maybe_transform( + { + "next_action": next_action, + "wait_for_completion": wait_for_completion, + }, + item_sync_params.ItemSyncParams, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -852,6 +873,7 @@ async def create_or_update( name: str, key: str, next_action: Literal["INDEX"], + wait_for_completion: bool | Omit = omit, # 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, @@ -867,6 +889,12 @@ async def create_or_update( key: Item key / filename. Must not exceed 128 characters. + wait_for_completion: Wait for indexing to fully complete before responding. On RAGs with vector + indexing enabled, this additionally waits for Vectorize ingestion confirmation + (up to 40s) so the returned item reflects a queryable state. On timeout the item + is returned in `running` state and the background alarm continues polling. + Defaults to false. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -892,6 +920,7 @@ async def create_or_update( { "key": key, "next_action": next_action, + "wait_for_completion": wait_for_completion, }, item_create_or_update_params.ItemCreateOrUpdateParams, ), @@ -1082,6 +1111,7 @@ async def sync( name: str, id: str, next_action: Literal["INDEX"], + wait_for_completion: bool | Omit = omit, # 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, @@ -1096,6 +1126,12 @@ async def sync( Lowercase alphanumeric, hyphens, and underscores. + wait_for_completion: Wait for indexing to fully complete before responding. On RAGs with vector + indexing enabled, this additionally waits for Vectorize ingestion confirmation + (up to 40s) so the returned item reflects a queryable state. On timeout the item + is returned in `running` state and the background alarm continues polling. + Defaults to false. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -1120,7 +1156,13 @@ async def sync( id=id, item_id=item_id, ), - body=await async_maybe_transform({"next_action": next_action}, item_sync_params.ItemSyncParams), + body=await async_maybe_transform( + { + "next_action": next_action, + "wait_for_completion": wait_for_completion, + }, + item_sync_params.ItemSyncParams, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, diff --git a/src/cloudflare/types/aisearch/instance_list_params.py b/src/cloudflare/types/aisearch/instance_list_params.py index 7c3b1faa18a..f7191795e9b 100644 --- a/src/cloudflare/types/aisearch/instance_list_params.py +++ b/src/cloudflare/types/aisearch/instance_list_params.py @@ -2,7 +2,6 @@ from __future__ import annotations -from typing import Optional from typing_extensions import Literal, Required, TypedDict __all__ = ["InstanceListParams"] @@ -11,17 +10,20 @@ class InstanceListParams(TypedDict, total=False): account_id: Required[str] - namespace: Optional[str] + namespace: str + """Filter by namespace.""" order_by: Literal["created_at"] - """Order By Column Name""" + """Field to order results by.""" order_by_direction: Literal["asc", "desc"] - """Order By Direction""" + """Order direction.""" page: int + """Page number (1-indexed).""" per_page: int + """Number of results per page.""" search: str - """Search by id""" + """Filter instances whose id contains this string (case-insensitive).""" diff --git a/src/cloudflare/types/aisearch/namespaces/instance_list_params.py b/src/cloudflare/types/aisearch/namespaces/instance_list_params.py index 7c3b1faa18a..f7191795e9b 100644 --- a/src/cloudflare/types/aisearch/namespaces/instance_list_params.py +++ b/src/cloudflare/types/aisearch/namespaces/instance_list_params.py @@ -2,7 +2,6 @@ from __future__ import annotations -from typing import Optional from typing_extensions import Literal, Required, TypedDict __all__ = ["InstanceListParams"] @@ -11,17 +10,20 @@ class InstanceListParams(TypedDict, total=False): account_id: Required[str] - namespace: Optional[str] + namespace: str + """Filter by namespace.""" order_by: Literal["created_at"] - """Order By Column Name""" + """Field to order results by.""" order_by_direction: Literal["asc", "desc"] - """Order By Direction""" + """Order direction.""" page: int + """Page number (1-indexed).""" per_page: int + """Number of results per page.""" search: str - """Search by id""" + """Filter instances whose id contains this string (case-insensitive).""" diff --git a/src/cloudflare/types/aisearch/namespaces/instances/item_create_or_update_params.py b/src/cloudflare/types/aisearch/namespaces/instances/item_create_or_update_params.py index 99ee3a5f635..237cc3acaf5 100644 --- a/src/cloudflare/types/aisearch/namespaces/instances/item_create_or_update_params.py +++ b/src/cloudflare/types/aisearch/namespaces/instances/item_create_or_update_params.py @@ -16,3 +16,12 @@ class ItemCreateOrUpdateParams(TypedDict, total=False): """Item key / filename. Must not exceed 128 characters.""" next_action: Required[Literal["INDEX"]] + + wait_for_completion: bool + """Wait for indexing to fully complete before responding. + + On RAGs with vector indexing enabled, this additionally waits for Vectorize + ingestion confirmation (up to 40s) so the returned item reflects a queryable + state. On timeout the item is returned in `running` state and the background + alarm continues polling. Defaults to false. + """ diff --git a/src/cloudflare/types/aisearch/namespaces/instances/item_sync_params.py b/src/cloudflare/types/aisearch/namespaces/instances/item_sync_params.py index 89a0585b224..6fa679fe3b6 100644 --- a/src/cloudflare/types/aisearch/namespaces/instances/item_sync_params.py +++ b/src/cloudflare/types/aisearch/namespaces/instances/item_sync_params.py @@ -16,3 +16,12 @@ class ItemSyncParams(TypedDict, total=False): """AI Search instance ID. Lowercase alphanumeric, hyphens, and underscores.""" next_action: Required[Literal["INDEX"]] + + wait_for_completion: bool + """Wait for indexing to fully complete before responding. + + On RAGs with vector indexing enabled, this additionally waits for Vectorize + ingestion confirmation (up to 40s) so the returned item reflects a queryable + state. On timeout the item is returned in `running` state and the background + alarm continues polling. Defaults to false. + """ diff --git a/src/cloudflare/types/aisearch/namespaces/instances/item_upload_params.py b/src/cloudflare/types/aisearch/namespaces/instances/item_upload_params.py index 96dd49ad951..e7caf691795 100644 --- a/src/cloudflare/types/aisearch/namespaces/instances/item_upload_params.py +++ b/src/cloudflare/types/aisearch/namespaces/instances/item_upload_params.py @@ -25,4 +25,10 @@ class File(TypedDict, total=False): """JSON string of custom metadata key-value pairs.""" wait_for_completion: bool - """Wait for indexing to complete before responding. Defaults to false.""" + """Wait for indexing to fully complete before responding. + + On RAGs with vector indexing enabled, this additionally waits for Vectorize + ingestion confirmation (up to 40s) so the returned item reflects a queryable + state. On timeout the item is returned in `running` state and the background + alarm continues polling. Defaults to false. + """ diff --git a/tests/api_resources/aisearch/namespaces/instances/test_items.py b/tests/api_resources/aisearch/namespaces/instances/test_items.py index d7a6b9b7bed..6753ef60196 100644 --- a/tests/api_resources/aisearch/namespaces/instances/test_items.py +++ b/tests/api_resources/aisearch/namespaces/instances/test_items.py @@ -283,6 +283,18 @@ def test_method_create_or_update(self, client: Cloudflare) -> None: ) assert_matches_type(ItemCreateOrUpdateResponse, item, path=["response"]) + @parametrize + def test_method_create_or_update_with_all_params(self, client: Cloudflare) -> None: + item = client.aisearch.namespaces.instances.items.create_or_update( + id="my-ai-search", + account_id="c3dc5f0b34a14ff8e1b3ec04895e1b22", + name="my-namespace", + key="key", + next_action="INDEX", + wait_for_completion=True, + ) + assert_matches_type(ItemCreateOrUpdateResponse, item, path=["response"]) + @parametrize def test_raw_response_create_or_update(self, client: Cloudflare) -> None: response = client.aisearch.namespaces.instances.items.with_raw_response.create_or_update( @@ -607,6 +619,18 @@ def test_method_sync(self, client: Cloudflare) -> None: ) assert_matches_type(ItemSyncResponse, item, path=["response"]) + @parametrize + def test_method_sync_with_all_params(self, client: Cloudflare) -> None: + item = client.aisearch.namespaces.instances.items.sync( + item_id="item_id", + account_id="c3dc5f0b34a14ff8e1b3ec04895e1b22", + name="my-namespace", + id="my-ai-search", + next_action="INDEX", + wait_for_completion=True, + ) + assert_matches_type(ItemSyncResponse, item, path=["response"]) + @parametrize def test_raw_response_sync(self, client: Cloudflare) -> None: response = client.aisearch.namespaces.instances.items.with_raw_response.sync( @@ -1011,6 +1035,18 @@ async def test_method_create_or_update(self, async_client: AsyncCloudflare) -> N ) assert_matches_type(ItemCreateOrUpdateResponse, item, path=["response"]) + @parametrize + async def test_method_create_or_update_with_all_params(self, async_client: AsyncCloudflare) -> None: + item = await async_client.aisearch.namespaces.instances.items.create_or_update( + id="my-ai-search", + account_id="c3dc5f0b34a14ff8e1b3ec04895e1b22", + name="my-namespace", + key="key", + next_action="INDEX", + wait_for_completion=True, + ) + assert_matches_type(ItemCreateOrUpdateResponse, item, path=["response"]) + @parametrize async def test_raw_response_create_or_update(self, async_client: AsyncCloudflare) -> None: response = await async_client.aisearch.namespaces.instances.items.with_raw_response.create_or_update( @@ -1335,6 +1371,18 @@ async def test_method_sync(self, async_client: AsyncCloudflare) -> None: ) assert_matches_type(ItemSyncResponse, item, path=["response"]) + @parametrize + async def test_method_sync_with_all_params(self, async_client: AsyncCloudflare) -> None: + item = await async_client.aisearch.namespaces.instances.items.sync( + item_id="item_id", + account_id="c3dc5f0b34a14ff8e1b3ec04895e1b22", + name="my-namespace", + id="my-ai-search", + next_action="INDEX", + wait_for_completion=True, + ) + assert_matches_type(ItemSyncResponse, item, path=["response"]) + @parametrize async def test_raw_response_sync(self, async_client: AsyncCloudflare) -> None: response = await async_client.aisearch.namespaces.instances.items.with_raw_response.sync( diff --git a/tests/api_resources/aisearch/namespaces/test_instances.py b/tests/api_resources/aisearch/namespaces/test_instances.py index 3aab8040ce6..b9ef034cc9e 100644 --- a/tests/api_resources/aisearch/namespaces/test_instances.py +++ b/tests/api_resources/aisearch/namespaces/test_instances.py @@ -378,7 +378,7 @@ def test_method_list_with_all_params(self, client: Cloudflare) -> None: order_by="created_at", order_by_direction="asc", page=1, - per_page=1, + per_page=20, search="search", ) assert_matches_type(SyncV4PagePaginationArray[InstanceListResponse], instance, path=["response"]) @@ -1213,7 +1213,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncCloudflare) order_by="created_at", order_by_direction="asc", page=1, - per_page=1, + per_page=20, search="search", ) assert_matches_type(AsyncV4PagePaginationArray[InstanceListResponse], instance, path=["response"]) diff --git a/tests/api_resources/aisearch/test_instances.py b/tests/api_resources/aisearch/test_instances.py index 80bd18541ba..b80c7cb3ba2 100644 --- a/tests/api_resources/aisearch/test_instances.py +++ b/tests/api_resources/aisearch/test_instances.py @@ -351,7 +351,7 @@ def test_method_list_with_all_params(self, client: Cloudflare) -> None: order_by="created_at", order_by_direction="asc", page=1, - per_page=1, + per_page=20, search="search", ) assert_matches_type(SyncV4PagePaginationArray[InstanceListResponse], instance, path=["response"]) @@ -1082,7 +1082,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncCloudflare) order_by="created_at", order_by_direction="asc", page=1, - per_page=1, + per_page=20, search="search", ) assert_matches_type(AsyncV4PagePaginationArray[InstanceListResponse], instance, path=["response"]) From e6c37b075c7254387dea152103c6e720e17bf839 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 28 Apr 2026 15:23:04 +0000 Subject: [PATCH 07/45] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 28f3d3e4b06..8615c63d94a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 2184 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a085fe9423a471ff6a541742d5f268cc73a5a641321c8a280eec22ad5745fa52.yml -openapi_spec_hash: 5b2b657acd891857f1afe26418371a23 +openapi_spec_hash: 6dbad68ff183c93ecdd3df4b2b77f09d config_hash: 95239e8fc62638979bc21e538307bbe3 From 4dab5b03a690fea350988606b30825bb8c344e10 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 28 Apr 2026 16:22:31 +0000 Subject: [PATCH 08/45] chore(api): update composite API spec --- .stats.yml | 2 +- .../magic_transit/cf_interconnects.py | 6 ++- .../resources/magic_transit/gre_tunnels.py | 12 ++++-- .../resources/magic_transit/ipsec_tunnels.py | 12 ++++-- .../cf_interconnect_bulk_update_response.py | 3 +- .../cf_interconnect_get_response.py | 3 +- .../cf_interconnect_list_response.py | 3 +- .../cf_interconnect_update_params.py | 3 +- .../cf_interconnect_update_response.py | 3 +- .../gre_tunnel_bulk_update_response.py | 3 +- .../magic_transit/gre_tunnel_create_params.py | 3 +- .../gre_tunnel_create_response.py | 3 +- .../gre_tunnel_delete_response.py | 3 +- .../magic_transit/gre_tunnel_get_response.py | 3 +- .../magic_transit/gre_tunnel_list_response.py | 3 +- .../magic_transit/gre_tunnel_update_params.py | 3 +- .../gre_tunnel_update_response.py | 3 +- .../ipsec_tunnel_bulk_update_response.py | 3 +- .../ipsec_tunnel_create_params.py | 3 +- .../ipsec_tunnel_create_response.py | 3 +- .../ipsec_tunnel_delete_response.py | 3 +- .../ipsec_tunnel_get_response.py | 3 +- .../ipsec_tunnel_list_response.py | 3 +- .../ipsec_tunnel_update_params.py | 3 +- .../ipsec_tunnel_update_response.py | 3 +- .../types/magic_transit/sites/dhcp_server.py | 32 +++++++++++++- .../magic_transit/sites/dhcp_server_param.py | 35 ++++++++++++++-- .../magic_transit/sites/test_lans.py | 42 +++++++++++++++++++ 28 files changed, 168 insertions(+), 36 deletions(-) diff --git a/.stats.yml b/.stats.yml index 8615c63d94a..fb5c201e921 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 2184 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a085fe9423a471ff6a541742d5f268cc73a5a641321c8a280eec22ad5745fa52.yml -openapi_spec_hash: 6dbad68ff183c93ecdd3df4b2b77f09d +openapi_spec_hash: 86610e8d69a7b3f8b83cb5f6a0a7c96e config_hash: 95239e8fc62638979bc21e538307bbe3 diff --git a/src/cloudflare/resources/magic_transit/cf_interconnects.py b/src/cloudflare/resources/magic_transit/cf_interconnects.py index f2e3ef1890e..6a127aa7698 100644 --- a/src/cloudflare/resources/magic_transit/cf_interconnects.py +++ b/src/cloudflare/resources/magic_transit/cf_interconnects.py @@ -81,7 +81,8 @@ def update( cf_interconnect_id: Identifier automatic_return_routing: True if automatic stateful return routing should be enabled for a tunnel, false - otherwise. + otherwise. Requires the `coupler_integration` account flag to be enabled; + requests setting this to `true` without that flag will be rejected. description: An optional description of the interconnect. @@ -370,7 +371,8 @@ async def update( cf_interconnect_id: Identifier automatic_return_routing: True if automatic stateful return routing should be enabled for a tunnel, false - otherwise. + otherwise. Requires the `coupler_integration` account flag to be enabled; + requests setting this to `true` without that flag will be rejected. description: An optional description of the interconnect. diff --git a/src/cloudflare/resources/magic_transit/gre_tunnels.py b/src/cloudflare/resources/magic_transit/gre_tunnels.py index e0cf9482bee..96d0d1f6ea7 100644 --- a/src/cloudflare/resources/magic_transit/gre_tunnels.py +++ b/src/cloudflare/resources/magic_transit/gre_tunnels.py @@ -92,7 +92,8 @@ def create( must be 15 characters or less, and cannot share a name with another GRE tunnel. automatic_return_routing: True if automatic stateful return routing should be enabled for a tunnel, false - otherwise. + otherwise. Requires the `coupler_integration` account flag to be enabled; + requests setting this to `true` without that flag will be rejected. description: An optional description of the GRE tunnel. @@ -199,7 +200,8 @@ def update( must be 15 characters or less, and cannot share a name with another GRE tunnel. automatic_return_routing: True if automatic stateful return routing should be enabled for a tunnel, false - otherwise. + otherwise. Requires the `coupler_integration` account flag to be enabled; + requests setting this to `true` without that flag will be rejected. description: An optional description of the GRE tunnel. @@ -554,7 +556,8 @@ async def create( must be 15 characters or less, and cannot share a name with another GRE tunnel. automatic_return_routing: True if automatic stateful return routing should be enabled for a tunnel, false - otherwise. + otherwise. Requires the `coupler_integration` account flag to be enabled; + requests setting this to `true` without that flag will be rejected. description: An optional description of the GRE tunnel. @@ -661,7 +664,8 @@ async def update( must be 15 characters or less, and cannot share a name with another GRE tunnel. automatic_return_routing: True if automatic stateful return routing should be enabled for a tunnel, false - otherwise. + otherwise. Requires the `coupler_integration` account flag to be enabled; + requests setting this to `true` without that flag will be rejected. description: An optional description of the GRE tunnel. diff --git a/src/cloudflare/resources/magic_transit/ipsec_tunnels.py b/src/cloudflare/resources/magic_transit/ipsec_tunnels.py index 0e3f3ade8bc..776165a6701 100644 --- a/src/cloudflare/resources/magic_transit/ipsec_tunnels.py +++ b/src/cloudflare/resources/magic_transit/ipsec_tunnels.py @@ -97,7 +97,8 @@ def create( name: The name of the IPsec tunnel. The name cannot share a name with other tunnels. automatic_return_routing: True if automatic stateful return routing should be enabled for a tunnel, false - otherwise. + otherwise. Requires the `coupler_integration` account flag to be enabled; + requests setting this to `true` without that flag will be rejected. customer_endpoint: The IP address assigned to the customer side of the IPsec tunnel. Not required, but must be set for proactive traceroutes to work. @@ -208,7 +209,8 @@ def update( name: The name of the IPsec tunnel. The name cannot share a name with other tunnels. automatic_return_routing: True if automatic stateful return routing should be enabled for a tunnel, false - otherwise. + otherwise. Requires the `coupler_integration` account flag to be enabled; + requests setting this to `true` without that flag will be rejected. customer_endpoint: The IP address assigned to the customer side of the IPsec tunnel. Not required, but must be set for proactive traceroutes to work. @@ -622,7 +624,8 @@ async def create( name: The name of the IPsec tunnel. The name cannot share a name with other tunnels. automatic_return_routing: True if automatic stateful return routing should be enabled for a tunnel, false - otherwise. + otherwise. Requires the `coupler_integration` account flag to be enabled; + requests setting this to `true` without that flag will be rejected. customer_endpoint: The IP address assigned to the customer side of the IPsec tunnel. Not required, but must be set for proactive traceroutes to work. @@ -733,7 +736,8 @@ async def update( name: The name of the IPsec tunnel. The name cannot share a name with other tunnels. automatic_return_routing: True if automatic stateful return routing should be enabled for a tunnel, false - otherwise. + otherwise. Requires the `coupler_integration` account flag to be enabled; + requests setting this to `true` without that flag will be rejected. customer_endpoint: The IP address assigned to the customer side of the IPsec tunnel. Not required, but must be set for proactive traceroutes to work. diff --git a/src/cloudflare/types/magic_transit/cf_interconnect_bulk_update_response.py b/src/cloudflare/types/magic_transit/cf_interconnect_bulk_update_response.py index 5ec4fe4087c..2f077f1a996 100644 --- a/src/cloudflare/types/magic_transit/cf_interconnect_bulk_update_response.py +++ b/src/cloudflare/types/magic_transit/cf_interconnect_bulk_update_response.py @@ -26,7 +26,8 @@ class ModifiedInterconnect(BaseModel): automatic_return_routing: Optional[bool] = None """ True if automatic stateful return routing should be enabled for a tunnel, false - otherwise. + otherwise. Requires the `coupler_integration` account flag to be enabled; + requests setting this to `true` without that flag will be rejected. """ colo_name: Optional[str] = None diff --git a/src/cloudflare/types/magic_transit/cf_interconnect_get_response.py b/src/cloudflare/types/magic_transit/cf_interconnect_get_response.py index 389b0fb12f0..93c01b6d70e 100644 --- a/src/cloudflare/types/magic_transit/cf_interconnect_get_response.py +++ b/src/cloudflare/types/magic_transit/cf_interconnect_get_response.py @@ -26,7 +26,8 @@ class Interconnect(BaseModel): automatic_return_routing: Optional[bool] = None """ True if automatic stateful return routing should be enabled for a tunnel, false - otherwise. + otherwise. Requires the `coupler_integration` account flag to be enabled; + requests setting this to `true` without that flag will be rejected. """ colo_name: Optional[str] = None diff --git a/src/cloudflare/types/magic_transit/cf_interconnect_list_response.py b/src/cloudflare/types/magic_transit/cf_interconnect_list_response.py index d4e7e7b8745..26eee8fee48 100644 --- a/src/cloudflare/types/magic_transit/cf_interconnect_list_response.py +++ b/src/cloudflare/types/magic_transit/cf_interconnect_list_response.py @@ -26,7 +26,8 @@ class Interconnect(BaseModel): automatic_return_routing: Optional[bool] = None """ True if automatic stateful return routing should be enabled for a tunnel, false - otherwise. + otherwise. Requires the `coupler_integration` account flag to be enabled; + requests setting this to `true` without that flag will be rejected. """ colo_name: Optional[str] = None diff --git a/src/cloudflare/types/magic_transit/cf_interconnect_update_params.py b/src/cloudflare/types/magic_transit/cf_interconnect_update_params.py index dea0aabfdeb..c57aba4f6e4 100644 --- a/src/cloudflare/types/magic_transit/cf_interconnect_update_params.py +++ b/src/cloudflare/types/magic_transit/cf_interconnect_update_params.py @@ -17,7 +17,8 @@ class CfInterconnectUpdateParams(TypedDict, total=False): automatic_return_routing: bool """ True if automatic stateful return routing should be enabled for a tunnel, false - otherwise. + otherwise. Requires the `coupler_integration` account flag to be enabled; + requests setting this to `true` without that flag will be rejected. """ description: str diff --git a/src/cloudflare/types/magic_transit/cf_interconnect_update_response.py b/src/cloudflare/types/magic_transit/cf_interconnect_update_response.py index 1e7f379fde1..acf0ec93893 100644 --- a/src/cloudflare/types/magic_transit/cf_interconnect_update_response.py +++ b/src/cloudflare/types/magic_transit/cf_interconnect_update_response.py @@ -26,7 +26,8 @@ class ModifiedInterconnect(BaseModel): automatic_return_routing: Optional[bool] = None """ True if automatic stateful return routing should be enabled for a tunnel, false - otherwise. + otherwise. Requires the `coupler_integration` account flag to be enabled; + requests setting this to `true` without that flag will be rejected. """ colo_name: Optional[str] = None diff --git a/src/cloudflare/types/magic_transit/gre_tunnel_bulk_update_response.py b/src/cloudflare/types/magic_transit/gre_tunnel_bulk_update_response.py index d98f4e9f5bf..ffacd0ffc74 100644 --- a/src/cloudflare/types/magic_transit/gre_tunnel_bulk_update_response.py +++ b/src/cloudflare/types/magic_transit/gre_tunnel_bulk_update_response.py @@ -151,7 +151,8 @@ class ModifiedGRETunnel(BaseModel): automatic_return_routing: Optional[bool] = None """ True if automatic stateful return routing should be enabled for a tunnel, false - otherwise. + otherwise. Requires the `coupler_integration` account flag to be enabled; + requests setting this to `true` without that flag will be rejected. """ bgp: Optional[ModifiedGRETunnelBGP] = None diff --git a/src/cloudflare/types/magic_transit/gre_tunnel_create_params.py b/src/cloudflare/types/magic_transit/gre_tunnel_create_params.py index 2e8e4a5b8e8..19e85148542 100644 --- a/src/cloudflare/types/magic_transit/gre_tunnel_create_params.py +++ b/src/cloudflare/types/magic_transit/gre_tunnel_create_params.py @@ -46,7 +46,8 @@ class GRETunnelCreateParams(TypedDict, total=False): automatic_return_routing: bool """ True if automatic stateful return routing should be enabled for a tunnel, false - otherwise. + otherwise. Requires the `coupler_integration` account flag to be enabled; + requests setting this to `true` without that flag will be rejected. """ bgp: BGP diff --git a/src/cloudflare/types/magic_transit/gre_tunnel_create_response.py b/src/cloudflare/types/magic_transit/gre_tunnel_create_response.py index d9af36faaab..ee95b6fa8b2 100644 --- a/src/cloudflare/types/magic_transit/gre_tunnel_create_response.py +++ b/src/cloudflare/types/magic_transit/gre_tunnel_create_response.py @@ -150,7 +150,8 @@ class GRETunnelCreateResponse(BaseModel): automatic_return_routing: Optional[bool] = None """ True if automatic stateful return routing should be enabled for a tunnel, false - otherwise. + otherwise. Requires the `coupler_integration` account flag to be enabled; + requests setting this to `true` without that flag will be rejected. """ bgp: Optional[BGP] = None diff --git a/src/cloudflare/types/magic_transit/gre_tunnel_delete_response.py b/src/cloudflare/types/magic_transit/gre_tunnel_delete_response.py index c31aed82b80..2607e9e41bf 100644 --- a/src/cloudflare/types/magic_transit/gre_tunnel_delete_response.py +++ b/src/cloudflare/types/magic_transit/gre_tunnel_delete_response.py @@ -151,7 +151,8 @@ class DeletedGRETunnel(BaseModel): automatic_return_routing: Optional[bool] = None """ True if automatic stateful return routing should be enabled for a tunnel, false - otherwise. + otherwise. Requires the `coupler_integration` account flag to be enabled; + requests setting this to `true` without that flag will be rejected. """ bgp: Optional[DeletedGRETunnelBGP] = None diff --git a/src/cloudflare/types/magic_transit/gre_tunnel_get_response.py b/src/cloudflare/types/magic_transit/gre_tunnel_get_response.py index 77e2db7f295..ef8eb5cacd8 100644 --- a/src/cloudflare/types/magic_transit/gre_tunnel_get_response.py +++ b/src/cloudflare/types/magic_transit/gre_tunnel_get_response.py @@ -151,7 +151,8 @@ class GRETunnel(BaseModel): automatic_return_routing: Optional[bool] = None """ True if automatic stateful return routing should be enabled for a tunnel, false - otherwise. + otherwise. Requires the `coupler_integration` account flag to be enabled; + requests setting this to `true` without that flag will be rejected. """ bgp: Optional[GRETunnelBGP] = None diff --git a/src/cloudflare/types/magic_transit/gre_tunnel_list_response.py b/src/cloudflare/types/magic_transit/gre_tunnel_list_response.py index 45d3abf29dd..e4d0cc9ec77 100644 --- a/src/cloudflare/types/magic_transit/gre_tunnel_list_response.py +++ b/src/cloudflare/types/magic_transit/gre_tunnel_list_response.py @@ -151,7 +151,8 @@ class GRETunnel(BaseModel): automatic_return_routing: Optional[bool] = None """ True if automatic stateful return routing should be enabled for a tunnel, false - otherwise. + otherwise. Requires the `coupler_integration` account flag to be enabled; + requests setting this to `true` without that flag will be rejected. """ bgp: Optional[GRETunnelBGP] = None diff --git a/src/cloudflare/types/magic_transit/gre_tunnel_update_params.py b/src/cloudflare/types/magic_transit/gre_tunnel_update_params.py index 0081115a1d3..003983dcf7d 100644 --- a/src/cloudflare/types/magic_transit/gre_tunnel_update_params.py +++ b/src/cloudflare/types/magic_transit/gre_tunnel_update_params.py @@ -39,7 +39,8 @@ class GRETunnelUpdateParams(TypedDict, total=False): automatic_return_routing: bool """ True if automatic stateful return routing should be enabled for a tunnel, false - otherwise. + otherwise. Requires the `coupler_integration` account flag to be enabled; + requests setting this to `true` without that flag will be rejected. """ description: str diff --git a/src/cloudflare/types/magic_transit/gre_tunnel_update_response.py b/src/cloudflare/types/magic_transit/gre_tunnel_update_response.py index 637b448d880..a1bba508388 100644 --- a/src/cloudflare/types/magic_transit/gre_tunnel_update_response.py +++ b/src/cloudflare/types/magic_transit/gre_tunnel_update_response.py @@ -151,7 +151,8 @@ class ModifiedGRETunnel(BaseModel): automatic_return_routing: Optional[bool] = None """ True if automatic stateful return routing should be enabled for a tunnel, false - otherwise. + otherwise. Requires the `coupler_integration` account flag to be enabled; + requests setting this to `true` without that flag will be rejected. """ bgp: Optional[ModifiedGRETunnelBGP] = None diff --git a/src/cloudflare/types/magic_transit/ipsec_tunnel_bulk_update_response.py b/src/cloudflare/types/magic_transit/ipsec_tunnel_bulk_update_response.py index 6fa99f7d723..09d3a3e6bc4 100644 --- a/src/cloudflare/types/magic_transit/ipsec_tunnel_bulk_update_response.py +++ b/src/cloudflare/types/magic_transit/ipsec_tunnel_bulk_update_response.py @@ -166,7 +166,8 @@ class ModifiedIPSECTunnel(BaseModel): automatic_return_routing: Optional[bool] = None """ True if automatic stateful return routing should be enabled for a tunnel, false - otherwise. + otherwise. Requires the `coupler_integration` account flag to be enabled; + requests setting this to `true` without that flag will be rejected. """ bgp: Optional[ModifiedIPSECTunnelBGP] = None diff --git a/src/cloudflare/types/magic_transit/ipsec_tunnel_create_params.py b/src/cloudflare/types/magic_transit/ipsec_tunnel_create_params.py index 1b6171df8e7..cbfb544cfcf 100644 --- a/src/cloudflare/types/magic_transit/ipsec_tunnel_create_params.py +++ b/src/cloudflare/types/magic_transit/ipsec_tunnel_create_params.py @@ -40,7 +40,8 @@ class IPSECTunnelCreateParams(TypedDict, total=False): automatic_return_routing: bool """ True if automatic stateful return routing should be enabled for a tunnel, false - otherwise. + otherwise. Requires the `coupler_integration` account flag to be enabled; + requests setting this to `true` without that flag will be rejected. """ bgp: BGP diff --git a/src/cloudflare/types/magic_transit/ipsec_tunnel_create_response.py b/src/cloudflare/types/magic_transit/ipsec_tunnel_create_response.py index 62a8802d687..3dfa6eef0d3 100644 --- a/src/cloudflare/types/magic_transit/ipsec_tunnel_create_response.py +++ b/src/cloudflare/types/magic_transit/ipsec_tunnel_create_response.py @@ -165,7 +165,8 @@ class IPSECTunnelCreateResponse(BaseModel): automatic_return_routing: Optional[bool] = None """ True if automatic stateful return routing should be enabled for a tunnel, false - otherwise. + otherwise. Requires the `coupler_integration` account flag to be enabled; + requests setting this to `true` without that flag will be rejected. """ bgp: Optional[BGP] = None diff --git a/src/cloudflare/types/magic_transit/ipsec_tunnel_delete_response.py b/src/cloudflare/types/magic_transit/ipsec_tunnel_delete_response.py index 20b73971937..196c7dd3204 100644 --- a/src/cloudflare/types/magic_transit/ipsec_tunnel_delete_response.py +++ b/src/cloudflare/types/magic_transit/ipsec_tunnel_delete_response.py @@ -166,7 +166,8 @@ class DeletedIPSECTunnel(BaseModel): automatic_return_routing: Optional[bool] = None """ True if automatic stateful return routing should be enabled for a tunnel, false - otherwise. + otherwise. Requires the `coupler_integration` account flag to be enabled; + requests setting this to `true` without that flag will be rejected. """ bgp: Optional[DeletedIPSECTunnelBGP] = None diff --git a/src/cloudflare/types/magic_transit/ipsec_tunnel_get_response.py b/src/cloudflare/types/magic_transit/ipsec_tunnel_get_response.py index 5a01d3e1a75..f8bc64d3ba0 100644 --- a/src/cloudflare/types/magic_transit/ipsec_tunnel_get_response.py +++ b/src/cloudflare/types/magic_transit/ipsec_tunnel_get_response.py @@ -166,7 +166,8 @@ class IPSECTunnel(BaseModel): automatic_return_routing: Optional[bool] = None """ True if automatic stateful return routing should be enabled for a tunnel, false - otherwise. + otherwise. Requires the `coupler_integration` account flag to be enabled; + requests setting this to `true` without that flag will be rejected. """ bgp: Optional[IPSECTunnelBGP] = None diff --git a/src/cloudflare/types/magic_transit/ipsec_tunnel_list_response.py b/src/cloudflare/types/magic_transit/ipsec_tunnel_list_response.py index a2671697a5a..2b400df722d 100644 --- a/src/cloudflare/types/magic_transit/ipsec_tunnel_list_response.py +++ b/src/cloudflare/types/magic_transit/ipsec_tunnel_list_response.py @@ -166,7 +166,8 @@ class IPSECTunnel(BaseModel): automatic_return_routing: Optional[bool] = None """ True if automatic stateful return routing should be enabled for a tunnel, false - otherwise. + otherwise. Requires the `coupler_integration` account flag to be enabled; + requests setting this to `true` without that flag will be rejected. """ bgp: Optional[IPSECTunnelBGP] = None diff --git a/src/cloudflare/types/magic_transit/ipsec_tunnel_update_params.py b/src/cloudflare/types/magic_transit/ipsec_tunnel_update_params.py index 459e55c76ed..b8d6325f32e 100644 --- a/src/cloudflare/types/magic_transit/ipsec_tunnel_update_params.py +++ b/src/cloudflare/types/magic_transit/ipsec_tunnel_update_params.py @@ -40,7 +40,8 @@ class IPSECTunnelUpdateParams(TypedDict, total=False): automatic_return_routing: bool """ True if automatic stateful return routing should be enabled for a tunnel, false - otherwise. + otherwise. Requires the `coupler_integration` account flag to be enabled; + requests setting this to `true` without that flag will be rejected. """ bgp: BGP diff --git a/src/cloudflare/types/magic_transit/ipsec_tunnel_update_response.py b/src/cloudflare/types/magic_transit/ipsec_tunnel_update_response.py index 291befb11e9..9e82141a51d 100644 --- a/src/cloudflare/types/magic_transit/ipsec_tunnel_update_response.py +++ b/src/cloudflare/types/magic_transit/ipsec_tunnel_update_response.py @@ -166,7 +166,8 @@ class ModifiedIPSECTunnel(BaseModel): automatic_return_routing: Optional[bool] = None """ True if automatic stateful return routing should be enabled for a tunnel, false - otherwise. + otherwise. Requires the `coupler_integration` account flag to be enabled; + requests setting this to `true` without that flag will be rejected. """ bgp: Optional[ModifiedIPSECTunnelBGP] = None diff --git a/src/cloudflare/types/magic_transit/sites/dhcp_server.py b/src/cloudflare/types/magic_transit/sites/dhcp_server.py index 51cce549430..55609a201c9 100644 --- a/src/cloudflare/types/magic_transit/sites/dhcp_server.py +++ b/src/cloudflare/types/magic_transit/sites/dhcp_server.py @@ -1,13 +1,43 @@ # 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__ = ["DHCPServer"] +__all__ = ["DHCPServer", "DHCPOption"] + + +class DHCPOption(BaseModel): + """A custom DHCP option to include in DHCP responses.""" + + code: int + """DHCP option number (1-254). + + Options 0 and 255 are reserved by RFC 2132. Options 3, 6, and 51 are not allowed + because they conflict with connector-managed configuration. + """ + + type: Literal["text", "hex", "ip", "byte", "short", "integer"] + """The type of the option value. + + text: a string (max 255 bytes). hex: colon-separated hex bytes (e.g. + "01:04:aa:bb:cc", max 255 bytes). ip: an IPv4 address (e.g. "10.20.30.40"). + byte: an unsigned integer 0-255 (1 byte). short: an unsigned integer 0-65535 (2 + bytes). integer: an unsigned integer 0-4294967295 (4 bytes). + """ + + value: str + """The option value, interpreted according to the type field.""" class DHCPServer(BaseModel): + dhcp_options: Optional[List[DHCPOption]] = None + """Optional list of custom DHCP options to include in DHCP responses. + + Only valid when DHCP server is enabled. + """ + dhcp_pool_end: Optional[str] = None """A valid IPv4 address.""" diff --git a/src/cloudflare/types/magic_transit/sites/dhcp_server_param.py b/src/cloudflare/types/magic_transit/sites/dhcp_server_param.py index 4eecd6a47df..58e8d8983f2 100644 --- a/src/cloudflare/types/magic_transit/sites/dhcp_server_param.py +++ b/src/cloudflare/types/magic_transit/sites/dhcp_server_param.py @@ -2,15 +2,44 @@ from __future__ import annotations -from typing import Dict -from typing_extensions import TypedDict +from typing import Dict, Iterable +from typing_extensions import Literal, Required, TypedDict from ...._types import SequenceNotStr -__all__ = ["DHCPServerParam"] +__all__ = ["DHCPServerParam", "DHCPOption"] + + +class DHCPOption(TypedDict, total=False): + """A custom DHCP option to include in DHCP responses.""" + + code: Required[int] + """DHCP option number (1-254). + + Options 0 and 255 are reserved by RFC 2132. Options 3, 6, and 51 are not allowed + because they conflict with connector-managed configuration. + """ + + type: Required[Literal["text", "hex", "ip", "byte", "short", "integer"]] + """The type of the option value. + + text: a string (max 255 bytes). hex: colon-separated hex bytes (e.g. + "01:04:aa:bb:cc", max 255 bytes). ip: an IPv4 address (e.g. "10.20.30.40"). + byte: an unsigned integer 0-255 (1 byte). short: an unsigned integer 0-65535 (2 + bytes). integer: an unsigned integer 0-4294967295 (4 bytes). + """ + + value: Required[str] + """The option value, interpreted according to the type field.""" class DHCPServerParam(TypedDict, total=False): + dhcp_options: Iterable[DHCPOption] + """Optional list of custom DHCP options to include in DHCP responses. + + Only valid when DHCP server is enabled. + """ + dhcp_pool_end: str """A valid IPv4 address.""" diff --git a/tests/api_resources/magic_transit/sites/test_lans.py b/tests/api_resources/magic_transit/sites/test_lans.py index b5b9d2a9bc3..89140a8b749 100644 --- a/tests/api_resources/magic_transit/sites/test_lans.py +++ b/tests/api_resources/magic_transit/sites/test_lans.py @@ -51,6 +51,13 @@ def test_method_create_with_all_params(self, client: Cloudflare) -> None: "address": "192.0.2.0/24", "dhcp_relay": {"server_addresses": ["192.0.2.1"]}, "dhcp_server": { + "dhcp_options": [ + { + "code": 66, + "type": "ip", + "value": "10.20.30.40", + } + ], "dhcp_pool_end": "192.0.2.1", "dhcp_pool_start": "192.0.2.1", "dns_server": "192.0.2.1", @@ -139,6 +146,13 @@ def test_method_update_with_all_params(self, client: Cloudflare) -> None: "address": "192.0.2.0/24", "dhcp_relay": {"server_addresses": ["192.0.2.1"]}, "dhcp_server": { + "dhcp_options": [ + { + "code": 66, + "type": "ip", + "value": "10.20.30.40", + } + ], "dhcp_pool_end": "192.0.2.1", "dhcp_pool_start": "192.0.2.1", "dns_server": "192.0.2.1", @@ -346,6 +360,13 @@ def test_method_edit_with_all_params(self, client: Cloudflare) -> None: "address": "192.0.2.0/24", "dhcp_relay": {"server_addresses": ["192.0.2.1"]}, "dhcp_server": { + "dhcp_options": [ + { + "code": 66, + "type": "ip", + "value": "10.20.30.40", + } + ], "dhcp_pool_end": "192.0.2.1", "dhcp_pool_start": "192.0.2.1", "dns_server": "192.0.2.1", @@ -510,6 +531,13 @@ async def test_method_create_with_all_params(self, async_client: AsyncCloudflare "address": "192.0.2.0/24", "dhcp_relay": {"server_addresses": ["192.0.2.1"]}, "dhcp_server": { + "dhcp_options": [ + { + "code": 66, + "type": "ip", + "value": "10.20.30.40", + } + ], "dhcp_pool_end": "192.0.2.1", "dhcp_pool_start": "192.0.2.1", "dns_server": "192.0.2.1", @@ -598,6 +626,13 @@ async def test_method_update_with_all_params(self, async_client: AsyncCloudflare "address": "192.0.2.0/24", "dhcp_relay": {"server_addresses": ["192.0.2.1"]}, "dhcp_server": { + "dhcp_options": [ + { + "code": 66, + "type": "ip", + "value": "10.20.30.40", + } + ], "dhcp_pool_end": "192.0.2.1", "dhcp_pool_start": "192.0.2.1", "dns_server": "192.0.2.1", @@ -805,6 +840,13 @@ async def test_method_edit_with_all_params(self, async_client: AsyncCloudflare) "address": "192.0.2.0/24", "dhcp_relay": {"server_addresses": ["192.0.2.1"]}, "dhcp_server": { + "dhcp_options": [ + { + "code": 66, + "type": "ip", + "value": "10.20.30.40", + } + ], "dhcp_pool_end": "192.0.2.1", "dhcp_pool_start": "192.0.2.1", "dns_server": "192.0.2.1", From d42e065bc90db61bd7d0cadcf3d92ebda04153e5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 28 Apr 2026 19:08:51 +0000 Subject: [PATCH 09/45] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index fb5c201e921..661ee96b590 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 2184 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a085fe9423a471ff6a541742d5f268cc73a5a641321c8a280eec22ad5745fa52.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-95d8075980561cae9cc6ce09b5f930b84eae6f0864cb155abe47db94df2ee294.yml openapi_spec_hash: 86610e8d69a7b3f8b83cb5f6a0a7c96e config_hash: 95239e8fc62638979bc21e538307bbe3 From 3ebe4bc9788ad751c1d8cfc2edaa1584a340a5b4 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 28 Apr 2026 23:54:23 +0000 Subject: [PATCH 10/45] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 661ee96b590..6b1b7c4cd5a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 2184 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-95d8075980561cae9cc6ce09b5f930b84eae6f0864cb155abe47db94df2ee294.yml -openapi_spec_hash: 86610e8d69a7b3f8b83cb5f6a0a7c96e +openapi_spec_hash: 056ce7b95f00677a933e6da00b21c37c config_hash: 95239e8fc62638979bc21e538307bbe3 From f781a0269fca9474c8f6faf1505dd3a5dda1a7f8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 29 Apr 2026 08:01:30 +0000 Subject: [PATCH 11/45] chore(api): update composite API spec --- .stats.yml | 6 +- .../resources/browser_rendering/api.md | 2 + .../devtools/browser/targets.py | 117 +++++++++++++++++ .../devtools/browser/__init__.py | 1 + .../devtools/browser/target_close_response.py | 10 ++ .../devtools/browser/test_targets.py | 121 ++++++++++++++++++ .../browser_rendering/test_content.py | 8 +- .../browser_rendering/test_crawl.py | 12 +- .../browser_rendering/test_json.py | 8 +- .../browser_rendering/test_links.py | 8 +- .../browser_rendering/test_markdown.py | 8 +- .../browser_rendering/test_pdf.py | 8 +- .../browser_rendering/test_scrape.py | 8 +- .../browser_rendering/test_screenshot.py | 8 +- .../browser_rendering/test_snapshot.py | 8 +- 15 files changed, 292 insertions(+), 41 deletions(-) create mode 100644 src/cloudflare/types/browser_rendering/devtools/browser/target_close_response.py diff --git a/.stats.yml b/.stats.yml index 6b1b7c4cd5a..4853f618eb7 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 2184 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-95d8075980561cae9cc6ce09b5f930b84eae6f0864cb155abe47db94df2ee294.yml -openapi_spec_hash: 056ce7b95f00677a933e6da00b21c37c +configured_endpoints: 2185 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-8afbe34627bb47c62422bcfe82d49e1ab7e5ea8e2f0d655a6a0ba3e4648c5e47.yml +openapi_spec_hash: 5a1a5d008c6f779c308ac0ae5a096de0 config_hash: 95239e8fc62638979bc21e538307bbe3 diff --git a/src/cloudflare/resources/browser_rendering/api.md b/src/cloudflare/resources/browser_rendering/api.md index c384cdcb32d..af4ab6e36d7 100644 --- a/src/cloudflare/resources/browser_rendering/api.md +++ b/src/cloudflare/resources/browser_rendering/api.md @@ -160,6 +160,7 @@ from cloudflare.types.browser_rendering.devtools.browser import ( TargetCreateResponse, TargetListResponse, TargetActivateResponse, + TargetCloseResponse, TargetGetResponse, ) ``` @@ -169,4 +170,5 @@ Methods: - client.browser_rendering.devtools.browser.targets.create(session_id, \*, account_id, \*\*params) -> TargetCreateResponse - client.browser_rendering.devtools.browser.targets.list(session_id, \*, account_id) -> TargetListResponse - client.browser_rendering.devtools.browser.targets.activate(target_id, \*, account_id, session_id) -> TargetActivateResponse +- client.browser_rendering.devtools.browser.targets.close(target_id, \*, account_id, session_id) -> TargetCloseResponse - client.browser_rendering.devtools.browser.targets.get(target_id, \*, account_id, session_id) -> TargetGetResponse diff --git a/src/cloudflare/resources/browser_rendering/devtools/browser/targets.py b/src/cloudflare/resources/browser_rendering/devtools/browser/targets.py index 75a19833916..425af81d325 100644 --- a/src/cloudflare/resources/browser_rendering/devtools/browser/targets.py +++ b/src/cloudflare/resources/browser_rendering/devtools/browser/targets.py @@ -18,6 +18,7 @@ from .....types.browser_rendering.devtools.browser import target_create_params from .....types.browser_rendering.devtools.browser.target_get_response import TargetGetResponse from .....types.browser_rendering.devtools.browser.target_list_response import TargetListResponse +from .....types.browser_rendering.devtools.browser.target_close_response import TargetCloseResponse from .....types.browser_rendering.devtools.browser.target_create_response import TargetCreateResponse from .....types.browser_rendering.devtools.browser.target_activate_response import TargetActivateResponse @@ -189,6 +190,58 @@ def activate( cast_to=TargetActivateResponse, ) + def close( + self, + target_id: str, + *, + account_id: str, + session_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, + ) -> TargetCloseResponse: + """Closes a specific browser target (tab, page, etc.) by its ID. + + Returns 'Target is + closing' on success or an error if the target is not found. + + Args: + account_id: Account ID. + + session_id: Browser session ID. + + target_id: Target ID to close. + + 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 session_id: + raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") + if not target_id: + raise ValueError(f"Expected a non-empty value for `target_id` but received {target_id!r}") + return self._get( + path_template( + "/accounts/{account_id}/browser-rendering/devtools/browser/{session_id}/json/close/{target_id}", + account_id=account_id, + session_id=session_id, + target_id=target_id, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TargetCloseResponse, + ) + def get( self, target_id: str, @@ -405,6 +458,58 @@ async def activate( cast_to=TargetActivateResponse, ) + async def close( + self, + target_id: str, + *, + account_id: str, + session_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, + ) -> TargetCloseResponse: + """Closes a specific browser target (tab, page, etc.) by its ID. + + Returns 'Target is + closing' on success or an error if the target is not found. + + Args: + account_id: Account ID. + + session_id: Browser session ID. + + target_id: Target ID to close. + + 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 session_id: + raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") + if not target_id: + raise ValueError(f"Expected a non-empty value for `target_id` but received {target_id!r}") + return await self._get( + path_template( + "/accounts/{account_id}/browser-rendering/devtools/browser/{session_id}/json/close/{target_id}", + account_id=account_id, + session_id=session_id, + target_id=target_id, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TargetCloseResponse, + ) + async def get( self, target_id: str, @@ -469,6 +574,9 @@ def __init__(self, targets: TargetsResource) -> None: self.activate = to_raw_response_wrapper( targets.activate, ) + self.close = to_raw_response_wrapper( + targets.close, + ) self.get = to_raw_response_wrapper( targets.get, ) @@ -487,6 +595,9 @@ def __init__(self, targets: AsyncTargetsResource) -> None: self.activate = async_to_raw_response_wrapper( targets.activate, ) + self.close = async_to_raw_response_wrapper( + targets.close, + ) self.get = async_to_raw_response_wrapper( targets.get, ) @@ -505,6 +616,9 @@ def __init__(self, targets: TargetsResource) -> None: self.activate = to_streamed_response_wrapper( targets.activate, ) + self.close = to_streamed_response_wrapper( + targets.close, + ) self.get = to_streamed_response_wrapper( targets.get, ) @@ -523,6 +637,9 @@ def __init__(self, targets: AsyncTargetsResource) -> None: self.activate = async_to_streamed_response_wrapper( targets.activate, ) + self.close = async_to_streamed_response_wrapper( + targets.close, + ) self.get = async_to_streamed_response_wrapper( targets.get, ) diff --git a/src/cloudflare/types/browser_rendering/devtools/browser/__init__.py b/src/cloudflare/types/browser_rendering/devtools/browser/__init__.py index 3bc1e83d2e4..7f66285244b 100644 --- a/src/cloudflare/types/browser_rendering/devtools/browser/__init__.py +++ b/src/cloudflare/types/browser_rendering/devtools/browser/__init__.py @@ -5,5 +5,6 @@ from .target_get_response import TargetGetResponse as TargetGetResponse from .target_create_params import TargetCreateParams as TargetCreateParams from .target_list_response import TargetListResponse as TargetListResponse +from .target_close_response import TargetCloseResponse as TargetCloseResponse from .target_create_response import TargetCreateResponse as TargetCreateResponse from .target_activate_response import TargetActivateResponse as TargetActivateResponse diff --git a/src/cloudflare/types/browser_rendering/devtools/browser/target_close_response.py b/src/cloudflare/types/browser_rendering/devtools/browser/target_close_response.py new file mode 100644 index 00000000000..db57120d7d4 --- /dev/null +++ b/src/cloudflare/types/browser_rendering/devtools/browser/target_close_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ....._models import BaseModel + +__all__ = ["TargetCloseResponse"] + + +class TargetCloseResponse(BaseModel): + message: str + """Target is closing.""" diff --git a/tests/api_resources/browser_rendering/devtools/browser/test_targets.py b/tests/api_resources/browser_rendering/devtools/browser/test_targets.py index f574b31673c..ca56261b925 100644 --- a/tests/api_resources/browser_rendering/devtools/browser/test_targets.py +++ b/tests/api_resources/browser_rendering/devtools/browser/test_targets.py @@ -12,6 +12,7 @@ from cloudflare.types.browser_rendering.devtools.browser import ( TargetGetResponse, TargetListResponse, + TargetCloseResponse, TargetCreateResponse, TargetActivateResponse, ) @@ -187,6 +188,66 @@ def test_path_params_activate(self, client: Cloudflare) -> None: session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) + @parametrize + def test_method_close(self, client: Cloudflare) -> None: + target = client.browser_rendering.devtools.browser.targets.close( + target_id="target_id", + account_id="account_id", + session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(TargetCloseResponse, target, path=["response"]) + + @parametrize + def test_raw_response_close(self, client: Cloudflare) -> None: + response = client.browser_rendering.devtools.browser.targets.with_raw_response.close( + target_id="target_id", + account_id="account_id", + session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + target = response.parse() + assert_matches_type(TargetCloseResponse, target, path=["response"]) + + @parametrize + def test_streaming_response_close(self, client: Cloudflare) -> None: + with client.browser_rendering.devtools.browser.targets.with_streaming_response.close( + target_id="target_id", + account_id="account_id", + session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + target = response.parse() + assert_matches_type(TargetCloseResponse, target, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_close(self, client: Cloudflare) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): + client.browser_rendering.devtools.browser.targets.with_raw_response.close( + target_id="target_id", + account_id="", + session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `session_id` but received ''"): + client.browser_rendering.devtools.browser.targets.with_raw_response.close( + target_id="target_id", + account_id="account_id", + session_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `target_id` but received ''"): + client.browser_rendering.devtools.browser.targets.with_raw_response.close( + target_id="", + account_id="account_id", + session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + @parametrize def test_method_get(self, client: Cloudflare) -> None: target = client.browser_rendering.devtools.browser.targets.get( @@ -418,6 +479,66 @@ async def test_path_params_activate(self, async_client: AsyncCloudflare) -> None session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) + @parametrize + async def test_method_close(self, async_client: AsyncCloudflare) -> None: + target = await async_client.browser_rendering.devtools.browser.targets.close( + target_id="target_id", + account_id="account_id", + session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(TargetCloseResponse, target, path=["response"]) + + @parametrize + async def test_raw_response_close(self, async_client: AsyncCloudflare) -> None: + response = await async_client.browser_rendering.devtools.browser.targets.with_raw_response.close( + target_id="target_id", + account_id="account_id", + session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + target = await response.parse() + assert_matches_type(TargetCloseResponse, target, path=["response"]) + + @parametrize + async def test_streaming_response_close(self, async_client: AsyncCloudflare) -> None: + async with async_client.browser_rendering.devtools.browser.targets.with_streaming_response.close( + target_id="target_id", + account_id="account_id", + session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + target = await response.parse() + assert_matches_type(TargetCloseResponse, target, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_close(self, async_client: AsyncCloudflare) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): + await async_client.browser_rendering.devtools.browser.targets.with_raw_response.close( + target_id="target_id", + account_id="", + session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `session_id` but received ''"): + await async_client.browser_rendering.devtools.browser.targets.with_raw_response.close( + target_id="target_id", + account_id="account_id", + session_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `target_id` but received ''"): + await async_client.browser_rendering.devtools.browser.targets.with_raw_response.close( + target_id="", + account_id="account_id", + session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + @parametrize async def test_method_get(self, async_client: AsyncCloudflare) -> None: target = await async_client.browser_rendering.devtools.browser.targets.get( diff --git a/tests/api_resources/browser_rendering/test_content.py b/tests/api_resources/browser_rendering/test_content.py index c702e1e2c05..42a1a8708b0 100644 --- a/tests/api_resources/browser_rendering/test_content.py +++ b/tests/api_resources/browser_rendering/test_content.py @@ -29,7 +29,7 @@ def test_method_create_with_all_params_overload_1(self, client: Cloudflare) -> N content = client.browser_rendering.content.create( account_id="account_id", url="https://example.com/", - cache_ttl=86400, + cache_ttl=0, action_timeout=120000, add_script_tag=[ { @@ -147,7 +147,7 @@ def test_method_create_with_all_params_overload_2(self, client: Cloudflare) -> N content = client.browser_rendering.content.create( account_id="account_id", html="

Hello World!

", - cache_ttl=86400, + cache_ttl=0, action_timeout=120000, add_script_tag=[ { @@ -271,7 +271,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn content = await async_client.browser_rendering.content.create( account_id="account_id", url="https://example.com/", - cache_ttl=86400, + cache_ttl=0, action_timeout=120000, add_script_tag=[ { @@ -389,7 +389,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn content = await async_client.browser_rendering.content.create( account_id="account_id", html="

Hello World!

", - cache_ttl=86400, + cache_ttl=0, action_timeout=120000, add_script_tag=[ { diff --git a/tests/api_resources/browser_rendering/test_crawl.py b/tests/api_resources/browser_rendering/test_crawl.py index 3a282e1e8f6..5ee643874a0 100644 --- a/tests/api_resources/browser_rendering/test_crawl.py +++ b/tests/api_resources/browser_rendering/test_crawl.py @@ -33,7 +33,7 @@ def test_method_create_with_all_params_overload_1(self, client: Cloudflare) -> N crawl = client.browser_rendering.crawl.create( account_id="account_id", url="https://example.com", - cache_ttl=86400, + cache_ttl=0, action_timeout=120000, add_script_tag=[ { @@ -179,7 +179,7 @@ def test_method_create_with_all_params_overload_2(self, client: Cloudflare) -> N account_id="account_id", render=False, url="https://example.com", - cache_ttl=86400, + cache_ttl=0, crawl_purposes=["search"], depth=1, formats=["html"], @@ -307,7 +307,7 @@ def test_method_get_with_all_params(self, client: Cloudflare) -> None: crawl = client.browser_rendering.crawl.get( job_id="x", account_id="account_id", - cache_ttl=86400, + cache_ttl=0, cursor=0, limit=0, status="queued", @@ -373,7 +373,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn crawl = await async_client.browser_rendering.crawl.create( account_id="account_id", url="https://example.com", - cache_ttl=86400, + cache_ttl=0, action_timeout=120000, add_script_tag=[ { @@ -519,7 +519,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn account_id="account_id", render=False, url="https://example.com", - cache_ttl=86400, + cache_ttl=0, crawl_purposes=["search"], depth=1, formats=["html"], @@ -647,7 +647,7 @@ async def test_method_get_with_all_params(self, async_client: AsyncCloudflare) - crawl = await async_client.browser_rendering.crawl.get( job_id="x", account_id="account_id", - cache_ttl=86400, + cache_ttl=0, cursor=0, limit=0, status="queued", diff --git a/tests/api_resources/browser_rendering/test_json.py b/tests/api_resources/browser_rendering/test_json.py index 1243f04ab7e..8c4f282a60f 100644 --- a/tests/api_resources/browser_rendering/test_json.py +++ b/tests/api_resources/browser_rendering/test_json.py @@ -30,7 +30,7 @@ def test_method_create_with_all_params_overload_1(self, client: Cloudflare) -> N json = client.browser_rendering.json.create( account_id="account_id", html="

Hello World!

", - cache_ttl=86400, + cache_ttl=0, action_timeout=120000, add_script_tag=[ { @@ -159,7 +159,7 @@ def test_method_create_with_all_params_overload_2(self, client: Cloudflare) -> N json = client.browser_rendering.json.create( account_id="account_id", url="https://example.com/", - cache_ttl=86400, + cache_ttl=0, action_timeout=120000, add_script_tag=[ { @@ -294,7 +294,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn json = await async_client.browser_rendering.json.create( account_id="account_id", html="

Hello World!

", - cache_ttl=86400, + cache_ttl=0, action_timeout=120000, add_script_tag=[ { @@ -423,7 +423,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn json = await async_client.browser_rendering.json.create( account_id="account_id", url="https://example.com/", - cache_ttl=86400, + cache_ttl=0, action_timeout=120000, add_script_tag=[ { diff --git a/tests/api_resources/browser_rendering/test_links.py b/tests/api_resources/browser_rendering/test_links.py index 6609f2a3586..8e78e893b56 100644 --- a/tests/api_resources/browser_rendering/test_links.py +++ b/tests/api_resources/browser_rendering/test_links.py @@ -30,7 +30,7 @@ def test_method_create_with_all_params_overload_1(self, client: Cloudflare) -> N link = client.browser_rendering.links.create( account_id="account_id", html="

Hello World!

", - cache_ttl=86400, + cache_ttl=0, action_timeout=120000, add_script_tag=[ { @@ -150,7 +150,7 @@ def test_method_create_with_all_params_overload_2(self, client: Cloudflare) -> N link = client.browser_rendering.links.create( account_id="account_id", url="https://example.com/", - cache_ttl=86400, + cache_ttl=0, action_timeout=120000, add_script_tag=[ { @@ -276,7 +276,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn link = await async_client.browser_rendering.links.create( account_id="account_id", html="

Hello World!

", - cache_ttl=86400, + cache_ttl=0, action_timeout=120000, add_script_tag=[ { @@ -396,7 +396,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn link = await async_client.browser_rendering.links.create( account_id="account_id", url="https://example.com/", - cache_ttl=86400, + cache_ttl=0, action_timeout=120000, add_script_tag=[ { diff --git a/tests/api_resources/browser_rendering/test_markdown.py b/tests/api_resources/browser_rendering/test_markdown.py index b62b9643e4b..dc637f583ca 100644 --- a/tests/api_resources/browser_rendering/test_markdown.py +++ b/tests/api_resources/browser_rendering/test_markdown.py @@ -29,7 +29,7 @@ def test_method_create_with_all_params_overload_1(self, client: Cloudflare) -> N markdown = client.browser_rendering.markdown.create( account_id="account_id", url="https://example.com/", - cache_ttl=86400, + cache_ttl=0, action_timeout=120000, add_script_tag=[ { @@ -147,7 +147,7 @@ def test_method_create_with_all_params_overload_2(self, client: Cloudflare) -> N markdown = client.browser_rendering.markdown.create( account_id="account_id", html="

Hello World!

", - cache_ttl=86400, + cache_ttl=0, action_timeout=120000, add_script_tag=[ { @@ -271,7 +271,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn markdown = await async_client.browser_rendering.markdown.create( account_id="account_id", url="https://example.com/", - cache_ttl=86400, + cache_ttl=0, action_timeout=120000, add_script_tag=[ { @@ -389,7 +389,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn markdown = await async_client.browser_rendering.markdown.create( account_id="account_id", html="

Hello World!

", - cache_ttl=86400, + cache_ttl=0, action_timeout=120000, add_script_tag=[ { diff --git a/tests/api_resources/browser_rendering/test_pdf.py b/tests/api_resources/browser_rendering/test_pdf.py index 4c9e90a46d2..1e0b6fde88c 100644 --- a/tests/api_resources/browser_rendering/test_pdf.py +++ b/tests/api_resources/browser_rendering/test_pdf.py @@ -47,7 +47,7 @@ def test_method_create_with_all_params_overload_1(self, client: Cloudflare, resp pdf = client.browser_rendering.pdf.create( account_id="account_id", html="

Hello World!

", - cache_ttl=86400, + cache_ttl=0, action_timeout=120000, add_script_tag=[ { @@ -213,7 +213,7 @@ def test_method_create_with_all_params_overload_2(self, client: Cloudflare, resp pdf = client.browser_rendering.pdf.create( account_id="account_id", url="https://example.com/", - cache_ttl=86400, + cache_ttl=0, action_timeout=120000, add_script_tag=[ { @@ -387,7 +387,7 @@ async def test_method_create_with_all_params_overload_1( pdf = await async_client.browser_rendering.pdf.create( account_id="account_id", html="

Hello World!

", - cache_ttl=86400, + cache_ttl=0, action_timeout=120000, add_script_tag=[ { @@ -557,7 +557,7 @@ async def test_method_create_with_all_params_overload_2( pdf = await async_client.browser_rendering.pdf.create( account_id="account_id", url="https://example.com/", - cache_ttl=86400, + cache_ttl=0, action_timeout=120000, add_script_tag=[ { diff --git a/tests/api_resources/browser_rendering/test_scrape.py b/tests/api_resources/browser_rendering/test_scrape.py index e02f2924895..42800beed80 100644 --- a/tests/api_resources/browser_rendering/test_scrape.py +++ b/tests/api_resources/browser_rendering/test_scrape.py @@ -32,7 +32,7 @@ def test_method_create_with_all_params_overload_1(self, client: Cloudflare) -> N account_id="account_id", elements=[{"selector": "selector"}], html="

Hello World!

", - cache_ttl=86400, + cache_ttl=0, action_timeout=120000, add_script_tag=[ { @@ -155,7 +155,7 @@ def test_method_create_with_all_params_overload_2(self, client: Cloudflare) -> N account_id="account_id", elements=[{"selector": "selector"}], url="https://example.com/", - cache_ttl=86400, + cache_ttl=0, action_timeout=120000, add_script_tag=[ { @@ -284,7 +284,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn account_id="account_id", elements=[{"selector": "selector"}], html="

Hello World!

", - cache_ttl=86400, + cache_ttl=0, action_timeout=120000, add_script_tag=[ { @@ -407,7 +407,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn account_id="account_id", elements=[{"selector": "selector"}], url="https://example.com/", - cache_ttl=86400, + cache_ttl=0, action_timeout=120000, add_script_tag=[ { diff --git a/tests/api_resources/browser_rendering/test_screenshot.py b/tests/api_resources/browser_rendering/test_screenshot.py index 98d09071930..0f1147cedad 100644 --- a/tests/api_resources/browser_rendering/test_screenshot.py +++ b/tests/api_resources/browser_rendering/test_screenshot.py @@ -30,7 +30,7 @@ def test_method_create_with_all_params_overload_1(self, client: Cloudflare) -> N screenshot = client.browser_rendering.screenshot.create( account_id="account_id", html="

Hello World!

", - cache_ttl=86400, + cache_ttl=0, action_timeout=120000, add_script_tag=[ { @@ -167,7 +167,7 @@ def test_method_create_with_all_params_overload_2(self, client: Cloudflare) -> N screenshot = client.browser_rendering.screenshot.create( account_id="account_id", url="https://example.com/", - cache_ttl=86400, + cache_ttl=0, action_timeout=120000, add_script_tag=[ { @@ -310,7 +310,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn screenshot = await async_client.browser_rendering.screenshot.create( account_id="account_id", html="

Hello World!

", - cache_ttl=86400, + cache_ttl=0, action_timeout=120000, add_script_tag=[ { @@ -447,7 +447,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn screenshot = await async_client.browser_rendering.screenshot.create( account_id="account_id", url="https://example.com/", - cache_ttl=86400, + cache_ttl=0, action_timeout=120000, add_script_tag=[ { diff --git a/tests/api_resources/browser_rendering/test_snapshot.py b/tests/api_resources/browser_rendering/test_snapshot.py index 4c342c1d5eb..c19d9794baa 100644 --- a/tests/api_resources/browser_rendering/test_snapshot.py +++ b/tests/api_resources/browser_rendering/test_snapshot.py @@ -30,7 +30,7 @@ def test_method_create_with_all_params_overload_1(self, client: Cloudflare) -> N snapshot = client.browser_rendering.snapshot.create( account_id="account_id", html="

Hello World!

", - cache_ttl=86400, + cache_ttl=0, action_timeout=120000, add_script_tag=[ { @@ -164,7 +164,7 @@ def test_method_create_with_all_params_overload_2(self, client: Cloudflare) -> N snapshot = client.browser_rendering.snapshot.create( account_id="account_id", url="https://example.com/", - cache_ttl=86400, + cache_ttl=0, action_timeout=120000, add_script_tag=[ { @@ -304,7 +304,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn snapshot = await async_client.browser_rendering.snapshot.create( account_id="account_id", html="

Hello World!

", - cache_ttl=86400, + cache_ttl=0, action_timeout=120000, add_script_tag=[ { @@ -438,7 +438,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn snapshot = await async_client.browser_rendering.snapshot.create( account_id="account_id", url="https://example.com/", - cache_ttl=86400, + cache_ttl=0, action_timeout=120000, add_script_tag=[ { From 9a6518af4eb4b75e5e4ce2c13796e2c0d2bce3ff Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 29 Apr 2026 14:28:45 +0000 Subject: [PATCH 12/45] chore(api): update composite API spec --- .stats.yml | 4 +- .../api_gateway/operations/operations.py | 26 ++++++++- .../devices/policies/custom/custom.py | 16 ++++++ .../devices/policies/default/default.py | 8 +++ .../api_gateway/operation_create_response.py | 57 ++++++++++++++++++- .../types/api_gateway/operation_get_params.py | 7 +++ .../api_gateway/operation_get_response.py | 57 ++++++++++++++++++- .../types/zero_trust/devices/kolide_input.py | 8 +-- .../zero_trust/devices/kolide_input_param.py | 7 --- .../devices/policies/custom_create_params.py | 21 ++++++- .../devices/policies/custom_edit_params.py | 21 ++++++- .../devices/policies/default_edit_params.py | 21 ++++++- .../devices/policies/default_edit_response.py | 18 +++++- .../devices/policies/default_get_response.py | 18 +++++- .../zero_trust/devices/settings_policy.py | 18 +++++- .../api_gateway/test_operations.py | 2 + .../devices/policies/test_custom.py | 16 ++++++ .../devices/policies/test_default.py | 8 +++ 18 files changed, 304 insertions(+), 29 deletions(-) diff --git a/.stats.yml b/.stats.yml index 4853f618eb7..fe4ebb85888 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 2185 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-8afbe34627bb47c62422bcfe82d49e1ab7e5ea8e2f0d655a6a0ba3e4648c5e47.yml -openapi_spec_hash: 5a1a5d008c6f779c308ac0ae5a096de0 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-ea5d30bcded86d4f9fca4175a9bfdd0713e6dea3b9224506ebf03c104e652df7.yml +openapi_spec_hash: 85e897c979f187c5170264420489e9f0 config_hash: 95239e8fc62638979bc21e538307bbe3 diff --git a/src/cloudflare/resources/api_gateway/operations/operations.py b/src/cloudflare/resources/api_gateway/operations/operations.py index 3850a9a70ec..cd3ba74b2fd 100644 --- a/src/cloudflare/resources/api_gateway/operations/operations.py +++ b/src/cloudflare/resources/api_gateway/operations/operations.py @@ -354,6 +354,7 @@ def get( *, zone_id: str, feature: List[Literal["thresholds", "parameter_schemas", "schema_info"]] | Omit = omit, + with_schemas: bool | Omit = omit, # 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, @@ -374,6 +375,10 @@ def get( to the resulting feature object. Have a look at the top-level object description for more details on the specific meaning. + with_schemas: When true, includes OpenAPI schemas (both uploaded and learned) for the + operation in the response. Due to the conversion overhead, this parameter is + only supported on single-operation retrieval. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -395,7 +400,13 @@ def get( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - query=maybe_transform({"feature": feature}, operation_get_params.OperationGetParams), + query=maybe_transform( + { + "feature": feature, + "with_schemas": with_schemas, + }, + operation_get_params.OperationGetParams, + ), post_parser=ResultWrapper[OperationGetResponse]._unwrapper, ), cast_to=cast(Type[OperationGetResponse], ResultWrapper[OperationGetResponse]), @@ -704,6 +715,7 @@ async def get( *, zone_id: str, feature: List[Literal["thresholds", "parameter_schemas", "schema_info"]] | Omit = omit, + with_schemas: bool | Omit = omit, # 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, @@ -724,6 +736,10 @@ async def get( to the resulting feature object. Have a look at the top-level object description for more details on the specific meaning. + with_schemas: When true, includes OpenAPI schemas (both uploaded and learned) for the + operation in the response. Due to the conversion overhead, this parameter is + only supported on single-operation retrieval. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -745,7 +761,13 @@ async def get( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - query=await async_maybe_transform({"feature": feature}, operation_get_params.OperationGetParams), + query=await async_maybe_transform( + { + "feature": feature, + "with_schemas": with_schemas, + }, + operation_get_params.OperationGetParams, + ), post_parser=ResultWrapper[OperationGetResponse]._unwrapper, ), cast_to=cast(Type[OperationGetResponse], ResultWrapper[OperationGetResponse]), diff --git a/src/cloudflare/resources/zero_trust/devices/policies/custom/custom.py b/src/cloudflare/resources/zero_trust/devices/policies/custom/custom.py index ae7b27236a8..ee4baacac41 100644 --- a/src/cloudflare/resources/zero_trust/devices/policies/custom/custom.py +++ b/src/cloudflare/resources/zero_trust/devices/policies/custom/custom.py @@ -109,6 +109,7 @@ def create( support_url: str | Omit = omit, switch_locked: bool | Omit = omit, tunnel_protocol: str | Omit = omit, + virtual_networks: Optional[custom_create_params.VirtualNetworks] | Omit = omit, # 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, @@ -178,6 +179,8 @@ def create( tunnel_protocol: Determines which tunnel protocol to use. + virtual_networks: Virtual network access settings for the device. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -214,6 +217,7 @@ def create( "support_url": support_url, "switch_locked": switch_locked, "tunnel_protocol": tunnel_protocol, + "virtual_networks": virtual_networks, }, custom_create_params.CustomCreateParams, ), @@ -329,6 +333,7 @@ def edit( support_url: str | Omit = omit, switch_locked: bool | Omit = omit, tunnel_protocol: str | Omit = omit, + virtual_networks: Optional[custom_edit_params.VirtualNetworks] | Omit = omit, # 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, @@ -397,6 +402,8 @@ def edit( tunnel_protocol: Determines which tunnel protocol to use. + virtual_networks: Virtual network access settings for the device. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -437,6 +444,7 @@ def edit( "support_url": support_url, "switch_locked": switch_locked, "tunnel_protocol": tunnel_protocol, + "virtual_networks": virtual_networks, }, custom_edit_params.CustomEditParams, ), @@ -551,6 +559,7 @@ async def create( support_url: str | Omit = omit, switch_locked: bool | Omit = omit, tunnel_protocol: str | Omit = omit, + virtual_networks: Optional[custom_create_params.VirtualNetworks] | Omit = omit, # 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, @@ -620,6 +629,8 @@ async def create( tunnel_protocol: Determines which tunnel protocol to use. + virtual_networks: Virtual network access settings for the device. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -656,6 +667,7 @@ async def create( "support_url": support_url, "switch_locked": switch_locked, "tunnel_protocol": tunnel_protocol, + "virtual_networks": virtual_networks, }, custom_create_params.CustomCreateParams, ), @@ -771,6 +783,7 @@ async def edit( support_url: str | Omit = omit, switch_locked: bool | Omit = omit, tunnel_protocol: str | Omit = omit, + virtual_networks: Optional[custom_edit_params.VirtualNetworks] | Omit = omit, # 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, @@ -839,6 +852,8 @@ async def edit( tunnel_protocol: Determines which tunnel protocol to use. + virtual_networks: Virtual network access settings for the device. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -879,6 +894,7 @@ async def edit( "support_url": support_url, "switch_locked": switch_locked, "tunnel_protocol": tunnel_protocol, + "virtual_networks": virtual_networks, }, custom_edit_params.CustomEditParams, ), diff --git a/src/cloudflare/resources/zero_trust/devices/policies/default/default.py b/src/cloudflare/resources/zero_trust/devices/policies/default/default.py index 42273b7fee8..cbe59b3adac 100644 --- a/src/cloudflare/resources/zero_trust/devices/policies/default/default.py +++ b/src/cloudflare/resources/zero_trust/devices/policies/default/default.py @@ -116,6 +116,7 @@ def edit( support_url: str | Omit = omit, switch_locked: bool | Omit = omit, tunnel_protocol: str | Omit = omit, + virtual_networks: Optional[default_edit_params.VirtualNetworks] | Omit = omit, # 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, @@ -170,6 +171,8 @@ def edit( tunnel_protocol: Determines which tunnel protocol to use. + virtual_networks: Virtual network access settings for the device. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -201,6 +204,7 @@ def edit( "support_url": support_url, "switch_locked": switch_locked, "tunnel_protocol": tunnel_protocol, + "virtual_networks": virtual_networks, }, default_edit_params.DefaultEditParams, ), @@ -309,6 +313,7 @@ async def edit( support_url: str | Omit = omit, switch_locked: bool | Omit = omit, tunnel_protocol: str | Omit = omit, + virtual_networks: Optional[default_edit_params.VirtualNetworks] | Omit = omit, # 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, @@ -363,6 +368,8 @@ async def edit( tunnel_protocol: Determines which tunnel protocol to use. + virtual_networks: Virtual network access settings for the device. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -394,6 +401,7 @@ async def edit( "support_url": support_url, "switch_locked": switch_locked, "tunnel_protocol": tunnel_protocol, + "virtual_networks": virtual_networks, }, default_edit_params.DefaultEditParams, ), diff --git a/src/cloudflare/types/api_gateway/operation_create_response.py b/src/cloudflare/types/api_gateway/operation_create_response.py index 3ca28f40890..594a8b7ad83 100644 --- a/src/cloudflare/types/api_gateway/operation_create_response.py +++ b/src/cloudflare/types/api_gateway/operation_create_response.py @@ -1,9 +1,11 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union, Optional +from typing import Dict, List, Union, Optional from datetime import datetime from typing_extensions import Literal, TypeAlias +from pydantic import Field as FieldInfo + from ..._models import BaseModel __all__ = [ @@ -26,6 +28,9 @@ "FeaturesAPIShieldOperationFeatureSchemaInfo", "FeaturesAPIShieldOperationFeatureSchemaInfoSchemaInfo", "FeaturesAPIShieldOperationFeatureSchemaInfoSchemaInfoActiveSchema", + "Schemas", + "SchemasLearned", + "SchemasUploaded", ] @@ -216,6 +221,50 @@ class FeaturesAPIShieldOperationFeatureSchemaInfo(BaseModel): ] +class SchemasLearned(BaseModel): + """ + An OpenAPI operation object fragment containing schema information for an operation. May include parameter definitions, request body specifications, and a component schema extension. + """ + + parameters: Optional[List[Dict[str, object]]] = None + """OpenAPI parameter objects describing path, query, header, or cookie parameters.""" + + request_body: Optional[Dict[str, object]] = FieldInfo(alias="requestBody", default=None) + """OpenAPI request body object describing the expected request payload.""" + + +class SchemasUploaded(BaseModel): + """ + An OpenAPI operation object fragment containing schema information for an operation. May include parameter definitions, request body specifications, and a component schema extension. + """ + + parameters: Optional[List[Dict[str, object]]] = None + """OpenAPI parameter objects describing path, query, header, or cookie parameters.""" + + request_body: Optional[Dict[str, object]] = FieldInfo(alias="requestBody", default=None) + """OpenAPI request body object describing the expected request payload.""" + + +class Schemas(BaseModel): + """ + OpenAPI JSON schemas for an operation, including both user-uploaded and Cloudflare-learned schemas. + """ + + learned: Optional[SchemasLearned] = None + """ + An OpenAPI operation object fragment containing schema information for an + operation. May include parameter definitions, request body specifications, and a + component schema extension. + """ + + uploaded: Optional[SchemasUploaded] = None + """ + An OpenAPI operation object fragment containing schema information for an + operation. May include parameter definitions, request body specifications, and a + component schema extension. + """ + + class OperationCreateResponse(BaseModel): endpoint: str """ @@ -237,3 +286,9 @@ class OperationCreateResponse(BaseModel): """UUID.""" features: Optional[Features] = None + + schemas: Optional[Schemas] = None + """ + OpenAPI JSON schemas for an operation, including both user-uploaded and + Cloudflare-learned schemas. + """ diff --git a/src/cloudflare/types/api_gateway/operation_get_params.py b/src/cloudflare/types/api_gateway/operation_get_params.py index 80b1e80e724..6fa124ecc14 100644 --- a/src/cloudflare/types/api_gateway/operation_get_params.py +++ b/src/cloudflare/types/api_gateway/operation_get_params.py @@ -19,3 +19,10 @@ class OperationGetParams(TypedDict, total=False): Have a look at the top-level object description for more details on the specific meaning. """ + + with_schemas: bool + """ + When true, includes OpenAPI schemas (both uploaded and learned) for the + operation in the response. Due to the conversion overhead, this parameter is + only supported on single-operation retrieval. + """ diff --git a/src/cloudflare/types/api_gateway/operation_get_response.py b/src/cloudflare/types/api_gateway/operation_get_response.py index 7c45d8d8431..d3407d93057 100644 --- a/src/cloudflare/types/api_gateway/operation_get_response.py +++ b/src/cloudflare/types/api_gateway/operation_get_response.py @@ -1,9 +1,11 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union, Optional +from typing import Dict, List, Union, Optional from datetime import datetime from typing_extensions import Literal, TypeAlias +from pydantic import Field as FieldInfo + from ..._models import BaseModel __all__ = [ @@ -26,6 +28,9 @@ "FeaturesAPIShieldOperationFeatureSchemaInfo", "FeaturesAPIShieldOperationFeatureSchemaInfoSchemaInfo", "FeaturesAPIShieldOperationFeatureSchemaInfoSchemaInfoActiveSchema", + "Schemas", + "SchemasLearned", + "SchemasUploaded", ] @@ -216,6 +221,50 @@ class FeaturesAPIShieldOperationFeatureSchemaInfo(BaseModel): ] +class SchemasLearned(BaseModel): + """ + An OpenAPI operation object fragment containing schema information for an operation. May include parameter definitions, request body specifications, and a component schema extension. + """ + + parameters: Optional[List[Dict[str, object]]] = None + """OpenAPI parameter objects describing path, query, header, or cookie parameters.""" + + request_body: Optional[Dict[str, object]] = FieldInfo(alias="requestBody", default=None) + """OpenAPI request body object describing the expected request payload.""" + + +class SchemasUploaded(BaseModel): + """ + An OpenAPI operation object fragment containing schema information for an operation. May include parameter definitions, request body specifications, and a component schema extension. + """ + + parameters: Optional[List[Dict[str, object]]] = None + """OpenAPI parameter objects describing path, query, header, or cookie parameters.""" + + request_body: Optional[Dict[str, object]] = FieldInfo(alias="requestBody", default=None) + """OpenAPI request body object describing the expected request payload.""" + + +class Schemas(BaseModel): + """ + OpenAPI JSON schemas for an operation, including both user-uploaded and Cloudflare-learned schemas. + """ + + learned: Optional[SchemasLearned] = None + """ + An OpenAPI operation object fragment containing schema information for an + operation. May include parameter definitions, request body specifications, and a + component schema extension. + """ + + uploaded: Optional[SchemasUploaded] = None + """ + An OpenAPI operation object fragment containing schema information for an + operation. May include parameter definitions, request body specifications, and a + component schema extension. + """ + + class OperationGetResponse(BaseModel): endpoint: str """ @@ -237,3 +286,9 @@ class OperationGetResponse(BaseModel): """UUID.""" features: Optional[Features] = None + + schemas: Optional[Schemas] = None + """ + OpenAPI JSON schemas for an operation, including both user-uploaded and + Cloudflare-learned schemas. + """ diff --git a/src/cloudflare/types/zero_trust/devices/kolide_input.py b/src/cloudflare/types/zero_trust/devices/kolide_input.py index a18da6e1fcc..34f8b1534a0 100644 --- a/src/cloudflare/types/zero_trust/devices/kolide_input.py +++ b/src/cloudflare/types/zero_trust/devices/kolide_input.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Optional +from typing import Optional from typing_extensions import Literal from pydantic import Field as FieldInfo @@ -14,12 +14,6 @@ class KolideInput(BaseModel): connection_id: str """Posture Integration ID.""" - auth_state: Optional[List[Literal["Good", "Notified", "Will Block", "Blocked"]]] = None - """The set of Kolide device authentication states that pass the posture check. - - Device must match one of the specified states. - """ - count_operator: Optional[Literal["<", "<=", ">", ">=", "=="]] = FieldInfo(alias="countOperator", default=None) """Count Operator.""" diff --git a/src/cloudflare/types/zero_trust/devices/kolide_input_param.py b/src/cloudflare/types/zero_trust/devices/kolide_input_param.py index 85990a105bb..2876e3bc9b6 100644 --- a/src/cloudflare/types/zero_trust/devices/kolide_input_param.py +++ b/src/cloudflare/types/zero_trust/devices/kolide_input_param.py @@ -2,7 +2,6 @@ from __future__ import annotations -from typing import List from typing_extensions import Literal, Required, Annotated, TypedDict from ...._utils import PropertyInfo @@ -14,12 +13,6 @@ class KolideInputParam(TypedDict, total=False): connection_id: Required[str] """Posture Integration ID.""" - auth_state: List[Literal["Good", "Notified", "Will Block", "Blocked"]] - """The set of Kolide device authentication states that pass the posture check. - - Device must match one of the specified states. - """ - count_operator: Annotated[Literal["<", "<=", ">", ">=", "=="], PropertyInfo(alias="countOperator")] """Count Operator.""" diff --git a/src/cloudflare/types/zero_trust/devices/policies/custom_create_params.py b/src/cloudflare/types/zero_trust/devices/policies/custom_create_params.py index d2302201175..2712f2391aa 100644 --- a/src/cloudflare/types/zero_trust/devices/policies/custom_create_params.py +++ b/src/cloudflare/types/zero_trust/devices/policies/custom_create_params.py @@ -2,13 +2,14 @@ from __future__ import annotations -from typing import Iterable +from typing import Iterable, Optional from typing_extensions import Required, TypedDict +from ....._types import SequenceNotStr from ..split_tunnel_exclude_param import SplitTunnelExcludeParam from ..split_tunnel_include_param import SplitTunnelIncludeParam -__all__ = ["CustomCreateParams", "ServiceModeV2"] +__all__ = ["CustomCreateParams", "ServiceModeV2", "VirtualNetworks"] class CustomCreateParams(TypedDict, total=False): @@ -117,6 +118,9 @@ class CustomCreateParams(TypedDict, total=False): tunnel_protocol: str """Determines which tunnel protocol to use.""" + virtual_networks: Optional[VirtualNetworks] + """Virtual network access settings for the device.""" + class ServiceModeV2(TypedDict, total=False): mode: str @@ -124,3 +128,16 @@ class ServiceModeV2(TypedDict, total=False): port: float """The port number when used with proxy mode.""" + + +class VirtualNetworks(TypedDict, total=False): + """Virtual network access settings for the device.""" + + allowed: Required[SequenceNotStr[str]] + """List of virtual network IDs the device is allowed to access. + + When virtual_networks is set, at least one entry is required. + """ + + default: Required[str] + """The default virtual network ID. Must be included in the `allowed` list.""" diff --git a/src/cloudflare/types/zero_trust/devices/policies/custom_edit_params.py b/src/cloudflare/types/zero_trust/devices/policies/custom_edit_params.py index 85e7e19bd3c..004fb5454bd 100644 --- a/src/cloudflare/types/zero_trust/devices/policies/custom_edit_params.py +++ b/src/cloudflare/types/zero_trust/devices/policies/custom_edit_params.py @@ -2,13 +2,14 @@ from __future__ import annotations -from typing import Iterable +from typing import Iterable, Optional from typing_extensions import Required, TypedDict +from ....._types import SequenceNotStr from ..split_tunnel_exclude_param import SplitTunnelExcludeParam from ..split_tunnel_include_param import SplitTunnelIncludeParam -__all__ = ["CustomEditParams", "ServiceModeV2"] +__all__ = ["CustomEditParams", "ServiceModeV2", "VirtualNetworks"] class CustomEditParams(TypedDict, total=False): @@ -117,6 +118,9 @@ class CustomEditParams(TypedDict, total=False): tunnel_protocol: str """Determines which tunnel protocol to use.""" + virtual_networks: Optional[VirtualNetworks] + """Virtual network access settings for the device.""" + class ServiceModeV2(TypedDict, total=False): mode: str @@ -124,3 +128,16 @@ class ServiceModeV2(TypedDict, total=False): port: float """The port number when used with proxy mode.""" + + +class VirtualNetworks(TypedDict, total=False): + """Virtual network access settings for the device.""" + + allowed: Required[SequenceNotStr[str]] + """List of virtual network IDs the device is allowed to access. + + When virtual_networks is set, at least one entry is required. + """ + + default: Required[str] + """The default virtual network ID. Must be included in the `allowed` list.""" diff --git a/src/cloudflare/types/zero_trust/devices/policies/default_edit_params.py b/src/cloudflare/types/zero_trust/devices/policies/default_edit_params.py index 9a6b533464c..74eb2e3ce42 100644 --- a/src/cloudflare/types/zero_trust/devices/policies/default_edit_params.py +++ b/src/cloudflare/types/zero_trust/devices/policies/default_edit_params.py @@ -2,13 +2,14 @@ from __future__ import annotations -from typing import Iterable +from typing import Iterable, Optional from typing_extensions import Required, TypedDict +from ....._types import SequenceNotStr from ..split_tunnel_exclude_param import SplitTunnelExcludeParam from ..split_tunnel_include_param import SplitTunnelIncludeParam -__all__ = ["DefaultEditParams", "ServiceModeV2"] +__all__ = ["DefaultEditParams", "ServiceModeV2", "VirtualNetworks"] class DefaultEditParams(TypedDict, total=False): @@ -93,6 +94,9 @@ class DefaultEditParams(TypedDict, total=False): tunnel_protocol: str """Determines which tunnel protocol to use.""" + virtual_networks: Optional[VirtualNetworks] + """Virtual network access settings for the device.""" + class ServiceModeV2(TypedDict, total=False): mode: str @@ -100,3 +104,16 @@ class ServiceModeV2(TypedDict, total=False): port: float """The port number when used with proxy mode.""" + + +class VirtualNetworks(TypedDict, total=False): + """Virtual network access settings for the device.""" + + allowed: Required[SequenceNotStr[str]] + """List of virtual network IDs the device is allowed to access. + + When virtual_networks is set, at least one entry is required. + """ + + default: Required[str] + """The default virtual network ID. Must be included in the `allowed` list.""" diff --git a/src/cloudflare/types/zero_trust/devices/policies/default_edit_response.py b/src/cloudflare/types/zero_trust/devices/policies/default_edit_response.py index 4e512a63abc..d1eb4dca9d1 100644 --- a/src/cloudflare/types/zero_trust/devices/policies/default_edit_response.py +++ b/src/cloudflare/types/zero_trust/devices/policies/default_edit_response.py @@ -7,7 +7,7 @@ from ..split_tunnel_exclude import SplitTunnelExclude from ..split_tunnel_include import SplitTunnelInclude -__all__ = ["DefaultEditResponse", "ServiceModeV2"] +__all__ = ["DefaultEditResponse", "ServiceModeV2", "VirtualNetworks"] class ServiceModeV2(BaseModel): @@ -18,6 +18,19 @@ class ServiceModeV2(BaseModel): """The port number when used with proxy mode.""" +class VirtualNetworks(BaseModel): + """Virtual network access settings for the device.""" + + allowed: List[str] + """List of virtual network IDs the device is allowed to access. + + When virtual_networks is set, at least one entry is required. + """ + + default: str + """The default virtual network ID. Must be included in the `allowed` list.""" + + class DefaultEditResponse(BaseModel): allow_mode_switch: Optional[bool] = None """Whether to allow the user to switch WARP between modes.""" @@ -89,3 +102,6 @@ class DefaultEditResponse(BaseModel): tunnel_protocol: Optional[str] = None """Determines which tunnel protocol to use.""" + + virtual_networks: Optional[VirtualNetworks] = None + """Virtual network access settings for the device.""" diff --git a/src/cloudflare/types/zero_trust/devices/policies/default_get_response.py b/src/cloudflare/types/zero_trust/devices/policies/default_get_response.py index acdfa643df3..4fe0811461d 100644 --- a/src/cloudflare/types/zero_trust/devices/policies/default_get_response.py +++ b/src/cloudflare/types/zero_trust/devices/policies/default_get_response.py @@ -7,7 +7,7 @@ from ..split_tunnel_exclude import SplitTunnelExclude from ..split_tunnel_include import SplitTunnelInclude -__all__ = ["DefaultGetResponse", "ServiceModeV2"] +__all__ = ["DefaultGetResponse", "ServiceModeV2", "VirtualNetworks"] class ServiceModeV2(BaseModel): @@ -18,6 +18,19 @@ class ServiceModeV2(BaseModel): """The port number when used with proxy mode.""" +class VirtualNetworks(BaseModel): + """Virtual network access settings for the device.""" + + allowed: List[str] + """List of virtual network IDs the device is allowed to access. + + When virtual_networks is set, at least one entry is required. + """ + + default: str + """The default virtual network ID. Must be included in the `allowed` list.""" + + class DefaultGetResponse(BaseModel): allow_mode_switch: Optional[bool] = None """Whether to allow the user to switch WARP between modes.""" @@ -89,3 +102,6 @@ class DefaultGetResponse(BaseModel): tunnel_protocol: Optional[str] = None """Determines which tunnel protocol to use.""" + + virtual_networks: Optional[VirtualNetworks] = None + """Virtual network access settings for the device.""" diff --git a/src/cloudflare/types/zero_trust/devices/settings_policy.py b/src/cloudflare/types/zero_trust/devices/settings_policy.py index dfc7f7ae559..0dbbe0ea2e2 100644 --- a/src/cloudflare/types/zero_trust/devices/settings_policy.py +++ b/src/cloudflare/types/zero_trust/devices/settings_policy.py @@ -7,7 +7,7 @@ from .split_tunnel_exclude import SplitTunnelExclude from .split_tunnel_include import SplitTunnelInclude -__all__ = ["SettingsPolicy", "ServiceModeV2", "TargetTest"] +__all__ = ["SettingsPolicy", "ServiceModeV2", "TargetTest", "VirtualNetworks"] class ServiceModeV2(BaseModel): @@ -26,6 +26,19 @@ class TargetTest(BaseModel): """The name of the DEX test targeting this policy.""" +class VirtualNetworks(BaseModel): + """Virtual network access settings for the device.""" + + allowed: List[str] + """List of virtual network IDs the device is allowed to access. + + When virtual_networks is set, at least one entry is required. + """ + + default: str + """The default virtual network ID. Must be included in the `allowed` list.""" + + class SettingsPolicy(BaseModel): allow_mode_switch: Optional[bool] = None """Whether to allow the user to switch WARP between modes.""" @@ -134,3 +147,6 @@ class SettingsPolicy(BaseModel): tunnel_protocol: Optional[str] = None """Determines which tunnel protocol to use.""" + + virtual_networks: Optional[VirtualNetworks] = None + """Virtual network access settings for the device.""" diff --git a/tests/api_resources/api_gateway/test_operations.py b/tests/api_resources/api_gateway/test_operations.py index aab5d1b4997..03ad915d493 100644 --- a/tests/api_resources/api_gateway/test_operations.py +++ b/tests/api_resources/api_gateway/test_operations.py @@ -294,6 +294,7 @@ def test_method_get_with_all_params(self, client: Cloudflare) -> None: operation_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", zone_id="023e105f4ecef8ad9ca31a8372d0c353", feature=["thresholds"], + with_schemas=True, ) assert_matches_type(OperationGetResponse, operation, path=["response"]) @@ -612,6 +613,7 @@ async def test_method_get_with_all_params(self, async_client: AsyncCloudflare) - operation_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", zone_id="023e105f4ecef8ad9ca31a8372d0c353", feature=["thresholds"], + with_schemas=True, ) assert_matches_type(OperationGetResponse, operation, path=["response"]) diff --git a/tests/api_resources/zero_trust/devices/policies/test_custom.py b/tests/api_resources/zero_trust/devices/policies/test_custom.py index 324311c25b8..2579fa98389 100644 --- a/tests/api_resources/zero_trust/devices/policies/test_custom.py +++ b/tests/api_resources/zero_trust/devices/policies/test_custom.py @@ -69,6 +69,10 @@ def test_method_create_with_all_params(self, client: Cloudflare) -> None: support_url="https://1.1.1.1/help", switch_locked=True, tunnel_protocol="wireguard", + virtual_networks={ + "allowed": ["f174e90a-fafe-4643-bbbc-4a0ed4fc8415"], + "default": "f174e90a-fafe-4643-bbbc-4a0ed4fc8415", + }, ) assert_matches_type(Optional[SettingsPolicy], custom, path=["response"]) @@ -251,6 +255,10 @@ def test_method_edit_with_all_params(self, client: Cloudflare) -> None: support_url="https://1.1.1.1/help", switch_locked=True, tunnel_protocol="wireguard", + virtual_networks={ + "allowed": ["f174e90a-fafe-4643-bbbc-4a0ed4fc8415"], + "default": "f174e90a-fafe-4643-bbbc-4a0ed4fc8415", + }, ) assert_matches_type(Optional[SettingsPolicy], custom, path=["response"]) @@ -406,6 +414,10 @@ async def test_method_create_with_all_params(self, async_client: AsyncCloudflare support_url="https://1.1.1.1/help", switch_locked=True, tunnel_protocol="wireguard", + virtual_networks={ + "allowed": ["f174e90a-fafe-4643-bbbc-4a0ed4fc8415"], + "default": "f174e90a-fafe-4643-bbbc-4a0ed4fc8415", + }, ) assert_matches_type(Optional[SettingsPolicy], custom, path=["response"]) @@ -588,6 +600,10 @@ async def test_method_edit_with_all_params(self, async_client: AsyncCloudflare) support_url="https://1.1.1.1/help", switch_locked=True, tunnel_protocol="wireguard", + virtual_networks={ + "allowed": ["f174e90a-fafe-4643-bbbc-4a0ed4fc8415"], + "default": "f174e90a-fafe-4643-bbbc-4a0ed4fc8415", + }, ) assert_matches_type(Optional[SettingsPolicy], custom, path=["response"]) diff --git a/tests/api_resources/zero_trust/devices/policies/test_default.py b/tests/api_resources/zero_trust/devices/policies/test_default.py index 4e6dce31427..2c5d907468e 100644 --- a/tests/api_resources/zero_trust/devices/policies/test_default.py +++ b/tests/api_resources/zero_trust/devices/policies/test_default.py @@ -58,6 +58,10 @@ def test_method_edit_with_all_params(self, client: Cloudflare) -> None: support_url="https://1.1.1.1/help", switch_locked=True, tunnel_protocol="wireguard", + virtual_networks={ + "allowed": ["f174e90a-fafe-4643-bbbc-4a0ed4fc8415"], + "default": "f174e90a-fafe-4643-bbbc-4a0ed4fc8415", + }, ) assert_matches_type(Optional[DefaultEditResponse], default, path=["response"]) @@ -177,6 +181,10 @@ async def test_method_edit_with_all_params(self, async_client: AsyncCloudflare) support_url="https://1.1.1.1/help", switch_locked=True, tunnel_protocol="wireguard", + virtual_networks={ + "allowed": ["f174e90a-fafe-4643-bbbc-4a0ed4fc8415"], + "default": "f174e90a-fafe-4643-bbbc-4a0ed4fc8415", + }, ) assert_matches_type(Optional[DefaultEditResponse], default, path=["response"]) From 68ea77d60a1b1dc2f4e823693496dac4a50d0b42 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 29 Apr 2026 16:33:08 -0400 Subject: [PATCH 13/45] chore(api): update composite API spec --- .stats.yml | 8 +- src/cloudflare/resources/botnet_feed/asn.py | 0 .../resources/botnet_feed/botnet_feed.py | 0 .../resources/botnet_feed/configs/__init__.py | 0 .../resources/botnet_feed/configs/asn.py | 0 .../resources/botnet_feed/configs/configs.py | 0 .../resources/email_security/api.md | 57 ++- .../email_security/investigate/__init__.py | 56 +++ .../email_security/investigate/detections.py | 199 +++++++++ .../email_security/investigate/investigate.py | 260 ++++++++++- .../email_security/investigate/move.py | 119 ++++- .../email_security/investigate/preview.py | 111 +++++ .../email_security/investigate/raw.py | 197 +++++++++ .../email_security/investigate/reclassify.py | 230 ++++++++++ .../email_security/investigate/trace.py | 203 +++++++++ .../settings/impersonation_registry.py | 413 +++++++++++++++++- src/cloudflare/resources/magic_transit/api.md | 2 +- .../magic_transit/connectors/connectors.py | 25 +- .../applications/policy_tests/__init__.py | 0 .../applications/policy_tests/policy_tests.py | 0 .../access/applications/policy_tests/users.py | 0 .../dlp/datasets/versions/__init__.py | 0 .../dlp/datasets/versions/entries.py | 0 .../dlp/datasets/versions/versions.py | 0 .../resources/zero_trust/dlp/limits.py | 0 .../gateway/configurations/__init__.py | 0 .../gateway/configurations/configurations.py | 0 .../types/accounts/account_create_params.py | 0 .../types/accounts/account_delete_response.py | 0 .../botnet_feed/asn_day_report_params.py | 0 .../botnet_feed/asn_day_report_response.py | 0 .../botnet_feed/asn_full_report_response.py | 0 .../configs/asn_delete_response.py | 0 .../botnet_feed/configs/asn_get_response.py | 0 .../types/email_security/__init__.py | 2 + .../email_security/investigate/__init__.py | 7 + .../investigate/detection_get_response.py | 169 +++++++ .../investigate/move_create_params.py | 16 + .../investigate/move_create_response.py | 37 ++ .../investigate/preview_get_response.py | 10 + .../investigate/raw_get_response.py | 10 + .../investigate/reclassify_create_params.py | 19 + .../investigate/trace_get_response.py | 50 +++ .../email_security/investigate_get_params.py | 18 + .../investigate_get_response.py | 233 ++++++++++ .../types/email_security/settings/__init__.py | 6 + .../impersonation_registry_delete_response.py | 10 + .../impersonation_registry_edit_params.py | 29 ++ .../impersonation_registry_edit_response.py | 41 ++ .../impersonation_registry_get_response.py | 41 ++ .../types/magic_transit/__init__.py | 1 + .../connector_create_response.py | 2 + .../connector_delete_response.py | 2 + .../magic_transit/connector_edit_response.py | 2 + .../magic_transit/connector_get_response.py | 2 + .../magic_transit/connector_list_params.py | 15 + .../magic_transit/connector_list_response.py | 2 + .../connector_update_response.py | 2 + .../types/r2/bucket_list_response.py | 0 .../namespaces/scripts/secret_get_response.py | 0 .../applications/policy_test_create_params.py | 0 .../policy_test_create_response.py | 0 .../applications/policy_test_get_response.py | 0 .../policy_tests/user_list_response.py | 0 .../zero_trust/devices/setting_edit_params.py | 0 .../dlp/datasets/version_create_params.py | 0 .../dlp/datasets/version_create_response.py | 0 .../datasets/versions/entry_create_params.py | 0 .../versions/entry_create_response.py | 0 .../zero_trust/dlp/limit_list_response.py | 0 .../zero_trust/dlp/profile_list_params.py | 0 .../botnet_feed/configs/__init__.py | 0 .../botnet_feed/configs/test_asn.py | 0 tests/api_resources/botnet_feed/test_asn.py | 0 .../investigate/test_detections.py | 120 +++++ .../email_security/investigate/test_move.py | 111 ++++- .../investigate/test_preview.py | 98 ++++- .../email_security/investigate/test_raw.py | 120 +++++ .../investigate/test_reclassify.py | 151 +++++++ .../email_security/investigate/test_trace.py | 120 +++++ .../settings/test_impersonation_registry.py | 339 ++++++++++++++ .../email_security/test_investigate.py | 119 ++++- .../magic_transit/test_connectors.py | 16 + .../applications/policy_tests/__init__.py | 0 .../applications/policy_tests/test_users.py | 0 .../access/applications/test_policy_tests.py | 0 .../zero_trust/dlp/datasets/test_versions.py | 0 .../dlp/datasets/versions/__init__.py | 0 .../dlp/datasets/versions/test_entries.py | 0 .../zero_trust/dlp/test_limits.py | 0 .../gateway/configurations/__init__.py | 0 91 files changed, 3781 insertions(+), 19 deletions(-) mode change 100755 => 100644 src/cloudflare/resources/botnet_feed/asn.py mode change 100755 => 100644 src/cloudflare/resources/botnet_feed/botnet_feed.py mode change 100755 => 100644 src/cloudflare/resources/botnet_feed/configs/__init__.py mode change 100755 => 100644 src/cloudflare/resources/botnet_feed/configs/asn.py mode change 100755 => 100644 src/cloudflare/resources/botnet_feed/configs/configs.py create mode 100644 src/cloudflare/resources/email_security/investigate/detections.py create mode 100644 src/cloudflare/resources/email_security/investigate/raw.py create mode 100644 src/cloudflare/resources/email_security/investigate/reclassify.py create mode 100644 src/cloudflare/resources/email_security/investigate/trace.py mode change 100755 => 100644 src/cloudflare/resources/zero_trust/access/applications/policy_tests/__init__.py mode change 100755 => 100644 src/cloudflare/resources/zero_trust/access/applications/policy_tests/policy_tests.py mode change 100755 => 100644 src/cloudflare/resources/zero_trust/access/applications/policy_tests/users.py mode change 100755 => 100644 src/cloudflare/resources/zero_trust/dlp/datasets/versions/__init__.py mode change 100755 => 100644 src/cloudflare/resources/zero_trust/dlp/datasets/versions/entries.py mode change 100755 => 100644 src/cloudflare/resources/zero_trust/dlp/datasets/versions/versions.py mode change 100755 => 100644 src/cloudflare/resources/zero_trust/dlp/limits.py mode change 100755 => 100644 src/cloudflare/resources/zero_trust/gateway/configurations/__init__.py mode change 100755 => 100644 src/cloudflare/resources/zero_trust/gateway/configurations/configurations.py mode change 100755 => 100644 src/cloudflare/types/accounts/account_create_params.py mode change 100755 => 100644 src/cloudflare/types/accounts/account_delete_response.py mode change 100755 => 100644 src/cloudflare/types/botnet_feed/asn_day_report_params.py mode change 100755 => 100644 src/cloudflare/types/botnet_feed/asn_day_report_response.py mode change 100755 => 100644 src/cloudflare/types/botnet_feed/asn_full_report_response.py mode change 100755 => 100644 src/cloudflare/types/botnet_feed/configs/asn_delete_response.py mode change 100755 => 100644 src/cloudflare/types/botnet_feed/configs/asn_get_response.py create mode 100644 src/cloudflare/types/email_security/investigate/detection_get_response.py create mode 100644 src/cloudflare/types/email_security/investigate/move_create_params.py create mode 100644 src/cloudflare/types/email_security/investigate/move_create_response.py create mode 100644 src/cloudflare/types/email_security/investigate/preview_get_response.py create mode 100644 src/cloudflare/types/email_security/investigate/raw_get_response.py create mode 100644 src/cloudflare/types/email_security/investigate/reclassify_create_params.py create mode 100644 src/cloudflare/types/email_security/investigate/trace_get_response.py create mode 100644 src/cloudflare/types/email_security/investigate_get_params.py create mode 100644 src/cloudflare/types/email_security/investigate_get_response.py create mode 100644 src/cloudflare/types/email_security/settings/impersonation_registry_delete_response.py create mode 100644 src/cloudflare/types/email_security/settings/impersonation_registry_edit_params.py create mode 100644 src/cloudflare/types/email_security/settings/impersonation_registry_edit_response.py create mode 100644 src/cloudflare/types/email_security/settings/impersonation_registry_get_response.py create mode 100644 src/cloudflare/types/magic_transit/connector_list_params.py mode change 100755 => 100644 src/cloudflare/types/r2/bucket_list_response.py mode change 100755 => 100644 src/cloudflare/types/workers_for_platforms/dispatch/namespaces/scripts/secret_get_response.py mode change 100755 => 100644 src/cloudflare/types/zero_trust/access/applications/policy_test_create_params.py mode change 100755 => 100644 src/cloudflare/types/zero_trust/access/applications/policy_test_create_response.py mode change 100755 => 100644 src/cloudflare/types/zero_trust/access/applications/policy_test_get_response.py mode change 100755 => 100644 src/cloudflare/types/zero_trust/access/applications/policy_tests/user_list_response.py mode change 100755 => 100644 src/cloudflare/types/zero_trust/devices/setting_edit_params.py mode change 100755 => 100644 src/cloudflare/types/zero_trust/dlp/datasets/version_create_params.py mode change 100755 => 100644 src/cloudflare/types/zero_trust/dlp/datasets/version_create_response.py mode change 100755 => 100644 src/cloudflare/types/zero_trust/dlp/datasets/versions/entry_create_params.py mode change 100755 => 100644 src/cloudflare/types/zero_trust/dlp/datasets/versions/entry_create_response.py mode change 100755 => 100644 src/cloudflare/types/zero_trust/dlp/limit_list_response.py mode change 100755 => 100644 src/cloudflare/types/zero_trust/dlp/profile_list_params.py mode change 100755 => 100644 tests/api_resources/botnet_feed/configs/__init__.py mode change 100755 => 100644 tests/api_resources/botnet_feed/configs/test_asn.py mode change 100755 => 100644 tests/api_resources/botnet_feed/test_asn.py create mode 100644 tests/api_resources/email_security/investigate/test_detections.py create mode 100644 tests/api_resources/email_security/investigate/test_raw.py create mode 100644 tests/api_resources/email_security/investigate/test_reclassify.py create mode 100644 tests/api_resources/email_security/investigate/test_trace.py mode change 100755 => 100644 tests/api_resources/zero_trust/access/applications/policy_tests/__init__.py mode change 100755 => 100644 tests/api_resources/zero_trust/access/applications/policy_tests/test_users.py mode change 100755 => 100644 tests/api_resources/zero_trust/access/applications/test_policy_tests.py mode change 100755 => 100644 tests/api_resources/zero_trust/dlp/datasets/test_versions.py mode change 100755 => 100644 tests/api_resources/zero_trust/dlp/datasets/versions/__init__.py mode change 100755 => 100644 tests/api_resources/zero_trust/dlp/datasets/versions/test_entries.py mode change 100755 => 100644 tests/api_resources/zero_trust/dlp/test_limits.py mode change 100755 => 100644 tests/api_resources/zero_trust/gateway/configurations/__init__.py diff --git a/.stats.yml b/.stats.yml index fe4ebb85888..bb8578554e1 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 2185 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-ea5d30bcded86d4f9fca4175a9bfdd0713e6dea3b9224506ebf03c104e652df7.yml -openapi_spec_hash: 85e897c979f187c5170264420489e9f0 -config_hash: 95239e8fc62638979bc21e538307bbe3 +configured_endpoints: 2195 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a6c352830d1270d0abb5bb983058ea21815e1bb7d2e163965335dcb0e706f057.yml +openapi_spec_hash: 04d3f0746288b539043c14a9eaab066d +config_hash: 763a29f9838b6c535ff5a0e883bd3209 diff --git a/src/cloudflare/resources/botnet_feed/asn.py b/src/cloudflare/resources/botnet_feed/asn.py old mode 100755 new mode 100644 diff --git a/src/cloudflare/resources/botnet_feed/botnet_feed.py b/src/cloudflare/resources/botnet_feed/botnet_feed.py old mode 100755 new mode 100644 diff --git a/src/cloudflare/resources/botnet_feed/configs/__init__.py b/src/cloudflare/resources/botnet_feed/configs/__init__.py old mode 100755 new mode 100644 diff --git a/src/cloudflare/resources/botnet_feed/configs/asn.py b/src/cloudflare/resources/botnet_feed/configs/asn.py old mode 100755 new mode 100644 diff --git a/src/cloudflare/resources/botnet_feed/configs/configs.py b/src/cloudflare/resources/botnet_feed/configs/configs.py old mode 100755 new mode 100644 diff --git a/src/cloudflare/resources/email_security/api.md b/src/cloudflare/resources/email_security/api.md index 0584be64fa9..cfa43e12f75 100644 --- a/src/cloudflare/resources/email_security/api.md +++ b/src/cloudflare/resources/email_security/api.md @@ -5,37 +5,82 @@ Types: ```python -from cloudflare.types.email_security import InvestigateListResponse +from cloudflare.types.email_security import InvestigateListResponse, InvestigateGetResponse ``` Methods: - client.email_security.investigate.list(\*, account_id, \*\*params) -> SyncV4PagePaginationArray[InvestigateListResponse] +- client.email_security.investigate.get(investigate_id, \*, account_id, \*\*params) -> InvestigateGetResponse + +### Detections + +Types: + +```python +from cloudflare.types.email_security.investigate import DetectionGetResponse +``` + +Methods: + +- client.email_security.investigate.detections.get(investigate_id, \*, account_id) -> DetectionGetResponse ### Preview Types: ```python -from cloudflare.types.email_security.investigate import PreviewCreateResponse +from cloudflare.types.email_security.investigate import PreviewCreateResponse, PreviewGetResponse ``` Methods: - client.email_security.investigate.preview.create(\*, account_id, \*\*params) -> PreviewCreateResponse +- client.email_security.investigate.preview.get(investigate_id, \*, account_id) -> PreviewGetResponse + +### Raw + +Types: + +```python +from cloudflare.types.email_security.investigate import RawGetResponse +``` + +Methods: + +- client.email_security.investigate.raw.get(investigate_id, \*, account_id) -> RawGetResponse + +### Trace + +Types: + +```python +from cloudflare.types.email_security.investigate import TraceGetResponse +``` + +Methods: + +- client.email_security.investigate.trace.get(investigate_id, \*, account_id) -> TraceGetResponse ### Move Types: ```python -from cloudflare.types.email_security.investigate import MoveBulkResponse +from cloudflare.types.email_security.investigate import MoveCreateResponse, MoveBulkResponse ``` Methods: +- client.email_security.investigate.move.create(investigate_id, \*, account_id, \*\*params) -> SyncSinglePage[MoveCreateResponse] - client.email_security.investigate.move.bulk(\*, account_id, \*\*params) -> SyncSinglePage[MoveBulkResponse] +### Reclassify + +Methods: + +- client.email_security.investigate.reclassify.create(investigate_id, \*, account_id, \*\*params) -> object + ### Release Types: @@ -136,6 +181,9 @@ Types: from cloudflare.types.email_security.settings import ( ImpersonationRegistryCreateResponse, ImpersonationRegistryListResponse, + ImpersonationRegistryDeleteResponse, + ImpersonationRegistryEditResponse, + ImpersonationRegistryGetResponse, ) ``` @@ -143,6 +191,9 @@ Methods: - client.email_security.settings.impersonation_registry.create(\*, account_id, \*\*params) -> Optional[ImpersonationRegistryCreateResponse] - client.email_security.settings.impersonation_registry.list(\*, account_id, \*\*params) -> SyncV4PagePaginationArray[ImpersonationRegistryListResponse] +- client.email_security.settings.impersonation_registry.delete(impersonation_registry_id, \*, account_id) -> Optional[ImpersonationRegistryDeleteResponse] +- client.email_security.settings.impersonation_registry.edit(impersonation_registry_id, \*, account_id, \*\*params) -> Optional[ImpersonationRegistryEditResponse] +- client.email_security.settings.impersonation_registry.get(impersonation_registry_id, \*, account_id) -> Optional[ImpersonationRegistryGetResponse] ### TrustedDomains diff --git a/src/cloudflare/resources/email_security/investigate/__init__.py b/src/cloudflare/resources/email_security/investigate/__init__.py index 7de4ad936c0..5b206205771 100644 --- a/src/cloudflare/resources/email_security/investigate/__init__.py +++ b/src/cloudflare/resources/email_security/investigate/__init__.py @@ -1,5 +1,13 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from .raw import ( + RawResource, + AsyncRawResource, + RawResourceWithRawResponse, + AsyncRawResourceWithRawResponse, + RawResourceWithStreamingResponse, + AsyncRawResourceWithStreamingResponse, +) from .move import ( MoveResource, AsyncMoveResource, @@ -8,6 +16,14 @@ MoveResourceWithStreamingResponse, AsyncMoveResourceWithStreamingResponse, ) +from .trace import ( + TraceResource, + AsyncTraceResource, + TraceResourceWithRawResponse, + AsyncTraceResourceWithRawResponse, + TraceResourceWithStreamingResponse, + AsyncTraceResourceWithStreamingResponse, +) from .preview import ( PreviewResource, AsyncPreviewResource, @@ -24,6 +40,22 @@ ReleaseResourceWithStreamingResponse, AsyncReleaseResourceWithStreamingResponse, ) +from .detections import ( + DetectionsResource, + AsyncDetectionsResource, + DetectionsResourceWithRawResponse, + AsyncDetectionsResourceWithRawResponse, + DetectionsResourceWithStreamingResponse, + AsyncDetectionsResourceWithStreamingResponse, +) +from .reclassify import ( + ReclassifyResource, + AsyncReclassifyResource, + ReclassifyResourceWithRawResponse, + AsyncReclassifyResourceWithRawResponse, + ReclassifyResourceWithStreamingResponse, + AsyncReclassifyResourceWithStreamingResponse, +) from .investigate import ( InvestigateResource, AsyncInvestigateResource, @@ -34,18 +66,42 @@ ) __all__ = [ + "DetectionsResource", + "AsyncDetectionsResource", + "DetectionsResourceWithRawResponse", + "AsyncDetectionsResourceWithRawResponse", + "DetectionsResourceWithStreamingResponse", + "AsyncDetectionsResourceWithStreamingResponse", "PreviewResource", "AsyncPreviewResource", "PreviewResourceWithRawResponse", "AsyncPreviewResourceWithRawResponse", "PreviewResourceWithStreamingResponse", "AsyncPreviewResourceWithStreamingResponse", + "RawResource", + "AsyncRawResource", + "RawResourceWithRawResponse", + "AsyncRawResourceWithRawResponse", + "RawResourceWithStreamingResponse", + "AsyncRawResourceWithStreamingResponse", + "TraceResource", + "AsyncTraceResource", + "TraceResourceWithRawResponse", + "AsyncTraceResourceWithRawResponse", + "TraceResourceWithStreamingResponse", + "AsyncTraceResourceWithStreamingResponse", "MoveResource", "AsyncMoveResource", "MoveResourceWithRawResponse", "AsyncMoveResourceWithRawResponse", "MoveResourceWithStreamingResponse", "AsyncMoveResourceWithStreamingResponse", + "ReclassifyResource", + "AsyncReclassifyResource", + "ReclassifyResourceWithRawResponse", + "AsyncReclassifyResourceWithRawResponse", + "ReclassifyResourceWithStreamingResponse", + "AsyncReclassifyResourceWithStreamingResponse", "ReleaseResource", "AsyncReleaseResource", "ReleaseResourceWithRawResponse", diff --git a/src/cloudflare/resources/email_security/investigate/detections.py b/src/cloudflare/resources/email_security/investigate/detections.py new file mode 100644 index 00000000000..f53430d18c5 --- /dev/null +++ b/src/cloudflare/resources/email_security/investigate/detections.py @@ -0,0 +1,199 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Type, cast + +import httpx + +from ...._types import Body, Query, Headers, NotGiven, not_given +from ...._utils import path_template +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.email_security.investigate.detection_get_response import DetectionGetResponse + +__all__ = ["DetectionsResource", "AsyncDetectionsResource"] + + +class DetectionsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> DetectionsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 DetectionsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> DetectionsResourceWithStreamingResponse: + """ + 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 DetectionsResourceWithStreamingResponse(self) + + def get( + self, + investigate_id: str, + *, + 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, + ) -> DetectionGetResponse: + """ + Returns detection details such as threat categories and sender information for + non-benign messages. + + Args: + account_id: Identifier. + + investigate_id: Unique identifier for a message retrieved from investigation + + 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 investigate_id: + raise ValueError(f"Expected a non-empty value for `investigate_id` but received {investigate_id!r}") + return self._get( + path_template( + "/accounts/{account_id}/email-security/investigate/{investigate_id}/detections", + account_id=account_id, + investigate_id=investigate_id, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[DetectionGetResponse]._unwrapper, + ), + cast_to=cast(Type[DetectionGetResponse], ResultWrapper[DetectionGetResponse]), + ) + + +class AsyncDetectionsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncDetectionsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 AsyncDetectionsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncDetectionsResourceWithStreamingResponse: + """ + 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 AsyncDetectionsResourceWithStreamingResponse(self) + + async def get( + self, + investigate_id: str, + *, + 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, + ) -> DetectionGetResponse: + """ + Returns detection details such as threat categories and sender information for + non-benign messages. + + Args: + account_id: Identifier. + + investigate_id: Unique identifier for a message retrieved from investigation + + 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 investigate_id: + raise ValueError(f"Expected a non-empty value for `investigate_id` but received {investigate_id!r}") + return await self._get( + path_template( + "/accounts/{account_id}/email-security/investigate/{investigate_id}/detections", + account_id=account_id, + investigate_id=investigate_id, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[DetectionGetResponse]._unwrapper, + ), + cast_to=cast(Type[DetectionGetResponse], ResultWrapper[DetectionGetResponse]), + ) + + +class DetectionsResourceWithRawResponse: + def __init__(self, detections: DetectionsResource) -> None: + self._detections = detections + + self.get = to_raw_response_wrapper( + detections.get, + ) + + +class AsyncDetectionsResourceWithRawResponse: + def __init__(self, detections: AsyncDetectionsResource) -> None: + self._detections = detections + + self.get = async_to_raw_response_wrapper( + detections.get, + ) + + +class DetectionsResourceWithStreamingResponse: + def __init__(self, detections: DetectionsResource) -> None: + self._detections = detections + + self.get = to_streamed_response_wrapper( + detections.get, + ) + + +class AsyncDetectionsResourceWithStreamingResponse: + def __init__(self, detections: AsyncDetectionsResource) -> None: + self._detections = detections + + self.get = async_to_streamed_response_wrapper( + detections.get, + ) diff --git a/src/cloudflare/resources/email_security/investigate/investigate.py b/src/cloudflare/resources/email_security/investigate/investigate.py index 1b2bfa3f608..6572f57e9f6 100644 --- a/src/cloudflare/resources/email_security/investigate/investigate.py +++ b/src/cloudflare/resources/email_security/investigate/investigate.py @@ -2,12 +2,20 @@ from __future__ import annotations -from typing import Union, Optional +from typing import Type, Union, Optional, cast from datetime import datetime from typing_extensions import Literal import httpx +from .raw import ( + RawResource, + AsyncRawResource, + RawResourceWithRawResponse, + AsyncRawResourceWithRawResponse, + RawResourceWithStreamingResponse, + AsyncRawResourceWithStreamingResponse, +) from .move import ( MoveResource, AsyncMoveResource, @@ -16,6 +24,14 @@ MoveResourceWithStreamingResponse, AsyncMoveResourceWithStreamingResponse, ) +from .trace import ( + TraceResource, + AsyncTraceResource, + TraceResourceWithRawResponse, + AsyncTraceResourceWithRawResponse, + TraceResourceWithStreamingResponse, + AsyncTraceResourceWithStreamingResponse, +) from .preview import ( PreviewResource, AsyncPreviewResource, @@ -33,8 +49,24 @@ AsyncReleaseResourceWithStreamingResponse, ) from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import path_template, maybe_transform +from ...._utils import path_template, maybe_transform, async_maybe_transform from ...._compat import cached_property +from .detections import ( + DetectionsResource, + AsyncDetectionsResource, + DetectionsResourceWithRawResponse, + AsyncDetectionsResourceWithRawResponse, + DetectionsResourceWithStreamingResponse, + AsyncDetectionsResourceWithStreamingResponse, +) +from .reclassify import ( + ReclassifyResource, + AsyncReclassifyResource, + ReclassifyResourceWithRawResponse, + AsyncReclassifyResourceWithRawResponse, + ReclassifyResourceWithStreamingResponse, + AsyncReclassifyResourceWithStreamingResponse, +) from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import ( to_raw_response_wrapper, @@ -42,23 +74,41 @@ async_to_raw_response_wrapper, async_to_streamed_response_wrapper, ) +from ...._wrappers import ResultWrapper from ....pagination import SyncV4PagePaginationArray, AsyncV4PagePaginationArray from ...._base_client import AsyncPaginator, make_request_options -from ....types.email_security import investigate_list_params +from ....types.email_security import investigate_get_params, investigate_list_params +from ....types.email_security.investigate_get_response import InvestigateGetResponse from ....types.email_security.investigate_list_response import InvestigateListResponse __all__ = ["InvestigateResource", "AsyncInvestigateResource"] class InvestigateResource(SyncAPIResource): + @cached_property + def detections(self) -> DetectionsResource: + return DetectionsResource(self._client) + @cached_property def preview(self) -> PreviewResource: return PreviewResource(self._client) + @cached_property + def raw(self) -> RawResource: + return RawResource(self._client) + + @cached_property + def trace(self) -> TraceResource: + return TraceResource(self._client) + @cached_property def move(self) -> MoveResource: return MoveResource(self._client) + @cached_property + def reclassify(self) -> ReclassifyResource: + return ReclassifyResource(self._client) + @cached_property def release(self) -> ReleaseResource: return ReleaseResource(self._client) @@ -180,16 +230,87 @@ def list( model=InvestigateListResponse, ) + def get( + self, + investigate_id: str, + *, + account_id: str, + submission: bool | Omit = omit, + # 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, + ) -> InvestigateGetResponse: + """ + Retrieves comprehensive details for a specific email message including headers, + recipients, sender information, and current quarantine status. Use the + investigate_id from search results to fetch detailed information. + + Args: + account_id: Identifier. + + investigate_id: Unique identifier for a message retrieved from investigation + + submission: When true, search the submissions datastore only. When false or omitted, search + the regular datastore only. + + 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 investigate_id: + raise ValueError(f"Expected a non-empty value for `investigate_id` but received {investigate_id!r}") + return self._get( + path_template( + "/accounts/{account_id}/email-security/investigate/{investigate_id}", + account_id=account_id, + investigate_id=investigate_id, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"submission": submission}, investigate_get_params.InvestigateGetParams), + post_parser=ResultWrapper[InvestigateGetResponse]._unwrapper, + ), + cast_to=cast(Type[InvestigateGetResponse], ResultWrapper[InvestigateGetResponse]), + ) + class AsyncInvestigateResource(AsyncAPIResource): + @cached_property + def detections(self) -> AsyncDetectionsResource: + return AsyncDetectionsResource(self._client) + @cached_property def preview(self) -> AsyncPreviewResource: return AsyncPreviewResource(self._client) + @cached_property + def raw(self) -> AsyncRawResource: + return AsyncRawResource(self._client) + + @cached_property + def trace(self) -> AsyncTraceResource: + return AsyncTraceResource(self._client) + @cached_property def move(self) -> AsyncMoveResource: return AsyncMoveResource(self._client) + @cached_property + def reclassify(self) -> AsyncReclassifyResource: + return AsyncReclassifyResource(self._client) + @cached_property def release(self) -> AsyncReleaseResource: return AsyncReleaseResource(self._client) @@ -311,6 +432,63 @@ def list( model=InvestigateListResponse, ) + async def get( + self, + investigate_id: str, + *, + account_id: str, + submission: bool | Omit = omit, + # 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, + ) -> InvestigateGetResponse: + """ + Retrieves comprehensive details for a specific email message including headers, + recipients, sender information, and current quarantine status. Use the + investigate_id from search results to fetch detailed information. + + Args: + account_id: Identifier. + + investigate_id: Unique identifier for a message retrieved from investigation + + submission: When true, search the submissions datastore only. When false or omitted, search + the regular datastore only. + + 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 investigate_id: + raise ValueError(f"Expected a non-empty value for `investigate_id` but received {investigate_id!r}") + return await self._get( + path_template( + "/accounts/{account_id}/email-security/investigate/{investigate_id}", + account_id=account_id, + investigate_id=investigate_id, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + {"submission": submission}, investigate_get_params.InvestigateGetParams + ), + post_parser=ResultWrapper[InvestigateGetResponse]._unwrapper, + ), + cast_to=cast(Type[InvestigateGetResponse], ResultWrapper[InvestigateGetResponse]), + ) + class InvestigateResourceWithRawResponse: def __init__(self, investigate: InvestigateResource) -> None: @@ -319,15 +497,34 @@ def __init__(self, investigate: InvestigateResource) -> None: self.list = to_raw_response_wrapper( investigate.list, ) + self.get = to_raw_response_wrapper( + investigate.get, + ) + + @cached_property + def detections(self) -> DetectionsResourceWithRawResponse: + return DetectionsResourceWithRawResponse(self._investigate.detections) @cached_property def preview(self) -> PreviewResourceWithRawResponse: return PreviewResourceWithRawResponse(self._investigate.preview) + @cached_property + def raw(self) -> RawResourceWithRawResponse: + return RawResourceWithRawResponse(self._investigate.raw) + + @cached_property + def trace(self) -> TraceResourceWithRawResponse: + return TraceResourceWithRawResponse(self._investigate.trace) + @cached_property def move(self) -> MoveResourceWithRawResponse: return MoveResourceWithRawResponse(self._investigate.move) + @cached_property + def reclassify(self) -> ReclassifyResourceWithRawResponse: + return ReclassifyResourceWithRawResponse(self._investigate.reclassify) + @cached_property def release(self) -> ReleaseResourceWithRawResponse: return ReleaseResourceWithRawResponse(self._investigate.release) @@ -340,15 +537,34 @@ def __init__(self, investigate: AsyncInvestigateResource) -> None: self.list = async_to_raw_response_wrapper( investigate.list, ) + self.get = async_to_raw_response_wrapper( + investigate.get, + ) + + @cached_property + def detections(self) -> AsyncDetectionsResourceWithRawResponse: + return AsyncDetectionsResourceWithRawResponse(self._investigate.detections) @cached_property def preview(self) -> AsyncPreviewResourceWithRawResponse: return AsyncPreviewResourceWithRawResponse(self._investigate.preview) + @cached_property + def raw(self) -> AsyncRawResourceWithRawResponse: + return AsyncRawResourceWithRawResponse(self._investigate.raw) + + @cached_property + def trace(self) -> AsyncTraceResourceWithRawResponse: + return AsyncTraceResourceWithRawResponse(self._investigate.trace) + @cached_property def move(self) -> AsyncMoveResourceWithRawResponse: return AsyncMoveResourceWithRawResponse(self._investigate.move) + @cached_property + def reclassify(self) -> AsyncReclassifyResourceWithRawResponse: + return AsyncReclassifyResourceWithRawResponse(self._investigate.reclassify) + @cached_property def release(self) -> AsyncReleaseResourceWithRawResponse: return AsyncReleaseResourceWithRawResponse(self._investigate.release) @@ -361,15 +577,34 @@ def __init__(self, investigate: InvestigateResource) -> None: self.list = to_streamed_response_wrapper( investigate.list, ) + self.get = to_streamed_response_wrapper( + investigate.get, + ) + + @cached_property + def detections(self) -> DetectionsResourceWithStreamingResponse: + return DetectionsResourceWithStreamingResponse(self._investigate.detections) @cached_property def preview(self) -> PreviewResourceWithStreamingResponse: return PreviewResourceWithStreamingResponse(self._investigate.preview) + @cached_property + def raw(self) -> RawResourceWithStreamingResponse: + return RawResourceWithStreamingResponse(self._investigate.raw) + + @cached_property + def trace(self) -> TraceResourceWithStreamingResponse: + return TraceResourceWithStreamingResponse(self._investigate.trace) + @cached_property def move(self) -> MoveResourceWithStreamingResponse: return MoveResourceWithStreamingResponse(self._investigate.move) + @cached_property + def reclassify(self) -> ReclassifyResourceWithStreamingResponse: + return ReclassifyResourceWithStreamingResponse(self._investigate.reclassify) + @cached_property def release(self) -> ReleaseResourceWithStreamingResponse: return ReleaseResourceWithStreamingResponse(self._investigate.release) @@ -382,15 +617,34 @@ def __init__(self, investigate: AsyncInvestigateResource) -> None: self.list = async_to_streamed_response_wrapper( investigate.list, ) + self.get = async_to_streamed_response_wrapper( + investigate.get, + ) + + @cached_property + def detections(self) -> AsyncDetectionsResourceWithStreamingResponse: + return AsyncDetectionsResourceWithStreamingResponse(self._investigate.detections) @cached_property def preview(self) -> AsyncPreviewResourceWithStreamingResponse: return AsyncPreviewResourceWithStreamingResponse(self._investigate.preview) + @cached_property + def raw(self) -> AsyncRawResourceWithStreamingResponse: + return AsyncRawResourceWithStreamingResponse(self._investigate.raw) + + @cached_property + def trace(self) -> AsyncTraceResourceWithStreamingResponse: + return AsyncTraceResourceWithStreamingResponse(self._investigate.trace) + @cached_property def move(self) -> AsyncMoveResourceWithStreamingResponse: return AsyncMoveResourceWithStreamingResponse(self._investigate.move) + @cached_property + def reclassify(self) -> AsyncReclassifyResourceWithStreamingResponse: + return AsyncReclassifyResourceWithStreamingResponse(self._investigate.reclassify) + @cached_property def release(self) -> AsyncReleaseResourceWithStreamingResponse: return AsyncReleaseResourceWithStreamingResponse(self._investigate.release) diff --git a/src/cloudflare/resources/email_security/investigate/move.py b/src/cloudflare/resources/email_security/investigate/move.py index 52b6b073e5b..8fa530641c6 100644 --- a/src/cloudflare/resources/email_security/investigate/move.py +++ b/src/cloudflare/resources/email_security/investigate/move.py @@ -18,8 +18,9 @@ ) from ....pagination import SyncSinglePage, AsyncSinglePage from ...._base_client import AsyncPaginator, make_request_options -from ....types.email_security.investigate import move_bulk_params +from ....types.email_security.investigate import move_bulk_params, move_create_params from ....types.email_security.investigate.move_bulk_response import MoveBulkResponse +from ....types.email_security.investigate.move_create_response import MoveCreateResponse __all__ = ["MoveResource", "AsyncMoveResource"] @@ -44,6 +45,58 @@ def with_streaming_response(self) -> MoveResourceWithStreamingResponse: """ return MoveResourceWithStreamingResponse(self) + def create( + self, + investigate_id: str, + *, + account_id: str, + destination: Literal[ + "Inbox", "JunkEmail", "DeletedItems", "RecoverableItemsDeletions", "RecoverableItemsPurges" + ], + # 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, + ) -> SyncSinglePage[MoveCreateResponse]: + """ + Moves a single message to a specified mailbox folder (Inbox, JunkEmail, + DeletedItems, RecoverableItemsDeletions, or RecoverableItemsPurges). Requires + active integration. + + Args: + account_id: Identifier. + + investigate_id: Unique identifier for a message retrieved from investigation + + 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 investigate_id: + raise ValueError(f"Expected a non-empty value for `investigate_id` but received {investigate_id!r}") + return self._get_api_list( + path_template( + "/accounts/{account_id}/email-security/investigate/{investigate_id}/move", + account_id=account_id, + investigate_id=investigate_id, + ), + page=SyncSinglePage[MoveCreateResponse], + body=maybe_transform({"destination": destination}, move_create_params.MoveCreateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + model=MoveCreateResponse, + method="post", + ) + def bulk( self, *, @@ -122,6 +175,58 @@ def with_streaming_response(self) -> AsyncMoveResourceWithStreamingResponse: """ return AsyncMoveResourceWithStreamingResponse(self) + def create( + self, + investigate_id: str, + *, + account_id: str, + destination: Literal[ + "Inbox", "JunkEmail", "DeletedItems", "RecoverableItemsDeletions", "RecoverableItemsPurges" + ], + # 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[MoveCreateResponse, AsyncSinglePage[MoveCreateResponse]]: + """ + Moves a single message to a specified mailbox folder (Inbox, JunkEmail, + DeletedItems, RecoverableItemsDeletions, or RecoverableItemsPurges). Requires + active integration. + + Args: + account_id: Identifier. + + investigate_id: Unique identifier for a message retrieved from investigation + + 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 investigate_id: + raise ValueError(f"Expected a non-empty value for `investigate_id` but received {investigate_id!r}") + return self._get_api_list( + path_template( + "/accounts/{account_id}/email-security/investigate/{investigate_id}/move", + account_id=account_id, + investigate_id=investigate_id, + ), + page=AsyncSinglePage[MoveCreateResponse], + body=maybe_transform({"destination": destination}, move_create_params.MoveCreateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + model=MoveCreateResponse, + method="post", + ) + def bulk( self, *, @@ -184,6 +289,9 @@ class MoveResourceWithRawResponse: def __init__(self, move: MoveResource) -> None: self._move = move + self.create = to_raw_response_wrapper( + move.create, + ) self.bulk = to_raw_response_wrapper( move.bulk, ) @@ -193,6 +301,9 @@ class AsyncMoveResourceWithRawResponse: def __init__(self, move: AsyncMoveResource) -> None: self._move = move + self.create = async_to_raw_response_wrapper( + move.create, + ) self.bulk = async_to_raw_response_wrapper( move.bulk, ) @@ -202,6 +313,9 @@ class MoveResourceWithStreamingResponse: def __init__(self, move: MoveResource) -> None: self._move = move + self.create = to_streamed_response_wrapper( + move.create, + ) self.bulk = to_streamed_response_wrapper( move.bulk, ) @@ -211,6 +325,9 @@ class AsyncMoveResourceWithStreamingResponse: def __init__(self, move: AsyncMoveResource) -> None: self._move = move + self.create = async_to_streamed_response_wrapper( + move.create, + ) self.bulk = async_to_streamed_response_wrapper( move.bulk, ) diff --git a/src/cloudflare/resources/email_security/investigate/preview.py b/src/cloudflare/resources/email_security/investigate/preview.py index 7f582af0eb9..1bfbe97d41b 100644 --- a/src/cloudflare/resources/email_security/investigate/preview.py +++ b/src/cloudflare/resources/email_security/investigate/preview.py @@ -19,6 +19,7 @@ from ...._wrappers import ResultWrapper from ...._base_client import make_request_options from ....types.email_security.investigate import preview_create_params +from ....types.email_security.investigate.preview_get_response import PreviewGetResponse from ....types.email_security.investigate.preview_create_response import PreviewCreateResponse __all__ = ["PreviewResource", "AsyncPreviewResource"] @@ -89,6 +90,55 @@ def create( cast_to=cast(Type[PreviewCreateResponse], ResultWrapper[PreviewCreateResponse]), ) + def get( + self, + investigate_id: str, + *, + 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, + ) -> PreviewGetResponse: + """ + Returns a preview of the message body as a base64 encoded PNG image for + non-benign messages. + + Args: + account_id: Identifier. + + investigate_id: Unique identifier for a message retrieved from investigation + + 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 investigate_id: + raise ValueError(f"Expected a non-empty value for `investigate_id` but received {investigate_id!r}") + return self._get( + path_template( + "/accounts/{account_id}/email-security/investigate/{investigate_id}/preview", + account_id=account_id, + investigate_id=investigate_id, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[PreviewGetResponse]._unwrapper, + ), + cast_to=cast(Type[PreviewGetResponse], ResultWrapper[PreviewGetResponse]), + ) + class AsyncPreviewResource(AsyncAPIResource): @cached_property @@ -155,6 +205,55 @@ async def create( cast_to=cast(Type[PreviewCreateResponse], ResultWrapper[PreviewCreateResponse]), ) + async def get( + self, + investigate_id: str, + *, + 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, + ) -> PreviewGetResponse: + """ + Returns a preview of the message body as a base64 encoded PNG image for + non-benign messages. + + Args: + account_id: Identifier. + + investigate_id: Unique identifier for a message retrieved from investigation + + 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 investigate_id: + raise ValueError(f"Expected a non-empty value for `investigate_id` but received {investigate_id!r}") + return await self._get( + path_template( + "/accounts/{account_id}/email-security/investigate/{investigate_id}/preview", + account_id=account_id, + investigate_id=investigate_id, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[PreviewGetResponse]._unwrapper, + ), + cast_to=cast(Type[PreviewGetResponse], ResultWrapper[PreviewGetResponse]), + ) + class PreviewResourceWithRawResponse: def __init__(self, preview: PreviewResource) -> None: @@ -163,6 +262,9 @@ def __init__(self, preview: PreviewResource) -> None: self.create = to_raw_response_wrapper( preview.create, ) + self.get = to_raw_response_wrapper( + preview.get, + ) class AsyncPreviewResourceWithRawResponse: @@ -172,6 +274,9 @@ def __init__(self, preview: AsyncPreviewResource) -> None: self.create = async_to_raw_response_wrapper( preview.create, ) + self.get = async_to_raw_response_wrapper( + preview.get, + ) class PreviewResourceWithStreamingResponse: @@ -181,6 +286,9 @@ def __init__(self, preview: PreviewResource) -> None: self.create = to_streamed_response_wrapper( preview.create, ) + self.get = to_streamed_response_wrapper( + preview.get, + ) class AsyncPreviewResourceWithStreamingResponse: @@ -190,3 +298,6 @@ def __init__(self, preview: AsyncPreviewResource) -> None: self.create = async_to_streamed_response_wrapper( preview.create, ) + self.get = async_to_streamed_response_wrapper( + preview.get, + ) diff --git a/src/cloudflare/resources/email_security/investigate/raw.py b/src/cloudflare/resources/email_security/investigate/raw.py new file mode 100644 index 00000000000..9a3c682452c --- /dev/null +++ b/src/cloudflare/resources/email_security/investigate/raw.py @@ -0,0 +1,197 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Type, cast + +import httpx + +from ...._types import Body, Query, Headers, NotGiven, not_given +from ...._utils import path_template +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.email_security.investigate.raw_get_response import RawGetResponse + +__all__ = ["RawResource", "AsyncRawResource"] + + +class RawResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> RawResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 RawResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> RawResourceWithStreamingResponse: + """ + 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 RawResourceWithStreamingResponse(self) + + def get( + self, + investigate_id: str, + *, + 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, + ) -> RawGetResponse: + """ + Returns the raw eml of any non-benign message. + + Args: + account_id: Identifier. + + investigate_id: Unique identifier for a message retrieved from investigation + + 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 investigate_id: + raise ValueError(f"Expected a non-empty value for `investigate_id` but received {investigate_id!r}") + return self._get( + path_template( + "/accounts/{account_id}/email-security/investigate/{investigate_id}/raw", + account_id=account_id, + investigate_id=investigate_id, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[RawGetResponse]._unwrapper, + ), + cast_to=cast(Type[RawGetResponse], ResultWrapper[RawGetResponse]), + ) + + +class AsyncRawResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncRawResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 AsyncRawResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncRawResourceWithStreamingResponse: + """ + 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 AsyncRawResourceWithStreamingResponse(self) + + async def get( + self, + investigate_id: str, + *, + 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, + ) -> RawGetResponse: + """ + Returns the raw eml of any non-benign message. + + Args: + account_id: Identifier. + + investigate_id: Unique identifier for a message retrieved from investigation + + 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 investigate_id: + raise ValueError(f"Expected a non-empty value for `investigate_id` but received {investigate_id!r}") + return await self._get( + path_template( + "/accounts/{account_id}/email-security/investigate/{investigate_id}/raw", + account_id=account_id, + investigate_id=investigate_id, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[RawGetResponse]._unwrapper, + ), + cast_to=cast(Type[RawGetResponse], ResultWrapper[RawGetResponse]), + ) + + +class RawResourceWithRawResponse: + def __init__(self, raw: RawResource) -> None: + self._raw = raw + + self.get = to_raw_response_wrapper( + raw.get, + ) + + +class AsyncRawResourceWithRawResponse: + def __init__(self, raw: AsyncRawResource) -> None: + self._raw = raw + + self.get = async_to_raw_response_wrapper( + raw.get, + ) + + +class RawResourceWithStreamingResponse: + def __init__(self, raw: RawResource) -> None: + self._raw = raw + + self.get = to_streamed_response_wrapper( + raw.get, + ) + + +class AsyncRawResourceWithStreamingResponse: + def __init__(self, raw: AsyncRawResource) -> None: + self._raw = raw + + self.get = async_to_streamed_response_wrapper( + raw.get, + ) diff --git a/src/cloudflare/resources/email_security/investigate/reclassify.py b/src/cloudflare/resources/email_security/investigate/reclassify.py new file mode 100644 index 00000000000..80a1b87eebb --- /dev/null +++ b/src/cloudflare/resources/email_security/investigate/reclassify.py @@ -0,0 +1,230 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Type, cast +from typing_extensions import Literal + +import httpx + +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ...._utils import path_template, 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 ...._base_client import make_request_options +from ....types.email_security.investigate import reclassify_create_params + +__all__ = ["ReclassifyResource", "AsyncReclassifyResource"] + + +class ReclassifyResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ReclassifyResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 ReclassifyResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ReclassifyResourceWithStreamingResponse: + """ + 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 ReclassifyResourceWithStreamingResponse(self) + + def create( + self, + investigate_id: str, + *, + account_id: str, + expected_disposition: Literal["NONE", "BULK", "MALICIOUS", "SPAM", "SPOOF", "SUSPICIOUS"], + eml_content: str | Omit = omit, + escalated_submission_id: str | Omit = omit, + # 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, + ) -> object: + """Submits a request to reclassify an email's disposition. + + Use for reporting false + positives or false negatives. Optionally provide the raw EML content for + reanalysis. The reclassification is processed asynchronously. + + Args: + account_id: Identifier. + + investigate_id: Unique identifier for a message retrieved from investigation + + eml_content: Base64 encoded content of the EML file. + + 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 investigate_id: + raise ValueError(f"Expected a non-empty value for `investigate_id` but received {investigate_id!r}") + return self._post( + path_template( + "/accounts/{account_id}/email-security/investigate/{investigate_id}/reclassify", + account_id=account_id, + investigate_id=investigate_id, + ), + body=maybe_transform( + { + "expected_disposition": expected_disposition, + "eml_content": eml_content, + "escalated_submission_id": escalated_submission_id, + }, + reclassify_create_params.ReclassifyCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[object]._unwrapper, + ), + cast_to=cast(Type[object], ResultWrapper[object]), + ) + + +class AsyncReclassifyResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncReclassifyResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 AsyncReclassifyResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncReclassifyResourceWithStreamingResponse: + """ + 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 AsyncReclassifyResourceWithStreamingResponse(self) + + async def create( + self, + investigate_id: str, + *, + account_id: str, + expected_disposition: Literal["NONE", "BULK", "MALICIOUS", "SPAM", "SPOOF", "SUSPICIOUS"], + eml_content: str | Omit = omit, + escalated_submission_id: str | Omit = omit, + # 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, + ) -> object: + """Submits a request to reclassify an email's disposition. + + Use for reporting false + positives or false negatives. Optionally provide the raw EML content for + reanalysis. The reclassification is processed asynchronously. + + Args: + account_id: Identifier. + + investigate_id: Unique identifier for a message retrieved from investigation + + eml_content: Base64 encoded content of the EML file. + + 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 investigate_id: + raise ValueError(f"Expected a non-empty value for `investigate_id` but received {investigate_id!r}") + return await self._post( + path_template( + "/accounts/{account_id}/email-security/investigate/{investigate_id}/reclassify", + account_id=account_id, + investigate_id=investigate_id, + ), + body=await async_maybe_transform( + { + "expected_disposition": expected_disposition, + "eml_content": eml_content, + "escalated_submission_id": escalated_submission_id, + }, + reclassify_create_params.ReclassifyCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[object]._unwrapper, + ), + cast_to=cast(Type[object], ResultWrapper[object]), + ) + + +class ReclassifyResourceWithRawResponse: + def __init__(self, reclassify: ReclassifyResource) -> None: + self._reclassify = reclassify + + self.create = to_raw_response_wrapper( + reclassify.create, + ) + + +class AsyncReclassifyResourceWithRawResponse: + def __init__(self, reclassify: AsyncReclassifyResource) -> None: + self._reclassify = reclassify + + self.create = async_to_raw_response_wrapper( + reclassify.create, + ) + + +class ReclassifyResourceWithStreamingResponse: + def __init__(self, reclassify: ReclassifyResource) -> None: + self._reclassify = reclassify + + self.create = to_streamed_response_wrapper( + reclassify.create, + ) + + +class AsyncReclassifyResourceWithStreamingResponse: + def __init__(self, reclassify: AsyncReclassifyResource) -> None: + self._reclassify = reclassify + + self.create = async_to_streamed_response_wrapper( + reclassify.create, + ) diff --git a/src/cloudflare/resources/email_security/investigate/trace.py b/src/cloudflare/resources/email_security/investigate/trace.py new file mode 100644 index 00000000000..daf3560d6d1 --- /dev/null +++ b/src/cloudflare/resources/email_security/investigate/trace.py @@ -0,0 +1,203 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Type, cast + +import httpx + +from ...._types import Body, Query, Headers, NotGiven, not_given +from ...._utils import path_template +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.email_security.investigate.trace_get_response import TraceGetResponse + +__all__ = ["TraceResource", "AsyncTraceResource"] + + +class TraceResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> TraceResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 TraceResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> TraceResourceWithStreamingResponse: + """ + 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 TraceResourceWithStreamingResponse(self) + + def get( + self, + investigate_id: str, + *, + 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, + ) -> TraceGetResponse: + """Retrieves delivery and processing trace information for an email message. + + Shows + the delivery path, retraction history, and move operations performed on the + message. Useful for debugging delivery issues. + + Args: + account_id: Identifier. + + investigate_id: Unique identifier for a message retrieved from investigation + + 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 investigate_id: + raise ValueError(f"Expected a non-empty value for `investigate_id` but received {investigate_id!r}") + return self._get( + path_template( + "/accounts/{account_id}/email-security/investigate/{investigate_id}/trace", + account_id=account_id, + investigate_id=investigate_id, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[TraceGetResponse]._unwrapper, + ), + cast_to=cast(Type[TraceGetResponse], ResultWrapper[TraceGetResponse]), + ) + + +class AsyncTraceResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncTraceResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 AsyncTraceResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncTraceResourceWithStreamingResponse: + """ + 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 AsyncTraceResourceWithStreamingResponse(self) + + async def get( + self, + investigate_id: str, + *, + 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, + ) -> TraceGetResponse: + """Retrieves delivery and processing trace information for an email message. + + Shows + the delivery path, retraction history, and move operations performed on the + message. Useful for debugging delivery issues. + + Args: + account_id: Identifier. + + investigate_id: Unique identifier for a message retrieved from investigation + + 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 investigate_id: + raise ValueError(f"Expected a non-empty value for `investigate_id` but received {investigate_id!r}") + return await self._get( + path_template( + "/accounts/{account_id}/email-security/investigate/{investigate_id}/trace", + account_id=account_id, + investigate_id=investigate_id, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[TraceGetResponse]._unwrapper, + ), + cast_to=cast(Type[TraceGetResponse], ResultWrapper[TraceGetResponse]), + ) + + +class TraceResourceWithRawResponse: + def __init__(self, trace: TraceResource) -> None: + self._trace = trace + + self.get = to_raw_response_wrapper( + trace.get, + ) + + +class AsyncTraceResourceWithRawResponse: + def __init__(self, trace: AsyncTraceResource) -> None: + self._trace = trace + + self.get = async_to_raw_response_wrapper( + trace.get, + ) + + +class TraceResourceWithStreamingResponse: + def __init__(self, trace: TraceResource) -> None: + self._trace = trace + + self.get = to_streamed_response_wrapper( + trace.get, + ) + + +class AsyncTraceResourceWithStreamingResponse: + def __init__(self, trace: AsyncTraceResource) -> None: + self._trace = trace + + self.get = async_to_streamed_response_wrapper( + trace.get, + ) diff --git a/src/cloudflare/resources/email_security/settings/impersonation_registry.py b/src/cloudflare/resources/email_security/settings/impersonation_registry.py index 76b24c7d633..15d0da3afa2 100644 --- a/src/cloudflare/resources/email_security/settings/impersonation_registry.py +++ b/src/cloudflare/resources/email_security/settings/impersonation_registry.py @@ -20,9 +20,16 @@ from ...._wrappers import ResultWrapper from ....pagination import SyncV4PagePaginationArray, AsyncV4PagePaginationArray from ...._base_client import AsyncPaginator, make_request_options -from ....types.email_security.settings import impersonation_registry_list_params, impersonation_registry_create_params +from ....types.email_security.settings import ( + impersonation_registry_edit_params, + impersonation_registry_list_params, + impersonation_registry_create_params, +) +from ....types.email_security.settings.impersonation_registry_get_response import ImpersonationRegistryGetResponse +from ....types.email_security.settings.impersonation_registry_edit_response import ImpersonationRegistryEditResponse from ....types.email_security.settings.impersonation_registry_list_response import ImpersonationRegistryListResponse from ....types.email_security.settings.impersonation_registry_create_response import ImpersonationRegistryCreateResponse +from ....types.email_security.settings.impersonation_registry_delete_response import ImpersonationRegistryDeleteResponse __all__ = ["ImpersonationRegistryResource", "AsyncImpersonationRegistryResource"] @@ -186,6 +193,190 @@ def list( model=ImpersonationRegistryListResponse, ) + def delete( + self, + impersonation_registry_id: str, + *, + 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[ImpersonationRegistryDeleteResponse]: + """Removes an entry from the impersonation registry. + + After deletion, this identity + will no longer be protected from impersonation. + + Args: + account_id: Identifier. + + impersonation_registry_id: Impersonation registry entry identifier + + 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 impersonation_registry_id: + raise ValueError( + f"Expected a non-empty value for `impersonation_registry_id` but received {impersonation_registry_id!r}" + ) + return self._delete( + path_template( + "/accounts/{account_id}/email-security/settings/impersonation_registry/{impersonation_registry_id}", + account_id=account_id, + impersonation_registry_id=impersonation_registry_id, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[Optional[ImpersonationRegistryDeleteResponse]]._unwrapper, + ), + cast_to=cast( + Type[Optional[ImpersonationRegistryDeleteResponse]], ResultWrapper[ImpersonationRegistryDeleteResponse] + ), + ) + + def edit( + self, + impersonation_registry_id: str, + *, + account_id: str, + comments: Optional[str] | Omit = omit, + directory_id: Optional[int] | Omit = omit, + directory_node_id: Optional[int] | Omit = omit, + email: str | Omit = omit, + external_directory_node_id: Optional[str] | Omit = omit, + is_email_regex: bool | Omit = omit, + name: str | Omit = omit, + provenance: Literal["A1S_INTERNAL", "SNOOPY-CASB_OFFICE_365", "SNOOPY-OFFICE_365", "SNOOPY-GOOGLE_DIRECTORY"] + | Omit = omit, + # 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[ImpersonationRegistryEditResponse]: + """Updates an existing impersonation registry entry. + + Only provided fields will be + modified. Directory-synced entries can't be updated. + + Args: + account_id: Identifier. + + impersonation_registry_id: Impersonation registry entry identifier + + 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 impersonation_registry_id: + raise ValueError( + f"Expected a non-empty value for `impersonation_registry_id` but received {impersonation_registry_id!r}" + ) + return self._patch( + path_template( + "/accounts/{account_id}/email-security/settings/impersonation_registry/{impersonation_registry_id}", + account_id=account_id, + impersonation_registry_id=impersonation_registry_id, + ), + body=maybe_transform( + { + "comments": comments, + "directory_id": directory_id, + "directory_node_id": directory_node_id, + "email": email, + "external_directory_node_id": external_directory_node_id, + "is_email_regex": is_email_regex, + "name": name, + "provenance": provenance, + }, + impersonation_registry_edit_params.ImpersonationRegistryEditParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[Optional[ImpersonationRegistryEditResponse]]._unwrapper, + ), + cast_to=cast( + Type[Optional[ImpersonationRegistryEditResponse]], ResultWrapper[ImpersonationRegistryEditResponse] + ), + ) + + def get( + self, + impersonation_registry_id: str, + *, + 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[ImpersonationRegistryGetResponse]: + """ + Retrieves details for a specific impersonation registry entry including the + protected identity, email pattern, and synchronization source if + directory-synced. + + Args: + account_id: Identifier. + + impersonation_registry_id: Impersonation registry entry identifier + + 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 impersonation_registry_id: + raise ValueError( + f"Expected a non-empty value for `impersonation_registry_id` but received {impersonation_registry_id!r}" + ) + return self._get( + path_template( + "/accounts/{account_id}/email-security/settings/impersonation_registry/{impersonation_registry_id}", + account_id=account_id, + impersonation_registry_id=impersonation_registry_id, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[Optional[ImpersonationRegistryGetResponse]]._unwrapper, + ), + cast_to=cast( + Type[Optional[ImpersonationRegistryGetResponse]], ResultWrapper[ImpersonationRegistryGetResponse] + ), + ) + class AsyncImpersonationRegistryResource(AsyncAPIResource): @cached_property @@ -348,6 +539,190 @@ def list( model=ImpersonationRegistryListResponse, ) + async def delete( + self, + impersonation_registry_id: str, + *, + 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[ImpersonationRegistryDeleteResponse]: + """Removes an entry from the impersonation registry. + + After deletion, this identity + will no longer be protected from impersonation. + + Args: + account_id: Identifier. + + impersonation_registry_id: Impersonation registry entry identifier + + 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 impersonation_registry_id: + raise ValueError( + f"Expected a non-empty value for `impersonation_registry_id` but received {impersonation_registry_id!r}" + ) + return await self._delete( + path_template( + "/accounts/{account_id}/email-security/settings/impersonation_registry/{impersonation_registry_id}", + account_id=account_id, + impersonation_registry_id=impersonation_registry_id, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[Optional[ImpersonationRegistryDeleteResponse]]._unwrapper, + ), + cast_to=cast( + Type[Optional[ImpersonationRegistryDeleteResponse]], ResultWrapper[ImpersonationRegistryDeleteResponse] + ), + ) + + async def edit( + self, + impersonation_registry_id: str, + *, + account_id: str, + comments: Optional[str] | Omit = omit, + directory_id: Optional[int] | Omit = omit, + directory_node_id: Optional[int] | Omit = omit, + email: str | Omit = omit, + external_directory_node_id: Optional[str] | Omit = omit, + is_email_regex: bool | Omit = omit, + name: str | Omit = omit, + provenance: Literal["A1S_INTERNAL", "SNOOPY-CASB_OFFICE_365", "SNOOPY-OFFICE_365", "SNOOPY-GOOGLE_DIRECTORY"] + | Omit = omit, + # 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[ImpersonationRegistryEditResponse]: + """Updates an existing impersonation registry entry. + + Only provided fields will be + modified. Directory-synced entries can't be updated. + + Args: + account_id: Identifier. + + impersonation_registry_id: Impersonation registry entry identifier + + 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 impersonation_registry_id: + raise ValueError( + f"Expected a non-empty value for `impersonation_registry_id` but received {impersonation_registry_id!r}" + ) + return await self._patch( + path_template( + "/accounts/{account_id}/email-security/settings/impersonation_registry/{impersonation_registry_id}", + account_id=account_id, + impersonation_registry_id=impersonation_registry_id, + ), + body=await async_maybe_transform( + { + "comments": comments, + "directory_id": directory_id, + "directory_node_id": directory_node_id, + "email": email, + "external_directory_node_id": external_directory_node_id, + "is_email_regex": is_email_regex, + "name": name, + "provenance": provenance, + }, + impersonation_registry_edit_params.ImpersonationRegistryEditParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[Optional[ImpersonationRegistryEditResponse]]._unwrapper, + ), + cast_to=cast( + Type[Optional[ImpersonationRegistryEditResponse]], ResultWrapper[ImpersonationRegistryEditResponse] + ), + ) + + async def get( + self, + impersonation_registry_id: str, + *, + 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[ImpersonationRegistryGetResponse]: + """ + Retrieves details for a specific impersonation registry entry including the + protected identity, email pattern, and synchronization source if + directory-synced. + + Args: + account_id: Identifier. + + impersonation_registry_id: Impersonation registry entry identifier + + 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 impersonation_registry_id: + raise ValueError( + f"Expected a non-empty value for `impersonation_registry_id` but received {impersonation_registry_id!r}" + ) + return await self._get( + path_template( + "/accounts/{account_id}/email-security/settings/impersonation_registry/{impersonation_registry_id}", + account_id=account_id, + impersonation_registry_id=impersonation_registry_id, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[Optional[ImpersonationRegistryGetResponse]]._unwrapper, + ), + cast_to=cast( + Type[Optional[ImpersonationRegistryGetResponse]], ResultWrapper[ImpersonationRegistryGetResponse] + ), + ) + class ImpersonationRegistryResourceWithRawResponse: def __init__(self, impersonation_registry: ImpersonationRegistryResource) -> None: @@ -359,6 +734,15 @@ def __init__(self, impersonation_registry: ImpersonationRegistryResource) -> Non self.list = to_raw_response_wrapper( impersonation_registry.list, ) + self.delete = to_raw_response_wrapper( + impersonation_registry.delete, + ) + self.edit = to_raw_response_wrapper( + impersonation_registry.edit, + ) + self.get = to_raw_response_wrapper( + impersonation_registry.get, + ) class AsyncImpersonationRegistryResourceWithRawResponse: @@ -371,6 +755,15 @@ def __init__(self, impersonation_registry: AsyncImpersonationRegistryResource) - self.list = async_to_raw_response_wrapper( impersonation_registry.list, ) + self.delete = async_to_raw_response_wrapper( + impersonation_registry.delete, + ) + self.edit = async_to_raw_response_wrapper( + impersonation_registry.edit, + ) + self.get = async_to_raw_response_wrapper( + impersonation_registry.get, + ) class ImpersonationRegistryResourceWithStreamingResponse: @@ -383,6 +776,15 @@ def __init__(self, impersonation_registry: ImpersonationRegistryResource) -> Non self.list = to_streamed_response_wrapper( impersonation_registry.list, ) + self.delete = to_streamed_response_wrapper( + impersonation_registry.delete, + ) + self.edit = to_streamed_response_wrapper( + impersonation_registry.edit, + ) + self.get = to_streamed_response_wrapper( + impersonation_registry.get, + ) class AsyncImpersonationRegistryResourceWithStreamingResponse: @@ -395,3 +797,12 @@ def __init__(self, impersonation_registry: AsyncImpersonationRegistryResource) - self.list = async_to_streamed_response_wrapper( impersonation_registry.list, ) + self.delete = async_to_streamed_response_wrapper( + impersonation_registry.delete, + ) + self.edit = async_to_streamed_response_wrapper( + impersonation_registry.edit, + ) + self.get = async_to_streamed_response_wrapper( + impersonation_registry.get, + ) diff --git a/src/cloudflare/resources/magic_transit/api.md b/src/cloudflare/resources/magic_transit/api.md index a7477a25fa8..2d200bccc35 100644 --- a/src/cloudflare/resources/magic_transit/api.md +++ b/src/cloudflare/resources/magic_transit/api.md @@ -220,7 +220,7 @@ Methods: - client.magic_transit.connectors.create(\*, account_id, \*\*params) -> ConnectorCreateResponse - client.magic_transit.connectors.update(connector_id, \*, account_id, \*\*params) -> ConnectorUpdateResponse -- client.magic_transit.connectors.list(\*, account_id) -> SyncSinglePage[ConnectorListResponse] +- client.magic_transit.connectors.list(\*, account_id, \*\*params) -> SyncSinglePage[ConnectorListResponse] - client.magic_transit.connectors.delete(connector_id, \*, account_id) -> ConnectorDeleteResponse - client.magic_transit.connectors.edit(connector_id, \*, account_id, \*\*params) -> ConnectorEditResponse - client.magic_transit.connectors.get(connector_id, \*, account_id) -> ConnectorGetResponse diff --git a/src/cloudflare/resources/magic_transit/connectors/connectors.py b/src/cloudflare/resources/magic_transit/connectors/connectors.py index d842d3ecd80..bf11a0bced6 100644 --- a/src/cloudflare/resources/magic_transit/connectors/connectors.py +++ b/src/cloudflare/resources/magic_transit/connectors/connectors.py @@ -36,7 +36,12 @@ SnapshotsResourceWithStreamingResponse, AsyncSnapshotsResourceWithStreamingResponse, ) -from ....types.magic_transit import connector_edit_params, connector_create_params, connector_update_params +from ....types.magic_transit import ( + connector_edit_params, + connector_list_params, + connector_create_params, + connector_update_params, +) from ....types.magic_transit.connector_get_response import ConnectorGetResponse from ....types.magic_transit.connector_edit_response import ConnectorEditResponse from ....types.magic_transit.connector_list_response import ConnectorListResponse @@ -224,6 +229,7 @@ def list( self, *, account_id: str, + device_type: Literal["MANAGED", "LICENSED"] | Omit = omit, # 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, @@ -237,6 +243,8 @@ def list( Args: account_id: Account identifier + device_type: Filter connectors by device type. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -251,7 +259,11 @@ def list( path_template("/accounts/{account_id}/magic/connectors", account_id=account_id), page=SyncSinglePage[ConnectorListResponse], options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"device_type": device_type}, connector_list_params.ConnectorListParams), ), model=ConnectorListResponse, ) @@ -602,6 +614,7 @@ def list( self, *, account_id: str, + device_type: Literal["MANAGED", "LICENSED"] | Omit = omit, # 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, @@ -615,6 +628,8 @@ def list( Args: account_id: Account identifier + device_type: Filter connectors by device type. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -629,7 +644,11 @@ def list( path_template("/accounts/{account_id}/magic/connectors", account_id=account_id), page=AsyncSinglePage[ConnectorListResponse], options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"device_type": device_type}, connector_list_params.ConnectorListParams), ), model=ConnectorListResponse, ) diff --git a/src/cloudflare/resources/zero_trust/access/applications/policy_tests/__init__.py b/src/cloudflare/resources/zero_trust/access/applications/policy_tests/__init__.py old mode 100755 new mode 100644 diff --git a/src/cloudflare/resources/zero_trust/access/applications/policy_tests/policy_tests.py b/src/cloudflare/resources/zero_trust/access/applications/policy_tests/policy_tests.py old mode 100755 new mode 100644 diff --git a/src/cloudflare/resources/zero_trust/access/applications/policy_tests/users.py b/src/cloudflare/resources/zero_trust/access/applications/policy_tests/users.py old mode 100755 new mode 100644 diff --git a/src/cloudflare/resources/zero_trust/dlp/datasets/versions/__init__.py b/src/cloudflare/resources/zero_trust/dlp/datasets/versions/__init__.py old mode 100755 new mode 100644 diff --git a/src/cloudflare/resources/zero_trust/dlp/datasets/versions/entries.py b/src/cloudflare/resources/zero_trust/dlp/datasets/versions/entries.py old mode 100755 new mode 100644 diff --git a/src/cloudflare/resources/zero_trust/dlp/datasets/versions/versions.py b/src/cloudflare/resources/zero_trust/dlp/datasets/versions/versions.py old mode 100755 new mode 100644 diff --git a/src/cloudflare/resources/zero_trust/dlp/limits.py b/src/cloudflare/resources/zero_trust/dlp/limits.py old mode 100755 new mode 100644 diff --git a/src/cloudflare/resources/zero_trust/gateway/configurations/__init__.py b/src/cloudflare/resources/zero_trust/gateway/configurations/__init__.py old mode 100755 new mode 100644 diff --git a/src/cloudflare/resources/zero_trust/gateway/configurations/configurations.py b/src/cloudflare/resources/zero_trust/gateway/configurations/configurations.py old mode 100755 new mode 100644 diff --git a/src/cloudflare/types/accounts/account_create_params.py b/src/cloudflare/types/accounts/account_create_params.py old mode 100755 new mode 100644 diff --git a/src/cloudflare/types/accounts/account_delete_response.py b/src/cloudflare/types/accounts/account_delete_response.py old mode 100755 new mode 100644 diff --git a/src/cloudflare/types/botnet_feed/asn_day_report_params.py b/src/cloudflare/types/botnet_feed/asn_day_report_params.py old mode 100755 new mode 100644 diff --git a/src/cloudflare/types/botnet_feed/asn_day_report_response.py b/src/cloudflare/types/botnet_feed/asn_day_report_response.py old mode 100755 new mode 100644 diff --git a/src/cloudflare/types/botnet_feed/asn_full_report_response.py b/src/cloudflare/types/botnet_feed/asn_full_report_response.py old mode 100755 new mode 100644 diff --git a/src/cloudflare/types/botnet_feed/configs/asn_delete_response.py b/src/cloudflare/types/botnet_feed/configs/asn_delete_response.py old mode 100755 new mode 100644 diff --git a/src/cloudflare/types/botnet_feed/configs/asn_get_response.py b/src/cloudflare/types/botnet_feed/configs/asn_get_response.py old mode 100755 new mode 100644 diff --git a/src/cloudflare/types/email_security/__init__.py b/src/cloudflare/types/email_security/__init__.py index 55fad65cd27..7d6d4897e12 100644 --- a/src/cloudflare/types/email_security/__init__.py +++ b/src/cloudflare/types/email_security/__init__.py @@ -2,7 +2,9 @@ from __future__ import annotations +from .investigate_get_params import InvestigateGetParams as InvestigateGetParams from .submission_list_params import SubmissionListParams as SubmissionListParams from .investigate_list_params import InvestigateListParams as InvestigateListParams +from .investigate_get_response import InvestigateGetResponse as InvestigateGetResponse from .submission_list_response import SubmissionListResponse as SubmissionListResponse from .investigate_list_response import InvestigateListResponse as InvestigateListResponse diff --git a/src/cloudflare/types/email_security/investigate/__init__.py b/src/cloudflare/types/email_security/investigate/__init__.py index 2657a470e2c..e694dd47b9b 100644 --- a/src/cloudflare/types/email_security/investigate/__init__.py +++ b/src/cloudflare/types/email_security/investigate/__init__.py @@ -3,8 +3,15 @@ from __future__ import annotations from .move_bulk_params import MoveBulkParams as MoveBulkParams +from .raw_get_response import RawGetResponse as RawGetResponse from .move_bulk_response import MoveBulkResponse as MoveBulkResponse +from .move_create_params import MoveCreateParams as MoveCreateParams +from .trace_get_response import TraceGetResponse as TraceGetResponse from .release_bulk_params import ReleaseBulkParams as ReleaseBulkParams +from .move_create_response import MoveCreateResponse as MoveCreateResponse +from .preview_get_response import PreviewGetResponse as PreviewGetResponse from .preview_create_params import PreviewCreateParams as PreviewCreateParams from .release_bulk_response import ReleaseBulkResponse as ReleaseBulkResponse +from .detection_get_response import DetectionGetResponse as DetectionGetResponse from .preview_create_response import PreviewCreateResponse as PreviewCreateResponse +from .reclassify_create_params import ReclassifyCreateParams as ReclassifyCreateParams diff --git a/src/cloudflare/types/email_security/investigate/detection_get_response.py b/src/cloudflare/types/email_security/investigate/detection_get_response.py new file mode 100644 index 00000000000..9d292df5162 --- /dev/null +++ b/src/cloudflare/types/email_security/investigate/detection_get_response.py @@ -0,0 +1,169 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = [ + "DetectionGetResponse", + "Attachment", + "Finding", + "Header", + "Link", + "SenderInfo", + "ThreatCategory", + "Validation", +] + + +class Attachment(BaseModel): + size: int + """Size of the attachment in bytes""" + + content_type: Optional[str] = None + """MIME type of the attachment""" + + detection: Optional[ + Literal[ + "MALICIOUS", + "MALICIOUS-BEC", + "SUSPICIOUS", + "SPOOF", + "SPAM", + "BULK", + "ENCRYPTED", + "EXTERNAL", + "UNKNOWN", + "NONE", + ] + ] = None + """Detection result for this attachment""" + + encrypted: Optional[bool] = None + """Whether the attachment is encrypted""" + + filename: Optional[str] = None + """Name of the attached file""" + + md5: Optional[str] = None + """MD5 hash of the attachment""" + + name: Optional[str] = None + """Attachment name (alternative to filename)""" + + sha1: Optional[str] = None + """SHA1 hash of the attachment""" + + sha256: Optional[str] = None + """SHA256 hash of the attachment""" + + +class Finding(BaseModel): + attachment: Optional[str] = None + + detail: Optional[str] = None + + detection: Optional[ + Literal[ + "MALICIOUS", + "MALICIOUS-BEC", + "SUSPICIOUS", + "SPOOF", + "SPAM", + "BULK", + "ENCRYPTED", + "EXTERNAL", + "UNKNOWN", + "NONE", + ] + ] = None + + field: Optional[str] = None + + name: Optional[str] = None + + portion: Optional[str] = None + + reason: Optional[str] = None + + score: Optional[float] = None + + value: Optional[str] = None + + +class Header(BaseModel): + name: str + + value: str + + +class Link(BaseModel): + href: str + + text: Optional[str] = None + + +class SenderInfo(BaseModel): + as_name: Optional[str] = None + """The name of the autonomous system.""" + + as_number: Optional[int] = None + """The number of the autonomous system.""" + + geo: Optional[str] = None + + ip: Optional[str] = None + + pld: Optional[str] = None + + +class ThreatCategory(BaseModel): + id: Optional[int] = None + + description: Optional[str] = None + + name: Optional[str] = None + + +class Validation(BaseModel): + comment: Optional[str] = None + + dkim: Optional[Literal["pass", "neutral", "fail", "error", "none"]] = None + + dmarc: Optional[Literal["pass", "neutral", "fail", "error", "none"]] = None + + spf: Optional[Literal["pass", "neutral", "fail", "error", "none"]] = None + + +class DetectionGetResponse(BaseModel): + action: str + + attachments: List[Attachment] + + findings: Optional[List[Finding]] = None + + headers: List[Header] + + links: List[Link] + + sender_info: SenderInfo + + threat_categories: List[ThreatCategory] + + validation: Validation + + final_disposition: Optional[ + Literal[ + "MALICIOUS", + "MALICIOUS-BEC", + "SUSPICIOUS", + "SPOOF", + "SPAM", + "BULK", + "ENCRYPTED", + "EXTERNAL", + "UNKNOWN", + "NONE", + ] + ] = None diff --git a/src/cloudflare/types/email_security/investigate/move_create_params.py b/src/cloudflare/types/email_security/investigate/move_create_params.py new file mode 100644 index 00000000000..0e389b2ae93 --- /dev/null +++ b/src/cloudflare/types/email_security/investigate/move_create_params.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["MoveCreateParams"] + + +class MoveCreateParams(TypedDict, total=False): + account_id: Required[str] + """Identifier.""" + + destination: Required[ + Literal["Inbox", "JunkEmail", "DeletedItems", "RecoverableItemsDeletions", "RecoverableItemsPurges"] + ] diff --git a/src/cloudflare/types/email_security/investigate/move_create_response.py b/src/cloudflare/types/email_security/investigate/move_create_response.py new file mode 100644 index 00000000000..2737ff7f476 --- /dev/null +++ b/src/cloudflare/types/email_security/investigate/move_create_response.py @@ -0,0 +1,37 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime + +from ...._models import BaseModel + +__all__ = ["MoveCreateResponse"] + + +class MoveCreateResponse(BaseModel): + success: bool + """Whether the operation succeeded""" + + completed_at: Optional[datetime] = None + """When the move operation completed (UTC)""" + + completed_timestamp: Optional[datetime] = None + """Deprecated, use `completed_at` instead. End of life: November 1, 2026.""" + + destination: Optional[str] = None + """Destination folder for the message""" + + item_count: Optional[int] = None + """Number of items moved. End of life: November 1, 2026.""" + + message_id: Optional[str] = None + """Message identifier""" + + operation: Optional[str] = None + """Type of operation performed""" + + recipient: Optional[str] = None + """Recipient email address""" + + status: Optional[str] = None + """Operation status""" diff --git a/src/cloudflare/types/email_security/investigate/preview_get_response.py b/src/cloudflare/types/email_security/investigate/preview_get_response.py new file mode 100644 index 00000000000..a34a109ac48 --- /dev/null +++ b/src/cloudflare/types/email_security/investigate/preview_get_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ...._models import BaseModel + +__all__ = ["PreviewGetResponse"] + + +class PreviewGetResponse(BaseModel): + screenshot: str + """A base64 encoded PNG image of the email.""" diff --git a/src/cloudflare/types/email_security/investigate/raw_get_response.py b/src/cloudflare/types/email_security/investigate/raw_get_response.py new file mode 100644 index 00000000000..06544943fca --- /dev/null +++ b/src/cloudflare/types/email_security/investigate/raw_get_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ...._models import BaseModel + +__all__ = ["RawGetResponse"] + + +class RawGetResponse(BaseModel): + raw: str + """A UTF-8 encoded eml file of the email.""" diff --git a/src/cloudflare/types/email_security/investigate/reclassify_create_params.py b/src/cloudflare/types/email_security/investigate/reclassify_create_params.py new file mode 100644 index 00000000000..a35779781ec --- /dev/null +++ b/src/cloudflare/types/email_security/investigate/reclassify_create_params.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ReclassifyCreateParams"] + + +class ReclassifyCreateParams(TypedDict, total=False): + account_id: Required[str] + """Identifier.""" + + expected_disposition: Required[Literal["NONE", "BULK", "MALICIOUS", "SPAM", "SPOOF", "SUSPICIOUS"]] + + eml_content: str + """Base64 encoded content of the EML file.""" + + escalated_submission_id: str diff --git a/src/cloudflare/types/email_security/investigate/trace_get_response.py b/src/cloudflare/types/email_security/investigate/trace_get_response.py new file mode 100644 index 00000000000..c62405ddd96 --- /dev/null +++ b/src/cloudflare/types/email_security/investigate/trace_get_response.py @@ -0,0 +1,50 @@ +# 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__ = ["TraceGetResponse", "Inbound", "InboundLine", "Outbound", "OutboundLine"] + + +class InboundLine(BaseModel): + lineno: Optional[int] = None + """Line number in the trace log""" + + logged_at: Optional[datetime] = None + + message: Optional[str] = None + + ts: Optional[str] = None + """Deprecated, use `logged_at` instead. End of life: November 1, 2026.""" + + +class Inbound(BaseModel): + lines: Optional[List[InboundLine]] = None + + pending: Optional[bool] = None + + +class OutboundLine(BaseModel): + lineno: Optional[int] = None + """Line number in the trace log""" + + logged_at: Optional[datetime] = None + + message: Optional[str] = None + + ts: Optional[str] = None + """Deprecated, use `logged_at` instead. End of life: November 1, 2026.""" + + +class Outbound(BaseModel): + lines: Optional[List[OutboundLine]] = None + + pending: Optional[bool] = None + + +class TraceGetResponse(BaseModel): + inbound: Inbound + + outbound: Outbound diff --git a/src/cloudflare/types/email_security/investigate_get_params.py b/src/cloudflare/types/email_security/investigate_get_params.py new file mode 100644 index 00000000000..bf009131acd --- /dev/null +++ b/src/cloudflare/types/email_security/investigate_get_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["InvestigateGetParams"] + + +class InvestigateGetParams(TypedDict, total=False): + account_id: Required[str] + """Identifier.""" + + submission: bool + """When true, search the submissions datastore only. + + When false or omitted, search the regular datastore only. + """ diff --git a/src/cloudflare/types/email_security/investigate_get_response.py b/src/cloudflare/types/email_security/investigate_get_response.py new file mode 100644 index 00000000000..778fe7f2540 --- /dev/null +++ b/src/cloudflare/types/email_security/investigate_get_response.py @@ -0,0 +1,233 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = ["InvestigateGetResponse", "ActionLog", "ActionLogProperties", "Properties", "Finding", "Validation"] + + +class ActionLogProperties(BaseModel): + """Additional properties for the action""" + + folder: Optional[str] = None + """Target folder for move operations""" + + requested_by: Optional[str] = None + """User who requested the action""" + + +class ActionLog(BaseModel): + completed_at: datetime + """Timestamp when action completed""" + + operation: Literal["MOVE", "RELEASE", "RECLASSIFY", "SUBMISSION", "QUARANTINE_RELEASE", "PREVIEW"] + """Type of action performed""" + + completed_timestamp: Optional[str] = None + """Deprecated, use `completed_at` instead. End of life: November 1, 2026.""" + + properties: Optional[ActionLogProperties] = None + """Additional properties for the action""" + + status: Optional[str] = None + """Status of the action""" + + +class Properties(BaseModel): + """Message processing properties""" + + allowlisted_pattern: Optional[str] = None + """Pattern that allowlisted this message""" + + allowlisted_pattern_type: Optional[ + Literal[ + "quarantine_release", + "acceptable_sender", + "allowed_sender", + "allowed_recipient", + "domain_similarity", + "domain_recency", + "managed_acceptable_sender", + "outbound_ndr", + ] + ] = None + """Type of allowlist pattern""" + + blocklisted_message: Optional[bool] = None + """Whether message was blocklisted""" + + blocklisted_pattern: Optional[str] = None + """Pattern that blocklisted this message""" + + whitelisted_pattern_type: Optional[ + Literal[ + "quarantine_release", + "acceptable_sender", + "allowed_sender", + "allowed_recipient", + "domain_similarity", + "domain_recency", + "managed_acceptable_sender", + "outbound_ndr", + ] + ] = None + """Legacy field for allowlist pattern type""" + + +class Finding(BaseModel): + attachment: Optional[str] = None + + detail: Optional[str] = None + + detection: Optional[ + Literal[ + "MALICIOUS", + "MALICIOUS-BEC", + "SUSPICIOUS", + "SPOOF", + "SPAM", + "BULK", + "ENCRYPTED", + "EXTERNAL", + "UNKNOWN", + "NONE", + ] + ] = None + + field: Optional[str] = None + + name: Optional[str] = None + + portion: Optional[str] = None + + reason: Optional[str] = None + + score: Optional[float] = None + + value: Optional[str] = None + + +class Validation(BaseModel): + comment: Optional[str] = None + + dkim: Optional[Literal["pass", "neutral", "fail", "error", "none"]] = None + + dmarc: Optional[Literal["pass", "neutral", "fail", "error", "none"]] = None + + spf: Optional[Literal["pass", "neutral", "fail", "error", "none"]] = None + + +class InvestigateGetResponse(BaseModel): + id: str + """Unique identifier for a message retrieved from investigation""" + + action_log: List[ActionLog] + """Deprecated, use `GET /investigate/{investigate_id}/action_log` instead. + + End of life: November 1, 2026. + """ + + client_recipients: List[str] + + detection_reasons: List[str] + + is_phish_submission: bool + + is_quarantined: bool + + postfix_id: str + """The identifier of the message""" + + properties: Properties + """Message processing properties""" + + ts: str + """Deprecated, use `scanned_at` instead. End of life: November 1, 2026.""" + + alert_id: Optional[str] = None + + delivery_mode: Optional[ + Literal[ + "DIRECT", + "BCC", + "JOURNAL", + "REVIEW_SUBMISSION", + "DMARC_UNVERIFIED", + "DMARC_FAILURE_REPORT", + "DMARC_AGGREGATE_REPORT", + "THREAT_INTEL_SUBMISSION", + "SIMULATION_SUBMISSION", + "API", + "RETRO_SCAN", + ] + ] = None + + delivery_status: Optional[ + List[Literal["delivered", "moved", "quarantined", "rejected", "deferred", "bounced", "queued"]] + ] = None + + edf_hash: Optional[str] = None + + envelope_from: Optional[str] = None + + envelope_to: Optional[List[str]] = None + + final_disposition: Optional[ + Literal[ + "MALICIOUS", + "MALICIOUS-BEC", + "SUSPICIOUS", + "SPOOF", + "SPAM", + "BULK", + "ENCRYPTED", + "EXTERNAL", + "UNKNOWN", + "NONE", + ] + ] = None + + findings: Optional[List[Finding]] = None + """ + Deprecated, use the `findings` field from + `GET /investigate/{investigate_id}/detections` instead. End of life: November + 1, 2026. Detection findings for this message. + """ + + from_: Optional[str] = FieldInfo(alias="from", default=None) + + from_name: Optional[str] = None + + htmltext_structure_hash: Optional[str] = None + + message_id: Optional[str] = None + + post_delivery_operations: Optional[List[Literal["PREVIEW", "QUARANTINE_RELEASE", "SUBMISSION", "MOVE"]]] = None + """Post-delivery operations performed on this message""" + + postfix_id_outbound: Optional[str] = None + + replyto: Optional[str] = None + + scanned_at: Optional[datetime] = None + """When the message was scanned (UTC)""" + + sent_at: Optional[datetime] = None + """When the message was sent (UTC)""" + + sent_date: Optional[str] = None + + subject: Optional[str] = None + + threat_categories: Optional[List[str]] = None + + to: Optional[List[str]] = None + + to_name: Optional[List[str]] = None + + validation: Optional[Validation] = None diff --git a/src/cloudflare/types/email_security/settings/__init__.py b/src/cloudflare/types/email_security/settings/__init__.py index 866ff04dbcc..3cdacd3f71b 100644 --- a/src/cloudflare/types/email_security/settings/__init__.py +++ b/src/cloudflare/types/email_security/settings/__init__.py @@ -32,9 +32,15 @@ from .trusted_domain_list_response import TrustedDomainListResponse as TrustedDomainListResponse from .trusted_domain_create_response import TrustedDomainCreateResponse as TrustedDomainCreateResponse from .trusted_domain_delete_response import TrustedDomainDeleteResponse as TrustedDomainDeleteResponse +from .impersonation_registry_edit_params import ImpersonationRegistryEditParams as ImpersonationRegistryEditParams from .impersonation_registry_list_params import ImpersonationRegistryListParams as ImpersonationRegistryListParams +from .impersonation_registry_get_response import ImpersonationRegistryGetResponse as ImpersonationRegistryGetResponse from .impersonation_registry_create_params import ImpersonationRegistryCreateParams as ImpersonationRegistryCreateParams +from .impersonation_registry_edit_response import ImpersonationRegistryEditResponse as ImpersonationRegistryEditResponse from .impersonation_registry_list_response import ImpersonationRegistryListResponse as ImpersonationRegistryListResponse from .impersonation_registry_create_response import ( ImpersonationRegistryCreateResponse as ImpersonationRegistryCreateResponse, ) +from .impersonation_registry_delete_response import ( + ImpersonationRegistryDeleteResponse as ImpersonationRegistryDeleteResponse, +) diff --git a/src/cloudflare/types/email_security/settings/impersonation_registry_delete_response.py b/src/cloudflare/types/email_security/settings/impersonation_registry_delete_response.py new file mode 100644 index 00000000000..9f53eea77c2 --- /dev/null +++ b/src/cloudflare/types/email_security/settings/impersonation_registry_delete_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ...._models import BaseModel + +__all__ = ["ImpersonationRegistryDeleteResponse"] + + +class ImpersonationRegistryDeleteResponse(BaseModel): + id: str + """Impersonation registry entry identifier""" diff --git a/src/cloudflare/types/email_security/settings/impersonation_registry_edit_params.py b/src/cloudflare/types/email_security/settings/impersonation_registry_edit_params.py new file mode 100644 index 00000000000..6da26a51e67 --- /dev/null +++ b/src/cloudflare/types/email_security/settings/impersonation_registry_edit_params.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ImpersonationRegistryEditParams"] + + +class ImpersonationRegistryEditParams(TypedDict, total=False): + account_id: Required[str] + """Identifier.""" + + comments: Optional[str] + + directory_id: Optional[int] + + directory_node_id: Optional[int] + + email: str + + external_directory_node_id: Optional[str] + + is_email_regex: bool + + name: str + + provenance: Literal["A1S_INTERNAL", "SNOOPY-CASB_OFFICE_365", "SNOOPY-OFFICE_365", "SNOOPY-GOOGLE_DIRECTORY"] diff --git a/src/cloudflare/types/email_security/settings/impersonation_registry_edit_response.py b/src/cloudflare/types/email_security/settings/impersonation_registry_edit_response.py new file mode 100644 index 00000000000..f857877c46b --- /dev/null +++ b/src/cloudflare/types/email_security/settings/impersonation_registry_edit_response.py @@ -0,0 +1,41 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["ImpersonationRegistryEditResponse"] + + +class ImpersonationRegistryEditResponse(BaseModel): + """An impersonation registry entry""" + + id: Optional[str] = None + """Impersonation registry entry identifier""" + + comments: Optional[str] = None + + created_at: Optional[datetime] = None + + directory_id: Optional[int] = None + + directory_node_id: Optional[int] = None + + email: Optional[str] = None + + external_directory_node_id: Optional[str] = None + + is_email_regex: Optional[bool] = None + + last_modified: Optional[datetime] = None + """Deprecated, use `modified_at` instead. End of life: November 1, 2026.""" + + modified_at: Optional[datetime] = None + + name: Optional[str] = None + + provenance: Optional[ + Literal["A1S_INTERNAL", "SNOOPY-CASB_OFFICE_365", "SNOOPY-OFFICE_365", "SNOOPY-GOOGLE_DIRECTORY"] + ] = None diff --git a/src/cloudflare/types/email_security/settings/impersonation_registry_get_response.py b/src/cloudflare/types/email_security/settings/impersonation_registry_get_response.py new file mode 100644 index 00000000000..4a8d99ca5a3 --- /dev/null +++ b/src/cloudflare/types/email_security/settings/impersonation_registry_get_response.py @@ -0,0 +1,41 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["ImpersonationRegistryGetResponse"] + + +class ImpersonationRegistryGetResponse(BaseModel): + """An impersonation registry entry""" + + id: Optional[str] = None + """Impersonation registry entry identifier""" + + comments: Optional[str] = None + + created_at: Optional[datetime] = None + + directory_id: Optional[int] = None + + directory_node_id: Optional[int] = None + + email: Optional[str] = None + + external_directory_node_id: Optional[str] = None + + is_email_regex: Optional[bool] = None + + last_modified: Optional[datetime] = None + """Deprecated, use `modified_at` instead. End of life: November 1, 2026.""" + + modified_at: Optional[datetime] = None + + name: Optional[str] = None + + provenance: Optional[ + Literal["A1S_INTERNAL", "SNOOPY-CASB_OFFICE_365", "SNOOPY-OFFICE_365", "SNOOPY-GOOGLE_DIRECTORY"] + ] = None diff --git a/src/cloudflare/types/magic_transit/__init__.py b/src/cloudflare/types/magic_transit/__init__.py index 700b72f955b..bec3c88a56d 100644 --- a/src/cloudflare/types/magic_transit/__init__.py +++ b/src/cloudflare/types/magic_transit/__init__.py @@ -37,6 +37,7 @@ from .pcap_create_response import PCAPCreateResponse as PCAPCreateResponse from .route_empty_response import RouteEmptyResponse as RouteEmptyResponse from .connector_edit_params import ConnectorEditParams as ConnectorEditParams +from .connector_list_params import ConnectorListParams as ConnectorListParams from .route_create_response import RouteCreateResponse as RouteCreateResponse from .route_delete_response import RouteDeleteResponse as RouteDeleteResponse from .route_update_response import RouteUpdateResponse as RouteUpdateResponse diff --git a/src/cloudflare/types/magic_transit/connector_create_response.py b/src/cloudflare/types/magic_transit/connector_create_response.py index 74053c83628..57fabb8b537 100644 --- a/src/cloudflare/types/magic_transit/connector_create_response.py +++ b/src/cloudflare/types/magic_transit/connector_create_response.py @@ -13,6 +13,8 @@ class Device(BaseModel): serial_number: Optional[str] = None + type: Optional[Literal["MANAGED", "LICENSED"]] = None + class ConnectorCreateResponse(BaseModel): id: str diff --git a/src/cloudflare/types/magic_transit/connector_delete_response.py b/src/cloudflare/types/magic_transit/connector_delete_response.py index 7dc21b7c70c..e7e20709783 100644 --- a/src/cloudflare/types/magic_transit/connector_delete_response.py +++ b/src/cloudflare/types/magic_transit/connector_delete_response.py @@ -13,6 +13,8 @@ class Device(BaseModel): serial_number: Optional[str] = None + type: Optional[Literal["MANAGED", "LICENSED"]] = None + class ConnectorDeleteResponse(BaseModel): id: str diff --git a/src/cloudflare/types/magic_transit/connector_edit_response.py b/src/cloudflare/types/magic_transit/connector_edit_response.py index e65a54a4c14..25046e5f468 100644 --- a/src/cloudflare/types/magic_transit/connector_edit_response.py +++ b/src/cloudflare/types/magic_transit/connector_edit_response.py @@ -13,6 +13,8 @@ class Device(BaseModel): serial_number: Optional[str] = None + type: Optional[Literal["MANAGED", "LICENSED"]] = None + class ConnectorEditResponse(BaseModel): id: str diff --git a/src/cloudflare/types/magic_transit/connector_get_response.py b/src/cloudflare/types/magic_transit/connector_get_response.py index 00426f9c13b..2c5ab086aee 100644 --- a/src/cloudflare/types/magic_transit/connector_get_response.py +++ b/src/cloudflare/types/magic_transit/connector_get_response.py @@ -13,6 +13,8 @@ class Device(BaseModel): serial_number: Optional[str] = None + type: Optional[Literal["MANAGED", "LICENSED"]] = None + class ConnectorGetResponse(BaseModel): id: str diff --git a/src/cloudflare/types/magic_transit/connector_list_params.py b/src/cloudflare/types/magic_transit/connector_list_params.py new file mode 100644 index 00000000000..385ec3574f5 --- /dev/null +++ b/src/cloudflare/types/magic_transit/connector_list_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ConnectorListParams"] + + +class ConnectorListParams(TypedDict, total=False): + account_id: Required[str] + """Account identifier""" + + device_type: Literal["MANAGED", "LICENSED"] + """Filter connectors by device type.""" diff --git a/src/cloudflare/types/magic_transit/connector_list_response.py b/src/cloudflare/types/magic_transit/connector_list_response.py index bb73ab1bbf3..06079e4a732 100644 --- a/src/cloudflare/types/magic_transit/connector_list_response.py +++ b/src/cloudflare/types/magic_transit/connector_list_response.py @@ -13,6 +13,8 @@ class Device(BaseModel): serial_number: Optional[str] = None + type: Optional[Literal["MANAGED", "LICENSED"]] = None + class ConnectorListResponse(BaseModel): id: str diff --git a/src/cloudflare/types/magic_transit/connector_update_response.py b/src/cloudflare/types/magic_transit/connector_update_response.py index 35d0ee9f20d..17a1543c152 100644 --- a/src/cloudflare/types/magic_transit/connector_update_response.py +++ b/src/cloudflare/types/magic_transit/connector_update_response.py @@ -13,6 +13,8 @@ class Device(BaseModel): serial_number: Optional[str] = None + type: Optional[Literal["MANAGED", "LICENSED"]] = None + class ConnectorUpdateResponse(BaseModel): id: str diff --git a/src/cloudflare/types/r2/bucket_list_response.py b/src/cloudflare/types/r2/bucket_list_response.py old mode 100755 new mode 100644 diff --git a/src/cloudflare/types/workers_for_platforms/dispatch/namespaces/scripts/secret_get_response.py b/src/cloudflare/types/workers_for_platforms/dispatch/namespaces/scripts/secret_get_response.py old mode 100755 new mode 100644 diff --git a/src/cloudflare/types/zero_trust/access/applications/policy_test_create_params.py b/src/cloudflare/types/zero_trust/access/applications/policy_test_create_params.py old mode 100755 new mode 100644 diff --git a/src/cloudflare/types/zero_trust/access/applications/policy_test_create_response.py b/src/cloudflare/types/zero_trust/access/applications/policy_test_create_response.py old mode 100755 new mode 100644 diff --git a/src/cloudflare/types/zero_trust/access/applications/policy_test_get_response.py b/src/cloudflare/types/zero_trust/access/applications/policy_test_get_response.py old mode 100755 new mode 100644 diff --git a/src/cloudflare/types/zero_trust/access/applications/policy_tests/user_list_response.py b/src/cloudflare/types/zero_trust/access/applications/policy_tests/user_list_response.py old mode 100755 new mode 100644 diff --git a/src/cloudflare/types/zero_trust/devices/setting_edit_params.py b/src/cloudflare/types/zero_trust/devices/setting_edit_params.py old mode 100755 new mode 100644 diff --git a/src/cloudflare/types/zero_trust/dlp/datasets/version_create_params.py b/src/cloudflare/types/zero_trust/dlp/datasets/version_create_params.py old mode 100755 new mode 100644 diff --git a/src/cloudflare/types/zero_trust/dlp/datasets/version_create_response.py b/src/cloudflare/types/zero_trust/dlp/datasets/version_create_response.py old mode 100755 new mode 100644 diff --git a/src/cloudflare/types/zero_trust/dlp/datasets/versions/entry_create_params.py b/src/cloudflare/types/zero_trust/dlp/datasets/versions/entry_create_params.py old mode 100755 new mode 100644 diff --git a/src/cloudflare/types/zero_trust/dlp/datasets/versions/entry_create_response.py b/src/cloudflare/types/zero_trust/dlp/datasets/versions/entry_create_response.py old mode 100755 new mode 100644 diff --git a/src/cloudflare/types/zero_trust/dlp/limit_list_response.py b/src/cloudflare/types/zero_trust/dlp/limit_list_response.py old mode 100755 new mode 100644 diff --git a/src/cloudflare/types/zero_trust/dlp/profile_list_params.py b/src/cloudflare/types/zero_trust/dlp/profile_list_params.py old mode 100755 new mode 100644 diff --git a/tests/api_resources/botnet_feed/configs/__init__.py b/tests/api_resources/botnet_feed/configs/__init__.py old mode 100755 new mode 100644 diff --git a/tests/api_resources/botnet_feed/configs/test_asn.py b/tests/api_resources/botnet_feed/configs/test_asn.py old mode 100755 new mode 100644 diff --git a/tests/api_resources/botnet_feed/test_asn.py b/tests/api_resources/botnet_feed/test_asn.py old mode 100755 new mode 100644 diff --git a/tests/api_resources/email_security/investigate/test_detections.py b/tests/api_resources/email_security/investigate/test_detections.py new file mode 100644 index 00000000000..a8ae16ab645 --- /dev/null +++ b/tests/api_resources/email_security/investigate/test_detections.py @@ -0,0 +1,120 @@ +# 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 pytest + +from cloudflare import Cloudflare, AsyncCloudflare +from tests.utils import assert_matches_type +from cloudflare.types.email_security.investigate import DetectionGetResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestDetections: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_get(self, client: Cloudflare) -> None: + detection = client.email_security.investigate.detections.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + assert_matches_type(DetectionGetResponse, detection, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Cloudflare) -> None: + response = client.email_security.investigate.detections.with_raw_response.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + detection = response.parse() + assert_matches_type(DetectionGetResponse, detection, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Cloudflare) -> None: + with client.email_security.investigate.detections.with_streaming_response.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + detection = response.parse() + assert_matches_type(DetectionGetResponse, detection, 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.email_security.investigate.detections.with_raw_response.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `investigate_id` but received ''"): + client.email_security.investigate.detections.with_raw_response.get( + investigate_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + +class TestAsyncDetections: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_get(self, async_client: AsyncCloudflare) -> None: + detection = await async_client.email_security.investigate.detections.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + assert_matches_type(DetectionGetResponse, detection, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncCloudflare) -> None: + response = await async_client.email_security.investigate.detections.with_raw_response.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + detection = await response.parse() + assert_matches_type(DetectionGetResponse, detection, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncCloudflare) -> None: + async with async_client.email_security.investigate.detections.with_streaming_response.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + detection = await response.parse() + assert_matches_type(DetectionGetResponse, detection, 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.email_security.investigate.detections.with_raw_response.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `investigate_id` but received ''"): + await async_client.email_security.investigate.detections.with_raw_response.get( + investigate_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) diff --git a/tests/api_resources/email_security/investigate/test_move.py b/tests/api_resources/email_security/investigate/test_move.py index bfdd6cc4a7a..cf738cea491 100644 --- a/tests/api_resources/email_security/investigate/test_move.py +++ b/tests/api_resources/email_security/investigate/test_move.py @@ -10,7 +10,10 @@ from cloudflare import Cloudflare, AsyncCloudflare from tests.utils import assert_matches_type from cloudflare.pagination import SyncSinglePage, AsyncSinglePage -from cloudflare.types.email_security.investigate import MoveBulkResponse +from cloudflare.types.email_security.investigate import ( + MoveBulkResponse, + MoveCreateResponse, +) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -18,6 +21,59 @@ class TestMove: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + @parametrize + def test_method_create(self, client: Cloudflare) -> None: + move = client.email_security.investigate.move.create( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + destination="Inbox", + ) + assert_matches_type(SyncSinglePage[MoveCreateResponse], move, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Cloudflare) -> None: + response = client.email_security.investigate.move.with_raw_response.create( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + destination="Inbox", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + move = response.parse() + assert_matches_type(SyncSinglePage[MoveCreateResponse], move, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Cloudflare) -> None: + with client.email_security.investigate.move.with_streaming_response.create( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + destination="Inbox", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + move = response.parse() + assert_matches_type(SyncSinglePage[MoveCreateResponse], move, 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.email_security.investigate.move.with_raw_response.create( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="", + destination="Inbox", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `investigate_id` but received ''"): + client.email_security.investigate.move.with_raw_response.create( + investigate_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + destination="Inbox", + ) + @parametrize def test_method_bulk(self, client: Cloudflare) -> None: move = client.email_security.investigate.move.bulk( @@ -76,6 +132,59 @@ class TestAsyncMove: "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] ) + @parametrize + async def test_method_create(self, async_client: AsyncCloudflare) -> None: + move = await async_client.email_security.investigate.move.create( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + destination="Inbox", + ) + assert_matches_type(AsyncSinglePage[MoveCreateResponse], move, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncCloudflare) -> None: + response = await async_client.email_security.investigate.move.with_raw_response.create( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + destination="Inbox", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + move = await response.parse() + assert_matches_type(AsyncSinglePage[MoveCreateResponse], move, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncCloudflare) -> None: + async with async_client.email_security.investigate.move.with_streaming_response.create( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + destination="Inbox", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + move = await response.parse() + assert_matches_type(AsyncSinglePage[MoveCreateResponse], move, 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.email_security.investigate.move.with_raw_response.create( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="", + destination="Inbox", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `investigate_id` but received ''"): + await async_client.email_security.investigate.move.with_raw_response.create( + investigate_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + destination="Inbox", + ) + @parametrize async def test_method_bulk(self, async_client: AsyncCloudflare) -> None: move = await async_client.email_security.investigate.move.bulk( diff --git a/tests/api_resources/email_security/investigate/test_preview.py b/tests/api_resources/email_security/investigate/test_preview.py index 81c32fc4583..47e7ed01f01 100644 --- a/tests/api_resources/email_security/investigate/test_preview.py +++ b/tests/api_resources/email_security/investigate/test_preview.py @@ -9,7 +9,7 @@ from cloudflare import Cloudflare, AsyncCloudflare from tests.utils import assert_matches_type -from cloudflare.types.email_security.investigate import PreviewCreateResponse +from cloudflare.types.email_security.investigate import PreviewGetResponse, PreviewCreateResponse base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -59,6 +59,54 @@ def test_path_params_create(self, client: Cloudflare) -> None: postfix_id="4Njp3P0STMz2c02Q", ) + @parametrize + def test_method_get(self, client: Cloudflare) -> None: + preview = client.email_security.investigate.preview.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + assert_matches_type(PreviewGetResponse, preview, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Cloudflare) -> None: + response = client.email_security.investigate.preview.with_raw_response.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + preview = response.parse() + assert_matches_type(PreviewGetResponse, preview, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Cloudflare) -> None: + with client.email_security.investigate.preview.with_streaming_response.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + preview = response.parse() + assert_matches_type(PreviewGetResponse, preview, 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.email_security.investigate.preview.with_raw_response.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `investigate_id` but received ''"): + client.email_security.investigate.preview.with_raw_response.get( + investigate_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + class TestAsyncPreview: parametrize = pytest.mark.parametrize( @@ -106,3 +154,51 @@ async def test_path_params_create(self, async_client: AsyncCloudflare) -> None: account_id="", postfix_id="4Njp3P0STMz2c02Q", ) + + @parametrize + async def test_method_get(self, async_client: AsyncCloudflare) -> None: + preview = await async_client.email_security.investigate.preview.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + assert_matches_type(PreviewGetResponse, preview, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncCloudflare) -> None: + response = await async_client.email_security.investigate.preview.with_raw_response.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + preview = await response.parse() + assert_matches_type(PreviewGetResponse, preview, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncCloudflare) -> None: + async with async_client.email_security.investigate.preview.with_streaming_response.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + preview = await response.parse() + assert_matches_type(PreviewGetResponse, preview, 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.email_security.investigate.preview.with_raw_response.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `investigate_id` but received ''"): + await async_client.email_security.investigate.preview.with_raw_response.get( + investigate_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) diff --git a/tests/api_resources/email_security/investigate/test_raw.py b/tests/api_resources/email_security/investigate/test_raw.py new file mode 100644 index 00000000000..79d72553050 --- /dev/null +++ b/tests/api_resources/email_security/investigate/test_raw.py @@ -0,0 +1,120 @@ +# 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 pytest + +from cloudflare import Cloudflare, AsyncCloudflare +from tests.utils import assert_matches_type +from cloudflare.types.email_security.investigate import RawGetResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestRaw: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_get(self, client: Cloudflare) -> None: + raw = client.email_security.investigate.raw.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + assert_matches_type(RawGetResponse, raw, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Cloudflare) -> None: + response = client.email_security.investigate.raw.with_raw_response.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + raw = response.parse() + assert_matches_type(RawGetResponse, raw, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Cloudflare) -> None: + with client.email_security.investigate.raw.with_streaming_response.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + raw = response.parse() + assert_matches_type(RawGetResponse, raw, 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.email_security.investigate.raw.with_raw_response.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `investigate_id` but received ''"): + client.email_security.investigate.raw.with_raw_response.get( + investigate_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + +class TestAsyncRaw: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_get(self, async_client: AsyncCloudflare) -> None: + raw = await async_client.email_security.investigate.raw.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + assert_matches_type(RawGetResponse, raw, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncCloudflare) -> None: + response = await async_client.email_security.investigate.raw.with_raw_response.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + raw = await response.parse() + assert_matches_type(RawGetResponse, raw, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncCloudflare) -> None: + async with async_client.email_security.investigate.raw.with_streaming_response.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + raw = await response.parse() + assert_matches_type(RawGetResponse, raw, 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.email_security.investigate.raw.with_raw_response.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `investigate_id` but received ''"): + await async_client.email_security.investigate.raw.with_raw_response.get( + investigate_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) diff --git a/tests/api_resources/email_security/investigate/test_reclassify.py b/tests/api_resources/email_security/investigate/test_reclassify.py new file mode 100644 index 00000000000..8fe07d41a74 --- /dev/null +++ b/tests/api_resources/email_security/investigate/test_reclassify.py @@ -0,0 +1,151 @@ +# 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 pytest + +from cloudflare import Cloudflare, AsyncCloudflare +from tests.utils import assert_matches_type + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestReclassify: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Cloudflare) -> None: + reclassify = client.email_security.investigate.reclassify.create( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + expected_disposition="NONE", + ) + assert_matches_type(object, reclassify, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Cloudflare) -> None: + reclassify = client.email_security.investigate.reclassify.create( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + expected_disposition="NONE", + eml_content="eml_content", + escalated_submission_id="escalated_submission_id", + ) + assert_matches_type(object, reclassify, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Cloudflare) -> None: + response = client.email_security.investigate.reclassify.with_raw_response.create( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + expected_disposition="NONE", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + reclassify = response.parse() + assert_matches_type(object, reclassify, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Cloudflare) -> None: + with client.email_security.investigate.reclassify.with_streaming_response.create( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + expected_disposition="NONE", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + reclassify = response.parse() + assert_matches_type(object, reclassify, 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.email_security.investigate.reclassify.with_raw_response.create( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="", + expected_disposition="NONE", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `investigate_id` but received ''"): + client.email_security.investigate.reclassify.with_raw_response.create( + investigate_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + expected_disposition="NONE", + ) + + +class TestAsyncReclassify: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncCloudflare) -> None: + reclassify = await async_client.email_security.investigate.reclassify.create( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + expected_disposition="NONE", + ) + assert_matches_type(object, reclassify, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncCloudflare) -> None: + reclassify = await async_client.email_security.investigate.reclassify.create( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + expected_disposition="NONE", + eml_content="eml_content", + escalated_submission_id="escalated_submission_id", + ) + assert_matches_type(object, reclassify, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncCloudflare) -> None: + response = await async_client.email_security.investigate.reclassify.with_raw_response.create( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + expected_disposition="NONE", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + reclassify = await response.parse() + assert_matches_type(object, reclassify, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncCloudflare) -> None: + async with async_client.email_security.investigate.reclassify.with_streaming_response.create( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + expected_disposition="NONE", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + reclassify = await response.parse() + assert_matches_type(object, reclassify, 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.email_security.investigate.reclassify.with_raw_response.create( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="", + expected_disposition="NONE", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `investigate_id` but received ''"): + await async_client.email_security.investigate.reclassify.with_raw_response.create( + investigate_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + expected_disposition="NONE", + ) diff --git a/tests/api_resources/email_security/investigate/test_trace.py b/tests/api_resources/email_security/investigate/test_trace.py new file mode 100644 index 00000000000..fdea6fe7a3a --- /dev/null +++ b/tests/api_resources/email_security/investigate/test_trace.py @@ -0,0 +1,120 @@ +# 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 pytest + +from cloudflare import Cloudflare, AsyncCloudflare +from tests.utils import assert_matches_type +from cloudflare.types.email_security.investigate import TraceGetResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestTrace: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_get(self, client: Cloudflare) -> None: + trace = client.email_security.investigate.trace.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + assert_matches_type(TraceGetResponse, trace, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Cloudflare) -> None: + response = client.email_security.investigate.trace.with_raw_response.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + trace = response.parse() + assert_matches_type(TraceGetResponse, trace, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Cloudflare) -> None: + with client.email_security.investigate.trace.with_streaming_response.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + trace = response.parse() + assert_matches_type(TraceGetResponse, trace, 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.email_security.investigate.trace.with_raw_response.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `investigate_id` but received ''"): + client.email_security.investigate.trace.with_raw_response.get( + investigate_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + +class TestAsyncTrace: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_get(self, async_client: AsyncCloudflare) -> None: + trace = await async_client.email_security.investigate.trace.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + assert_matches_type(TraceGetResponse, trace, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncCloudflare) -> None: + response = await async_client.email_security.investigate.trace.with_raw_response.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + trace = await response.parse() + assert_matches_type(TraceGetResponse, trace, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncCloudflare) -> None: + async with async_client.email_security.investigate.trace.with_streaming_response.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + trace = await response.parse() + assert_matches_type(TraceGetResponse, trace, 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.email_security.investigate.trace.with_raw_response.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `investigate_id` but received ''"): + await async_client.email_security.investigate.trace.with_raw_response.get( + investigate_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) diff --git a/tests/api_resources/email_security/settings/test_impersonation_registry.py b/tests/api_resources/email_security/settings/test_impersonation_registry.py index a8b5ad03e39..ebf6398be74 100644 --- a/tests/api_resources/email_security/settings/test_impersonation_registry.py +++ b/tests/api_resources/email_security/settings/test_impersonation_registry.py @@ -11,8 +11,11 @@ from tests.utils import assert_matches_type from cloudflare.pagination import SyncV4PagePaginationArray, AsyncV4PagePaginationArray from cloudflare.types.email_security.settings import ( + ImpersonationRegistryGetResponse, + ImpersonationRegistryEditResponse, ImpersonationRegistryListResponse, ImpersonationRegistryCreateResponse, + ImpersonationRegistryDeleteResponse, ) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -147,6 +150,174 @@ def test_path_params_list(self, client: Cloudflare) -> None: account_id="", ) + @parametrize + def test_method_delete(self, client: Cloudflare) -> None: + impersonation_registry = client.email_security.settings.impersonation_registry.delete( + impersonation_registry_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + assert_matches_type(Optional[ImpersonationRegistryDeleteResponse], impersonation_registry, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Cloudflare) -> None: + response = client.email_security.settings.impersonation_registry.with_raw_response.delete( + impersonation_registry_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + impersonation_registry = response.parse() + assert_matches_type(Optional[ImpersonationRegistryDeleteResponse], impersonation_registry, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Cloudflare) -> None: + with client.email_security.settings.impersonation_registry.with_streaming_response.delete( + impersonation_registry_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + impersonation_registry = response.parse() + assert_matches_type( + Optional[ImpersonationRegistryDeleteResponse], impersonation_registry, path=["response"] + ) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Cloudflare) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): + client.email_security.settings.impersonation_registry.with_raw_response.delete( + impersonation_registry_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", + account_id="", + ) + + with pytest.raises( + ValueError, match=r"Expected a non-empty value for `impersonation_registry_id` but received ''" + ): + client.email_security.settings.impersonation_registry.with_raw_response.delete( + impersonation_registry_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + @parametrize + def test_method_edit(self, client: Cloudflare) -> None: + impersonation_registry = client.email_security.settings.impersonation_registry.edit( + impersonation_registry_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + assert_matches_type(Optional[ImpersonationRegistryEditResponse], impersonation_registry, path=["response"]) + + @parametrize + def test_method_edit_with_all_params(self, client: Cloudflare) -> None: + impersonation_registry = client.email_security.settings.impersonation_registry.edit( + impersonation_registry_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + comments="comments", + directory_id=0, + directory_node_id=0, + email="john.doe@example.com", + external_directory_node_id="external_directory_node_id", + is_email_regex=False, + name="John Doe", + provenance="A1S_INTERNAL", + ) + assert_matches_type(Optional[ImpersonationRegistryEditResponse], impersonation_registry, path=["response"]) + + @parametrize + def test_raw_response_edit(self, client: Cloudflare) -> None: + response = client.email_security.settings.impersonation_registry.with_raw_response.edit( + impersonation_registry_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + impersonation_registry = response.parse() + assert_matches_type(Optional[ImpersonationRegistryEditResponse], impersonation_registry, path=["response"]) + + @parametrize + def test_streaming_response_edit(self, client: Cloudflare) -> None: + with client.email_security.settings.impersonation_registry.with_streaming_response.edit( + impersonation_registry_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + impersonation_registry = response.parse() + assert_matches_type(Optional[ImpersonationRegistryEditResponse], impersonation_registry, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_edit(self, client: Cloudflare) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): + client.email_security.settings.impersonation_registry.with_raw_response.edit( + impersonation_registry_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", + account_id="", + ) + + with pytest.raises( + ValueError, match=r"Expected a non-empty value for `impersonation_registry_id` but received ''" + ): + client.email_security.settings.impersonation_registry.with_raw_response.edit( + impersonation_registry_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + @parametrize + def test_method_get(self, client: Cloudflare) -> None: + impersonation_registry = client.email_security.settings.impersonation_registry.get( + impersonation_registry_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + assert_matches_type(Optional[ImpersonationRegistryGetResponse], impersonation_registry, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Cloudflare) -> None: + response = client.email_security.settings.impersonation_registry.with_raw_response.get( + impersonation_registry_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + impersonation_registry = response.parse() + assert_matches_type(Optional[ImpersonationRegistryGetResponse], impersonation_registry, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Cloudflare) -> None: + with client.email_security.settings.impersonation_registry.with_streaming_response.get( + impersonation_registry_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + impersonation_registry = response.parse() + assert_matches_type(Optional[ImpersonationRegistryGetResponse], impersonation_registry, 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.email_security.settings.impersonation_registry.with_raw_response.get( + impersonation_registry_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", + account_id="", + ) + + with pytest.raises( + ValueError, match=r"Expected a non-empty value for `impersonation_registry_id` but received ''" + ): + client.email_security.settings.impersonation_registry.with_raw_response.get( + impersonation_registry_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + class TestAsyncImpersonationRegistry: parametrize = pytest.mark.parametrize( @@ -278,3 +449,171 @@ async def test_path_params_list(self, async_client: AsyncCloudflare) -> None: await async_client.email_security.settings.impersonation_registry.with_raw_response.list( account_id="", ) + + @parametrize + async def test_method_delete(self, async_client: AsyncCloudflare) -> None: + impersonation_registry = await async_client.email_security.settings.impersonation_registry.delete( + impersonation_registry_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + assert_matches_type(Optional[ImpersonationRegistryDeleteResponse], impersonation_registry, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncCloudflare) -> None: + response = await async_client.email_security.settings.impersonation_registry.with_raw_response.delete( + impersonation_registry_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + impersonation_registry = await response.parse() + assert_matches_type(Optional[ImpersonationRegistryDeleteResponse], impersonation_registry, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncCloudflare) -> None: + async with async_client.email_security.settings.impersonation_registry.with_streaming_response.delete( + impersonation_registry_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + impersonation_registry = await response.parse() + assert_matches_type( + Optional[ImpersonationRegistryDeleteResponse], impersonation_registry, path=["response"] + ) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(self, async_client: AsyncCloudflare) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): + await async_client.email_security.settings.impersonation_registry.with_raw_response.delete( + impersonation_registry_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", + account_id="", + ) + + with pytest.raises( + ValueError, match=r"Expected a non-empty value for `impersonation_registry_id` but received ''" + ): + await async_client.email_security.settings.impersonation_registry.with_raw_response.delete( + impersonation_registry_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + @parametrize + async def test_method_edit(self, async_client: AsyncCloudflare) -> None: + impersonation_registry = await async_client.email_security.settings.impersonation_registry.edit( + impersonation_registry_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + assert_matches_type(Optional[ImpersonationRegistryEditResponse], impersonation_registry, path=["response"]) + + @parametrize + async def test_method_edit_with_all_params(self, async_client: AsyncCloudflare) -> None: + impersonation_registry = await async_client.email_security.settings.impersonation_registry.edit( + impersonation_registry_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + comments="comments", + directory_id=0, + directory_node_id=0, + email="john.doe@example.com", + external_directory_node_id="external_directory_node_id", + is_email_regex=False, + name="John Doe", + provenance="A1S_INTERNAL", + ) + assert_matches_type(Optional[ImpersonationRegistryEditResponse], impersonation_registry, path=["response"]) + + @parametrize + async def test_raw_response_edit(self, async_client: AsyncCloudflare) -> None: + response = await async_client.email_security.settings.impersonation_registry.with_raw_response.edit( + impersonation_registry_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + impersonation_registry = await response.parse() + assert_matches_type(Optional[ImpersonationRegistryEditResponse], impersonation_registry, path=["response"]) + + @parametrize + async def test_streaming_response_edit(self, async_client: AsyncCloudflare) -> None: + async with async_client.email_security.settings.impersonation_registry.with_streaming_response.edit( + impersonation_registry_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + impersonation_registry = await response.parse() + assert_matches_type(Optional[ImpersonationRegistryEditResponse], impersonation_registry, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_edit(self, async_client: AsyncCloudflare) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): + await async_client.email_security.settings.impersonation_registry.with_raw_response.edit( + impersonation_registry_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", + account_id="", + ) + + with pytest.raises( + ValueError, match=r"Expected a non-empty value for `impersonation_registry_id` but received ''" + ): + await async_client.email_security.settings.impersonation_registry.with_raw_response.edit( + impersonation_registry_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + @parametrize + async def test_method_get(self, async_client: AsyncCloudflare) -> None: + impersonation_registry = await async_client.email_security.settings.impersonation_registry.get( + impersonation_registry_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + assert_matches_type(Optional[ImpersonationRegistryGetResponse], impersonation_registry, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncCloudflare) -> None: + response = await async_client.email_security.settings.impersonation_registry.with_raw_response.get( + impersonation_registry_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + impersonation_registry = await response.parse() + assert_matches_type(Optional[ImpersonationRegistryGetResponse], impersonation_registry, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncCloudflare) -> None: + async with async_client.email_security.settings.impersonation_registry.with_streaming_response.get( + impersonation_registry_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + impersonation_registry = await response.parse() + assert_matches_type(Optional[ImpersonationRegistryGetResponse], impersonation_registry, 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.email_security.settings.impersonation_registry.with_raw_response.get( + impersonation_registry_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", + account_id="", + ) + + with pytest.raises( + ValueError, match=r"Expected a non-empty value for `impersonation_registry_id` but received ''" + ): + await async_client.email_security.settings.impersonation_registry.with_raw_response.get( + impersonation_registry_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) diff --git a/tests/api_resources/email_security/test_investigate.py b/tests/api_resources/email_security/test_investigate.py index c9b051a9e22..82f56549196 100644 --- a/tests/api_resources/email_security/test_investigate.py +++ b/tests/api_resources/email_security/test_investigate.py @@ -11,7 +11,10 @@ from tests.utils import assert_matches_type from cloudflare._utils import parse_datetime from cloudflare.pagination import SyncV4PagePaginationArray, AsyncV4PagePaginationArray -from cloudflare.types.email_security import InvestigateListResponse +from cloudflare.types.email_security import ( + InvestigateGetResponse, + InvestigateListResponse, +) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -81,6 +84,63 @@ def test_path_params_list(self, client: Cloudflare) -> None: account_id="", ) + @parametrize + def test_method_get(self, client: Cloudflare) -> None: + investigate = client.email_security.investigate.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + assert_matches_type(InvestigateGetResponse, investigate, path=["response"]) + + @parametrize + def test_method_get_with_all_params(self, client: Cloudflare) -> None: + investigate = client.email_security.investigate.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + submission=True, + ) + assert_matches_type(InvestigateGetResponse, investigate, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Cloudflare) -> None: + response = client.email_security.investigate.with_raw_response.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + investigate = response.parse() + assert_matches_type(InvestigateGetResponse, investigate, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Cloudflare) -> None: + with client.email_security.investigate.with_streaming_response.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + investigate = response.parse() + assert_matches_type(InvestigateGetResponse, investigate, 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.email_security.investigate.with_raw_response.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `investigate_id` but received ''"): + client.email_security.investigate.with_raw_response.get( + investigate_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + class TestAsyncInvestigate: parametrize = pytest.mark.parametrize( @@ -148,3 +208,60 @@ async def test_path_params_list(self, async_client: AsyncCloudflare) -> None: await async_client.email_security.investigate.with_raw_response.list( account_id="", ) + + @parametrize + async def test_method_get(self, async_client: AsyncCloudflare) -> None: + investigate = await async_client.email_security.investigate.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + assert_matches_type(InvestigateGetResponse, investigate, path=["response"]) + + @parametrize + async def test_method_get_with_all_params(self, async_client: AsyncCloudflare) -> None: + investigate = await async_client.email_security.investigate.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + submission=True, + ) + assert_matches_type(InvestigateGetResponse, investigate, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncCloudflare) -> None: + response = await async_client.email_security.investigate.with_raw_response.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + investigate = await response.parse() + assert_matches_type(InvestigateGetResponse, investigate, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncCloudflare) -> None: + async with async_client.email_security.investigate.with_streaming_response.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + investigate = await response.parse() + assert_matches_type(InvestigateGetResponse, investigate, 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.email_security.investigate.with_raw_response.get( + investigate_id="4Njp3P0STMz2c02Q-2024-01-05T10:00:00-12345678", + account_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `investigate_id` but received ''"): + await async_client.email_security.investigate.with_raw_response.get( + investigate_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) diff --git a/tests/api_resources/magic_transit/test_connectors.py b/tests/api_resources/magic_transit/test_connectors.py index 17cf666175a..640220cc89b 100644 --- a/tests/api_resources/magic_transit/test_connectors.py +++ b/tests/api_resources/magic_transit/test_connectors.py @@ -172,6 +172,14 @@ def test_method_list(self, client: Cloudflare) -> None: ) assert_matches_type(SyncSinglePage[ConnectorListResponse], connector, path=["response"]) + @parametrize + def test_method_list_with_all_params(self, client: Cloudflare) -> None: + connector = client.magic_transit.connectors.list( + account_id="023e105f4ecef8ad9ca31a8372d0c353", + device_type="MANAGED", + ) + assert_matches_type(SyncSinglePage[ConnectorListResponse], connector, path=["response"]) + @parametrize def test_raw_response_list(self, client: Cloudflare) -> None: response = client.magic_transit.connectors.with_raw_response.list( @@ -516,6 +524,14 @@ async def test_method_list(self, async_client: AsyncCloudflare) -> None: ) assert_matches_type(AsyncSinglePage[ConnectorListResponse], connector, path=["response"]) + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncCloudflare) -> None: + connector = await async_client.magic_transit.connectors.list( + account_id="023e105f4ecef8ad9ca31a8372d0c353", + device_type="MANAGED", + ) + assert_matches_type(AsyncSinglePage[ConnectorListResponse], connector, path=["response"]) + @parametrize async def test_raw_response_list(self, async_client: AsyncCloudflare) -> None: response = await async_client.magic_transit.connectors.with_raw_response.list( diff --git a/tests/api_resources/zero_trust/access/applications/policy_tests/__init__.py b/tests/api_resources/zero_trust/access/applications/policy_tests/__init__.py old mode 100755 new mode 100644 diff --git a/tests/api_resources/zero_trust/access/applications/policy_tests/test_users.py b/tests/api_resources/zero_trust/access/applications/policy_tests/test_users.py old mode 100755 new mode 100644 diff --git a/tests/api_resources/zero_trust/access/applications/test_policy_tests.py b/tests/api_resources/zero_trust/access/applications/test_policy_tests.py old mode 100755 new mode 100644 diff --git a/tests/api_resources/zero_trust/dlp/datasets/test_versions.py b/tests/api_resources/zero_trust/dlp/datasets/test_versions.py old mode 100755 new mode 100644 diff --git a/tests/api_resources/zero_trust/dlp/datasets/versions/__init__.py b/tests/api_resources/zero_trust/dlp/datasets/versions/__init__.py old mode 100755 new mode 100644 diff --git a/tests/api_resources/zero_trust/dlp/datasets/versions/test_entries.py b/tests/api_resources/zero_trust/dlp/datasets/versions/test_entries.py old mode 100755 new mode 100644 diff --git a/tests/api_resources/zero_trust/dlp/test_limits.py b/tests/api_resources/zero_trust/dlp/test_limits.py old mode 100755 new mode 100644 diff --git a/tests/api_resources/zero_trust/gateway/configurations/__init__.py b/tests/api_resources/zero_trust/gateway/configurations/__init__.py old mode 100755 new mode 100644 From 5c7db6b58536ae9cb1fe20f5f4e9eb8c827d594e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 29 Apr 2026 21:03:38 +0000 Subject: [PATCH 14/45] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index bb8578554e1..0d382114c27 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 2195 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a6c352830d1270d0abb5bb983058ea21815e1bb7d2e163965335dcb0e706f057.yml openapi_spec_hash: 04d3f0746288b539043c14a9eaab066d -config_hash: 763a29f9838b6c535ff5a0e883bd3209 +config_hash: 21f60bdd0f0b7d52ffabed72d0fd2020 From 434e873ede679e19ffb96812e936081718321946 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 29 Apr 2026 21:40:44 +0000 Subject: [PATCH 15/45] chore(api): update composite API spec --- .stats.yml | 2 +- .../dlp/entries/custom_get_response.py | 23 +++- .../dlp/entries/custom_list_response.py | 23 +++- .../dlp/entries/integration_get_response.py | 23 +++- .../dlp/entries/integration_list_response.py | 23 +++- .../dlp/entries/predefined_create_response.py | 27 +++- .../dlp/entries/predefined_get_response.py | 23 +++- .../dlp/entries/predefined_list_response.py | 23 +++- .../dlp/entries/predefined_update_response.py | 27 +++- .../zero_trust/dlp/entry_get_response.py | 23 +++- .../zero_trust/dlp/entry_list_response.py | 23 +++- .../zero_trust/dlp/entry_update_response.py | 23 +++- .../types/zero_trust/dlp/profile.py | 127 +++++++++++++++++- .../dlp/profiles/predefined_profile.py | 25 +++- 14 files changed, 391 insertions(+), 24 deletions(-) diff --git a/.stats.yml b/.stats.yml index 0d382114c27..f1bb0e04443 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 2195 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a6c352830d1270d0abb5bb983058ea21815e1bb7d2e163965335dcb0e706f057.yml -openapi_spec_hash: 04d3f0746288b539043c14a9eaab066d +openapi_spec_hash: ffe469d5b0b3f29c20ccb91c0a2862e7 config_hash: 21f60bdd0f0b7d52ffabed72d0fd2020 diff --git a/src/cloudflare/types/zero_trust/dlp/entries/custom_get_response.py b/src/cloudflare/types/zero_trust/dlp/entries/custom_get_response.py index 0643a73c554..d0af2de6213 100644 --- a/src/cloudflare/types/zero_trust/dlp/entries/custom_get_response.py +++ b/src/cloudflare/types/zero_trust/dlp/entries/custom_get_response.py @@ -15,6 +15,8 @@ "UnionMember1Confidence", "UnionMember1Profile", "UnionMember1Variant", + "UnionMember1VariantUnionMember0", + "UnionMember1VariantUnionMember1", "UnionMember2", "UnionMember2Profile", "UnionMember3", @@ -77,12 +79,30 @@ class UnionMember1Profile(BaseModel): name: str -class UnionMember1Variant(BaseModel): +class UnionMember1VariantUnionMember0(BaseModel): + """A Predefined AI prompt classification topic entry.""" + topic_type: Literal["Intent", "Content"] type: Literal["PromptTopic"] description: Optional[str] = None + """ + A customer-facing explanation of what this predefined AI prompt topic + represents. + """ + + +class UnionMember1VariantUnionMember1(BaseModel): + """A general predefined entry.""" + + type: Literal["General"] + + description: Optional[str] = None + """A customer-facing explanation of what this predefined entry represents.""" + + +UnionMember1Variant: TypeAlias = Union[UnionMember1VariantUnionMember0, UnionMember1VariantUnionMember1] class UnionMember1(BaseModel): @@ -103,6 +123,7 @@ class UnionMember1(BaseModel): upload_status: Optional[Literal["empty", "uploading", "pending", "processing", "failed", "complete"]] = None variant: Optional[UnionMember1Variant] = None + """A Predefined AI prompt classification topic entry.""" class UnionMember2Profile(BaseModel): diff --git a/src/cloudflare/types/zero_trust/dlp/entries/custom_list_response.py b/src/cloudflare/types/zero_trust/dlp/entries/custom_list_response.py index af4e3334fbc..c8c47ce738d 100644 --- a/src/cloudflare/types/zero_trust/dlp/entries/custom_list_response.py +++ b/src/cloudflare/types/zero_trust/dlp/entries/custom_list_response.py @@ -13,6 +13,8 @@ "UnionMember1", "UnionMember1Confidence", "UnionMember1Variant", + "UnionMember1VariantUnionMember0", + "UnionMember1VariantUnionMember1", "UnionMember2", "UnionMember3", "UnionMember4", @@ -53,12 +55,30 @@ class UnionMember1Confidence(BaseModel): """ -class UnionMember1Variant(BaseModel): +class UnionMember1VariantUnionMember0(BaseModel): + """A Predefined AI prompt classification topic entry.""" + topic_type: Literal["Intent", "Content"] type: Literal["PromptTopic"] description: Optional[str] = None + """ + A customer-facing explanation of what this predefined AI prompt topic + represents. + """ + + +class UnionMember1VariantUnionMember1(BaseModel): + """A general predefined entry.""" + + type: Literal["General"] + + description: Optional[str] = None + """A customer-facing explanation of what this predefined entry represents.""" + + +UnionMember1Variant: TypeAlias = Union[UnionMember1VariantUnionMember0, UnionMember1VariantUnionMember1] class UnionMember1(BaseModel): @@ -77,6 +97,7 @@ class UnionMember1(BaseModel): upload_status: Optional[Literal["empty", "uploading", "pending", "processing", "failed", "complete"]] = None variant: Optional[UnionMember1Variant] = None + """A Predefined AI prompt classification topic entry.""" class UnionMember2(BaseModel): diff --git a/src/cloudflare/types/zero_trust/dlp/entries/integration_get_response.py b/src/cloudflare/types/zero_trust/dlp/entries/integration_get_response.py index da9028d38d6..28c992d2143 100644 --- a/src/cloudflare/types/zero_trust/dlp/entries/integration_get_response.py +++ b/src/cloudflare/types/zero_trust/dlp/entries/integration_get_response.py @@ -15,6 +15,8 @@ "UnionMember1Confidence", "UnionMember1Profile", "UnionMember1Variant", + "UnionMember1VariantUnionMember0", + "UnionMember1VariantUnionMember1", "UnionMember2", "UnionMember2Profile", "UnionMember3", @@ -77,12 +79,30 @@ class UnionMember1Profile(BaseModel): name: str -class UnionMember1Variant(BaseModel): +class UnionMember1VariantUnionMember0(BaseModel): + """A Predefined AI prompt classification topic entry.""" + topic_type: Literal["Intent", "Content"] type: Literal["PromptTopic"] description: Optional[str] = None + """ + A customer-facing explanation of what this predefined AI prompt topic + represents. + """ + + +class UnionMember1VariantUnionMember1(BaseModel): + """A general predefined entry.""" + + type: Literal["General"] + + description: Optional[str] = None + """A customer-facing explanation of what this predefined entry represents.""" + + +UnionMember1Variant: TypeAlias = Union[UnionMember1VariantUnionMember0, UnionMember1VariantUnionMember1] class UnionMember1(BaseModel): @@ -103,6 +123,7 @@ class UnionMember1(BaseModel): upload_status: Optional[Literal["empty", "uploading", "pending", "processing", "failed", "complete"]] = None variant: Optional[UnionMember1Variant] = None + """A Predefined AI prompt classification topic entry.""" class UnionMember2Profile(BaseModel): diff --git a/src/cloudflare/types/zero_trust/dlp/entries/integration_list_response.py b/src/cloudflare/types/zero_trust/dlp/entries/integration_list_response.py index ea7214a2153..f757267e68e 100644 --- a/src/cloudflare/types/zero_trust/dlp/entries/integration_list_response.py +++ b/src/cloudflare/types/zero_trust/dlp/entries/integration_list_response.py @@ -13,6 +13,8 @@ "UnionMember1", "UnionMember1Confidence", "UnionMember1Variant", + "UnionMember1VariantUnionMember0", + "UnionMember1VariantUnionMember1", "UnionMember2", "UnionMember3", "UnionMember4", @@ -53,12 +55,30 @@ class UnionMember1Confidence(BaseModel): """ -class UnionMember1Variant(BaseModel): +class UnionMember1VariantUnionMember0(BaseModel): + """A Predefined AI prompt classification topic entry.""" + topic_type: Literal["Intent", "Content"] type: Literal["PromptTopic"] description: Optional[str] = None + """ + A customer-facing explanation of what this predefined AI prompt topic + represents. + """ + + +class UnionMember1VariantUnionMember1(BaseModel): + """A general predefined entry.""" + + type: Literal["General"] + + description: Optional[str] = None + """A customer-facing explanation of what this predefined entry represents.""" + + +UnionMember1Variant: TypeAlias = Union[UnionMember1VariantUnionMember0, UnionMember1VariantUnionMember1] class UnionMember1(BaseModel): @@ -77,6 +97,7 @@ class UnionMember1(BaseModel): upload_status: Optional[Literal["empty", "uploading", "pending", "processing", "failed", "complete"]] = None variant: Optional[UnionMember1Variant] = None + """A Predefined AI prompt classification topic entry.""" class UnionMember2(BaseModel): diff --git a/src/cloudflare/types/zero_trust/dlp/entries/predefined_create_response.py b/src/cloudflare/types/zero_trust/dlp/entries/predefined_create_response.py index 60864076dca..21f28b21f3f 100644 --- a/src/cloudflare/types/zero_trust/dlp/entries/predefined_create_response.py +++ b/src/cloudflare/types/zero_trust/dlp/entries/predefined_create_response.py @@ -1,11 +1,11 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional -from typing_extensions import Literal +from typing import Union, Optional +from typing_extensions import Literal, TypeAlias from ....._models import BaseModel -__all__ = ["PredefinedCreateResponse", "Confidence", "Variant"] +__all__ = ["PredefinedCreateResponse", "Confidence", "Variant", "VariantUnionMember0", "VariantUnionMember1"] class Confidence(BaseModel): @@ -19,12 +19,30 @@ class Confidence(BaseModel): """ -class Variant(BaseModel): +class VariantUnionMember0(BaseModel): + """A Predefined AI prompt classification topic entry.""" + topic_type: Literal["Intent", "Content"] type: Literal["PromptTopic"] description: Optional[str] = None + """ + A customer-facing explanation of what this predefined AI prompt topic + represents. + """ + + +class VariantUnionMember1(BaseModel): + """A general predefined entry.""" + + type: Literal["General"] + + description: Optional[str] = None + """A customer-facing explanation of what this predefined entry represents.""" + + +Variant: TypeAlias = Union[VariantUnionMember0, VariantUnionMember1] class PredefinedCreateResponse(BaseModel): @@ -39,3 +57,4 @@ class PredefinedCreateResponse(BaseModel): profile_id: Optional[str] = None variant: Optional[Variant] = None + """A Predefined AI prompt classification topic entry.""" diff --git a/src/cloudflare/types/zero_trust/dlp/entries/predefined_get_response.py b/src/cloudflare/types/zero_trust/dlp/entries/predefined_get_response.py index 975c433ccf9..8d7479e52b7 100644 --- a/src/cloudflare/types/zero_trust/dlp/entries/predefined_get_response.py +++ b/src/cloudflare/types/zero_trust/dlp/entries/predefined_get_response.py @@ -15,6 +15,8 @@ "UnionMember1Confidence", "UnionMember1Profile", "UnionMember1Variant", + "UnionMember1VariantUnionMember0", + "UnionMember1VariantUnionMember1", "UnionMember2", "UnionMember2Profile", "UnionMember3", @@ -77,12 +79,30 @@ class UnionMember1Profile(BaseModel): name: str -class UnionMember1Variant(BaseModel): +class UnionMember1VariantUnionMember0(BaseModel): + """A Predefined AI prompt classification topic entry.""" + topic_type: Literal["Intent", "Content"] type: Literal["PromptTopic"] description: Optional[str] = None + """ + A customer-facing explanation of what this predefined AI prompt topic + represents. + """ + + +class UnionMember1VariantUnionMember1(BaseModel): + """A general predefined entry.""" + + type: Literal["General"] + + description: Optional[str] = None + """A customer-facing explanation of what this predefined entry represents.""" + + +UnionMember1Variant: TypeAlias = Union[UnionMember1VariantUnionMember0, UnionMember1VariantUnionMember1] class UnionMember1(BaseModel): @@ -103,6 +123,7 @@ class UnionMember1(BaseModel): upload_status: Optional[Literal["empty", "uploading", "pending", "processing", "failed", "complete"]] = None variant: Optional[UnionMember1Variant] = None + """A Predefined AI prompt classification topic entry.""" class UnionMember2Profile(BaseModel): diff --git a/src/cloudflare/types/zero_trust/dlp/entries/predefined_list_response.py b/src/cloudflare/types/zero_trust/dlp/entries/predefined_list_response.py index 2dcfabd8dc1..177f70b1745 100644 --- a/src/cloudflare/types/zero_trust/dlp/entries/predefined_list_response.py +++ b/src/cloudflare/types/zero_trust/dlp/entries/predefined_list_response.py @@ -13,6 +13,8 @@ "UnionMember1", "UnionMember1Confidence", "UnionMember1Variant", + "UnionMember1VariantUnionMember0", + "UnionMember1VariantUnionMember1", "UnionMember2", "UnionMember3", "UnionMember4", @@ -53,12 +55,30 @@ class UnionMember1Confidence(BaseModel): """ -class UnionMember1Variant(BaseModel): +class UnionMember1VariantUnionMember0(BaseModel): + """A Predefined AI prompt classification topic entry.""" + topic_type: Literal["Intent", "Content"] type: Literal["PromptTopic"] description: Optional[str] = None + """ + A customer-facing explanation of what this predefined AI prompt topic + represents. + """ + + +class UnionMember1VariantUnionMember1(BaseModel): + """A general predefined entry.""" + + type: Literal["General"] + + description: Optional[str] = None + """A customer-facing explanation of what this predefined entry represents.""" + + +UnionMember1Variant: TypeAlias = Union[UnionMember1VariantUnionMember0, UnionMember1VariantUnionMember1] class UnionMember1(BaseModel): @@ -77,6 +97,7 @@ class UnionMember1(BaseModel): upload_status: Optional[Literal["empty", "uploading", "pending", "processing", "failed", "complete"]] = None variant: Optional[UnionMember1Variant] = None + """A Predefined AI prompt classification topic entry.""" class UnionMember2(BaseModel): diff --git a/src/cloudflare/types/zero_trust/dlp/entries/predefined_update_response.py b/src/cloudflare/types/zero_trust/dlp/entries/predefined_update_response.py index 178470ad0a2..f72509d654d 100644 --- a/src/cloudflare/types/zero_trust/dlp/entries/predefined_update_response.py +++ b/src/cloudflare/types/zero_trust/dlp/entries/predefined_update_response.py @@ -1,11 +1,11 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional -from typing_extensions import Literal +from typing import Union, Optional +from typing_extensions import Literal, TypeAlias from ....._models import BaseModel -__all__ = ["PredefinedUpdateResponse", "Confidence", "Variant"] +__all__ = ["PredefinedUpdateResponse", "Confidence", "Variant", "VariantUnionMember0", "VariantUnionMember1"] class Confidence(BaseModel): @@ -19,12 +19,30 @@ class Confidence(BaseModel): """ -class Variant(BaseModel): +class VariantUnionMember0(BaseModel): + """A Predefined AI prompt classification topic entry.""" + topic_type: Literal["Intent", "Content"] type: Literal["PromptTopic"] description: Optional[str] = None + """ + A customer-facing explanation of what this predefined AI prompt topic + represents. + """ + + +class VariantUnionMember1(BaseModel): + """A general predefined entry.""" + + type: Literal["General"] + + description: Optional[str] = None + """A customer-facing explanation of what this predefined entry represents.""" + + +Variant: TypeAlias = Union[VariantUnionMember0, VariantUnionMember1] class PredefinedUpdateResponse(BaseModel): @@ -39,3 +57,4 @@ class PredefinedUpdateResponse(BaseModel): profile_id: Optional[str] = None variant: Optional[Variant] = None + """A Predefined AI prompt classification topic entry.""" diff --git a/src/cloudflare/types/zero_trust/dlp/entry_get_response.py b/src/cloudflare/types/zero_trust/dlp/entry_get_response.py index b14a69946d9..1ee40f14fd5 100644 --- a/src/cloudflare/types/zero_trust/dlp/entry_get_response.py +++ b/src/cloudflare/types/zero_trust/dlp/entry_get_response.py @@ -15,6 +15,8 @@ "UnionMember1Confidence", "UnionMember1Profile", "UnionMember1Variant", + "UnionMember1VariantUnionMember0", + "UnionMember1VariantUnionMember1", "UnionMember2", "UnionMember2Profile", "UnionMember3", @@ -77,12 +79,30 @@ class UnionMember1Profile(BaseModel): name: str -class UnionMember1Variant(BaseModel): +class UnionMember1VariantUnionMember0(BaseModel): + """A Predefined AI prompt classification topic entry.""" + topic_type: Literal["Intent", "Content"] type: Literal["PromptTopic"] description: Optional[str] = None + """ + A customer-facing explanation of what this predefined AI prompt topic + represents. + """ + + +class UnionMember1VariantUnionMember1(BaseModel): + """A general predefined entry.""" + + type: Literal["General"] + + description: Optional[str] = None + """A customer-facing explanation of what this predefined entry represents.""" + + +UnionMember1Variant: TypeAlias = Union[UnionMember1VariantUnionMember0, UnionMember1VariantUnionMember1] class UnionMember1(BaseModel): @@ -103,6 +123,7 @@ class UnionMember1(BaseModel): upload_status: Optional[Literal["empty", "uploading", "pending", "processing", "failed", "complete"]] = None variant: Optional[UnionMember1Variant] = None + """A Predefined AI prompt classification topic entry.""" class UnionMember2Profile(BaseModel): diff --git a/src/cloudflare/types/zero_trust/dlp/entry_list_response.py b/src/cloudflare/types/zero_trust/dlp/entry_list_response.py index c0e6b250d00..d6661bd90df 100644 --- a/src/cloudflare/types/zero_trust/dlp/entry_list_response.py +++ b/src/cloudflare/types/zero_trust/dlp/entry_list_response.py @@ -13,6 +13,8 @@ "UnionMember1", "UnionMember1Confidence", "UnionMember1Variant", + "UnionMember1VariantUnionMember0", + "UnionMember1VariantUnionMember1", "UnionMember2", "UnionMember3", "UnionMember4", @@ -53,12 +55,30 @@ class UnionMember1Confidence(BaseModel): """ -class UnionMember1Variant(BaseModel): +class UnionMember1VariantUnionMember0(BaseModel): + """A Predefined AI prompt classification topic entry.""" + topic_type: Literal["Intent", "Content"] type: Literal["PromptTopic"] description: Optional[str] = None + """ + A customer-facing explanation of what this predefined AI prompt topic + represents. + """ + + +class UnionMember1VariantUnionMember1(BaseModel): + """A general predefined entry.""" + + type: Literal["General"] + + description: Optional[str] = None + """A customer-facing explanation of what this predefined entry represents.""" + + +UnionMember1Variant: TypeAlias = Union[UnionMember1VariantUnionMember0, UnionMember1VariantUnionMember1] class UnionMember1(BaseModel): @@ -77,6 +97,7 @@ class UnionMember1(BaseModel): upload_status: Optional[Literal["empty", "uploading", "pending", "processing", "failed", "complete"]] = None variant: Optional[UnionMember1Variant] = None + """A Predefined AI prompt classification topic entry.""" class UnionMember2(BaseModel): diff --git a/src/cloudflare/types/zero_trust/dlp/entry_update_response.py b/src/cloudflare/types/zero_trust/dlp/entry_update_response.py index 0e256a22386..3b569087412 100644 --- a/src/cloudflare/types/zero_trust/dlp/entry_update_response.py +++ b/src/cloudflare/types/zero_trust/dlp/entry_update_response.py @@ -13,6 +13,8 @@ "PredefinedEntry", "PredefinedEntryConfidence", "PredefinedEntryVariant", + "PredefinedEntryVariantUnionMember0", + "PredefinedEntryVariantUnionMember1", "IntegrationEntry", "ExactDataEntry", "DocumentFingerprintEntry", @@ -51,12 +53,30 @@ class PredefinedEntryConfidence(BaseModel): """ -class PredefinedEntryVariant(BaseModel): +class PredefinedEntryVariantUnionMember0(BaseModel): + """A Predefined AI prompt classification topic entry.""" + topic_type: Literal["Intent", "Content"] type: Literal["PromptTopic"] description: Optional[str] = None + """ + A customer-facing explanation of what this predefined AI prompt topic + represents. + """ + + +class PredefinedEntryVariantUnionMember1(BaseModel): + """A general predefined entry.""" + + type: Literal["General"] + + description: Optional[str] = None + """A customer-facing explanation of what this predefined entry represents.""" + + +PredefinedEntryVariant: TypeAlias = Union[PredefinedEntryVariantUnionMember0, PredefinedEntryVariantUnionMember1] class PredefinedEntry(BaseModel): @@ -73,6 +93,7 @@ class PredefinedEntry(BaseModel): profile_id: Optional[str] = None variant: Optional[PredefinedEntryVariant] = None + """A Predefined AI prompt classification topic entry.""" class IntegrationEntry(BaseModel): diff --git a/src/cloudflare/types/zero_trust/dlp/profile.py b/src/cloudflare/types/zero_trust/dlp/profile.py index 96d6a05976b..869b45315df 100644 --- a/src/cloudflare/types/zero_trust/dlp/profile.py +++ b/src/cloudflare/types/zero_trust/dlp/profile.py @@ -19,6 +19,8 @@ "CustomProfileEntryPredefinedEntry", "CustomProfileEntryPredefinedEntryConfidence", "CustomProfileEntryPredefinedEntryVariant", + "CustomProfileEntryPredefinedEntryVariantUnionMember0", + "CustomProfileEntryPredefinedEntryVariantUnionMember1", "CustomProfileEntryIntegrationEntry", "CustomProfileEntryExactDataEntry", "CustomProfileEntryDocumentFingerprintEntry", @@ -29,6 +31,8 @@ "CustomProfileSharedEntryPredefinedEntry", "CustomProfileSharedEntryPredefinedEntryConfidence", "CustomProfileSharedEntryPredefinedEntryVariant", + "CustomProfileSharedEntryPredefinedEntryVariantUnionMember0", + "CustomProfileSharedEntryPredefinedEntryVariantUnionMember1", "CustomProfileSharedEntryIntegrationEntry", "CustomProfileSharedEntryExactDataEntry", "CustomProfileSharedEntryDocumentFingerprintEntry", @@ -39,6 +43,8 @@ "PredefinedProfileEntryPredefinedEntry", "PredefinedProfileEntryPredefinedEntryConfidence", "PredefinedProfileEntryPredefinedEntryVariant", + "PredefinedProfileEntryPredefinedEntryVariantUnionMember0", + "PredefinedProfileEntryPredefinedEntryVariantUnionMember1", "PredefinedProfileEntryIntegrationEntry", "PredefinedProfileEntryExactDataEntry", "PredefinedProfileEntryDocumentFingerprintEntry", @@ -49,6 +55,8 @@ "IntegrationProfileEntryPredefinedEntry", "IntegrationProfileEntryPredefinedEntryConfidence", "IntegrationProfileEntryPredefinedEntryVariant", + "IntegrationProfileEntryPredefinedEntryVariantUnionMember0", + "IntegrationProfileEntryPredefinedEntryVariantUnionMember1", "IntegrationProfileEntryIntegrationEntry", "IntegrationProfileEntryExactDataEntry", "IntegrationProfileEntryDocumentFingerprintEntry", @@ -58,6 +66,8 @@ "IntegrationProfileSharedEntryPredefinedEntry", "IntegrationProfileSharedEntryPredefinedEntryConfidence", "IntegrationProfileSharedEntryPredefinedEntryVariant", + "IntegrationProfileSharedEntryPredefinedEntryVariantUnionMember0", + "IntegrationProfileSharedEntryPredefinedEntryVariantUnionMember1", "IntegrationProfileSharedEntryIntegrationEntry", "IntegrationProfileSharedEntryExactDataEntry", "IntegrationProfileSharedEntryDocumentFingerprintEntry", @@ -96,12 +106,32 @@ class CustomProfileEntryPredefinedEntryConfidence(BaseModel): """ -class CustomProfileEntryPredefinedEntryVariant(BaseModel): +class CustomProfileEntryPredefinedEntryVariantUnionMember0(BaseModel): + """A Predefined AI prompt classification topic entry.""" + topic_type: Literal["Intent", "Content"] type: Literal["PromptTopic"] description: Optional[str] = None + """ + A customer-facing explanation of what this predefined AI prompt topic + represents. + """ + + +class CustomProfileEntryPredefinedEntryVariantUnionMember1(BaseModel): + """A general predefined entry.""" + + type: Literal["General"] + + description: Optional[str] = None + """A customer-facing explanation of what this predefined entry represents.""" + + +CustomProfileEntryPredefinedEntryVariant: TypeAlias = Union[ + CustomProfileEntryPredefinedEntryVariantUnionMember0, CustomProfileEntryPredefinedEntryVariantUnionMember1 +] class CustomProfileEntryPredefinedEntry(BaseModel): @@ -118,6 +148,7 @@ class CustomProfileEntryPredefinedEntry(BaseModel): profile_id: Optional[str] = None variant: Optional[CustomProfileEntryPredefinedEntryVariant] = None + """A Predefined AI prompt classification topic entry.""" class CustomProfileEntryIntegrationEntry(BaseModel): @@ -241,12 +272,33 @@ class CustomProfileSharedEntryPredefinedEntryConfidence(BaseModel): """ -class CustomProfileSharedEntryPredefinedEntryVariant(BaseModel): +class CustomProfileSharedEntryPredefinedEntryVariantUnionMember0(BaseModel): + """A Predefined AI prompt classification topic entry.""" + topic_type: Literal["Intent", "Content"] type: Literal["PromptTopic"] description: Optional[str] = None + """ + A customer-facing explanation of what this predefined AI prompt topic + represents. + """ + + +class CustomProfileSharedEntryPredefinedEntryVariantUnionMember1(BaseModel): + """A general predefined entry.""" + + type: Literal["General"] + + description: Optional[str] = None + """A customer-facing explanation of what this predefined entry represents.""" + + +CustomProfileSharedEntryPredefinedEntryVariant: TypeAlias = Union[ + CustomProfileSharedEntryPredefinedEntryVariantUnionMember0, + CustomProfileSharedEntryPredefinedEntryVariantUnionMember1, +] class CustomProfileSharedEntryPredefinedEntry(BaseModel): @@ -263,6 +315,7 @@ class CustomProfileSharedEntryPredefinedEntry(BaseModel): profile_id: Optional[str] = None variant: Optional[CustomProfileSharedEntryPredefinedEntryVariant] = None + """A Predefined AI prompt classification topic entry.""" class CustomProfileSharedEntryIntegrationEntry(BaseModel): @@ -423,12 +476,32 @@ class PredefinedProfileEntryPredefinedEntryConfidence(BaseModel): """ -class PredefinedProfileEntryPredefinedEntryVariant(BaseModel): +class PredefinedProfileEntryPredefinedEntryVariantUnionMember0(BaseModel): + """A Predefined AI prompt classification topic entry.""" + topic_type: Literal["Intent", "Content"] type: Literal["PromptTopic"] description: Optional[str] = None + """ + A customer-facing explanation of what this predefined AI prompt topic + represents. + """ + + +class PredefinedProfileEntryPredefinedEntryVariantUnionMember1(BaseModel): + """A general predefined entry.""" + + type: Literal["General"] + + description: Optional[str] = None + """A customer-facing explanation of what this predefined entry represents.""" + + +PredefinedProfileEntryPredefinedEntryVariant: TypeAlias = Union[ + PredefinedProfileEntryPredefinedEntryVariantUnionMember0, PredefinedProfileEntryPredefinedEntryVariantUnionMember1 +] class PredefinedProfileEntryPredefinedEntry(BaseModel): @@ -445,6 +518,7 @@ class PredefinedProfileEntryPredefinedEntry(BaseModel): profile_id: Optional[str] = None variant: Optional[PredefinedProfileEntryPredefinedEntryVariant] = None + """A Predefined AI prompt classification topic entry.""" class PredefinedProfileEntryIntegrationEntry(BaseModel): @@ -587,12 +661,32 @@ class IntegrationProfileEntryPredefinedEntryConfidence(BaseModel): """ -class IntegrationProfileEntryPredefinedEntryVariant(BaseModel): +class IntegrationProfileEntryPredefinedEntryVariantUnionMember0(BaseModel): + """A Predefined AI prompt classification topic entry.""" + topic_type: Literal["Intent", "Content"] type: Literal["PromptTopic"] description: Optional[str] = None + """ + A customer-facing explanation of what this predefined AI prompt topic + represents. + """ + + +class IntegrationProfileEntryPredefinedEntryVariantUnionMember1(BaseModel): + """A general predefined entry.""" + + type: Literal["General"] + + description: Optional[str] = None + """A customer-facing explanation of what this predefined entry represents.""" + + +IntegrationProfileEntryPredefinedEntryVariant: TypeAlias = Union[ + IntegrationProfileEntryPredefinedEntryVariantUnionMember0, IntegrationProfileEntryPredefinedEntryVariantUnionMember1 +] class IntegrationProfileEntryPredefinedEntry(BaseModel): @@ -609,6 +703,7 @@ class IntegrationProfileEntryPredefinedEntry(BaseModel): profile_id: Optional[str] = None variant: Optional[IntegrationProfileEntryPredefinedEntryVariant] = None + """A Predefined AI prompt classification topic entry.""" class IntegrationProfileEntryIntegrationEntry(BaseModel): @@ -722,12 +817,33 @@ class IntegrationProfileSharedEntryPredefinedEntryConfidence(BaseModel): """ -class IntegrationProfileSharedEntryPredefinedEntryVariant(BaseModel): +class IntegrationProfileSharedEntryPredefinedEntryVariantUnionMember0(BaseModel): + """A Predefined AI prompt classification topic entry.""" + topic_type: Literal["Intent", "Content"] type: Literal["PromptTopic"] description: Optional[str] = None + """ + A customer-facing explanation of what this predefined AI prompt topic + represents. + """ + + +class IntegrationProfileSharedEntryPredefinedEntryVariantUnionMember1(BaseModel): + """A general predefined entry.""" + + type: Literal["General"] + + description: Optional[str] = None + """A customer-facing explanation of what this predefined entry represents.""" + + +IntegrationProfileSharedEntryPredefinedEntryVariant: TypeAlias = Union[ + IntegrationProfileSharedEntryPredefinedEntryVariantUnionMember0, + IntegrationProfileSharedEntryPredefinedEntryVariantUnionMember1, +] class IntegrationProfileSharedEntryPredefinedEntry(BaseModel): @@ -744,6 +860,7 @@ class IntegrationProfileSharedEntryPredefinedEntry(BaseModel): profile_id: Optional[str] = None variant: Optional[IntegrationProfileSharedEntryPredefinedEntryVariant] = None + """A Predefined AI prompt classification topic entry.""" class IntegrationProfileSharedEntryIntegrationEntry(BaseModel): diff --git a/src/cloudflare/types/zero_trust/dlp/profiles/predefined_profile.py b/src/cloudflare/types/zero_trust/dlp/profiles/predefined_profile.py index b3c97b85ffc..234339358d1 100644 --- a/src/cloudflare/types/zero_trust/dlp/profiles/predefined_profile.py +++ b/src/cloudflare/types/zero_trust/dlp/profiles/predefined_profile.py @@ -14,6 +14,8 @@ "EntryPredefinedEntry", "EntryPredefinedEntryConfidence", "EntryPredefinedEntryVariant", + "EntryPredefinedEntryVariantUnionMember0", + "EntryPredefinedEntryVariantUnionMember1", "EntryIntegrationEntry", "EntryExactDataEntry", "EntryDocumentFingerprintEntry", @@ -52,12 +54,32 @@ class EntryPredefinedEntryConfidence(BaseModel): """ -class EntryPredefinedEntryVariant(BaseModel): +class EntryPredefinedEntryVariantUnionMember0(BaseModel): + """A Predefined AI prompt classification topic entry.""" + topic_type: Literal["Intent", "Content"] type: Literal["PromptTopic"] description: Optional[str] = None + """ + A customer-facing explanation of what this predefined AI prompt topic + represents. + """ + + +class EntryPredefinedEntryVariantUnionMember1(BaseModel): + """A general predefined entry.""" + + type: Literal["General"] + + description: Optional[str] = None + """A customer-facing explanation of what this predefined entry represents.""" + + +EntryPredefinedEntryVariant: TypeAlias = Union[ + EntryPredefinedEntryVariantUnionMember0, EntryPredefinedEntryVariantUnionMember1 +] class EntryPredefinedEntry(BaseModel): @@ -74,6 +96,7 @@ class EntryPredefinedEntry(BaseModel): profile_id: Optional[str] = None variant: Optional[EntryPredefinedEntryVariant] = None + """A Predefined AI prompt classification topic entry.""" class EntryIntegrationEntry(BaseModel): From 94536a08bc5c4e37328eafd96f2b5d4c6852dd8d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 29 Apr 2026 22:22:56 +0000 Subject: [PATCH 16/45] feat: chore: skip failing tests for email_security.settings and workers.observability.telemetry * chore: skip failing tests for email_security.settings and workers.observability.telemetry - email_security.settings.allow_policies.edit: HTTP 422 from prism - email_security.settings.block_senders.edit: HTTP 422 from prism - email_security.settings.impersonation_registry.edit: HTTP 422 from prism - email_security.settings.trusted_domains.edit: HTTP 422 from prism - workers.observability.telemetry.keys: HTTP 400 from prism - workers.observability.telemetry.query: HTTP 400 from prism - workers.observability.telemetry.values: HTTP 400 from prism Failures observed in CI run 25132870851 on cloudflare-typescript PR #2743. --- .stats.yml | 2 +- .../settings/test_allow_policies.py | 10 + .../settings/test_block_senders.py | 10 + .../settings/test_impersonation_registry.py | 10 + .../settings/test_trusted_domains.py | 10 + .../workers/observability/test_telemetry.py | 38 +- uv.lock | 1236 +++++++++++++++++ 7 files changed, 1307 insertions(+), 9 deletions(-) create mode 100644 uv.lock diff --git a/.stats.yml b/.stats.yml index f1bb0e04443..11365b78b41 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 2195 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a6c352830d1270d0abb5bb983058ea21815e1bb7d2e163965335dcb0e706f057.yml openapi_spec_hash: ffe469d5b0b3f29c20ccb91c0a2862e7 -config_hash: 21f60bdd0f0b7d52ffabed72d0fd2020 +config_hash: a83bae9f0be0219cfe77d38d5af60d4a diff --git a/tests/api_resources/email_security/settings/test_allow_policies.py b/tests/api_resources/email_security/settings/test_allow_policies.py index 7ddd322bd03..e6da1ccfdae 100644 --- a/tests/api_resources/email_security/settings/test_allow_policies.py +++ b/tests/api_resources/email_security/settings/test_allow_policies.py @@ -212,6 +212,7 @@ def test_path_params_delete(self, client: Cloudflare) -> None: account_id="023e105f4ecef8ad9ca31a8372d0c353", ) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize def test_method_edit(self, client: Cloudflare) -> None: allow_policy = client.email_security.settings.allow_policies.edit( @@ -220,6 +221,7 @@ def test_method_edit(self, client: Cloudflare) -> None: ) assert_matches_type(Optional[AllowPolicyEditResponse], allow_policy, path=["response"]) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize def test_method_edit_with_all_params(self, client: Cloudflare) -> None: allow_policy = client.email_security.settings.allow_policies.edit( @@ -239,6 +241,7 @@ def test_method_edit_with_all_params(self, client: Cloudflare) -> None: ) assert_matches_type(Optional[AllowPolicyEditResponse], allow_policy, path=["response"]) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize def test_raw_response_edit(self, client: Cloudflare) -> None: response = client.email_security.settings.allow_policies.with_raw_response.edit( @@ -251,6 +254,7 @@ def test_raw_response_edit(self, client: Cloudflare) -> None: allow_policy = response.parse() assert_matches_type(Optional[AllowPolicyEditResponse], allow_policy, path=["response"]) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize def test_streaming_response_edit(self, client: Cloudflare) -> None: with client.email_security.settings.allow_policies.with_streaming_response.edit( @@ -265,6 +269,7 @@ def test_streaming_response_edit(self, client: Cloudflare) -> None: assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize def test_path_params_edit(self, client: Cloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): @@ -521,6 +526,7 @@ async def test_path_params_delete(self, async_client: AsyncCloudflare) -> None: account_id="023e105f4ecef8ad9ca31a8372d0c353", ) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize async def test_method_edit(self, async_client: AsyncCloudflare) -> None: allow_policy = await async_client.email_security.settings.allow_policies.edit( @@ -529,6 +535,7 @@ async def test_method_edit(self, async_client: AsyncCloudflare) -> None: ) assert_matches_type(Optional[AllowPolicyEditResponse], allow_policy, path=["response"]) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize async def test_method_edit_with_all_params(self, async_client: AsyncCloudflare) -> None: allow_policy = await async_client.email_security.settings.allow_policies.edit( @@ -548,6 +555,7 @@ async def test_method_edit_with_all_params(self, async_client: AsyncCloudflare) ) assert_matches_type(Optional[AllowPolicyEditResponse], allow_policy, path=["response"]) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize async def test_raw_response_edit(self, async_client: AsyncCloudflare) -> None: response = await async_client.email_security.settings.allow_policies.with_raw_response.edit( @@ -560,6 +568,7 @@ async def test_raw_response_edit(self, async_client: AsyncCloudflare) -> None: allow_policy = await response.parse() assert_matches_type(Optional[AllowPolicyEditResponse], allow_policy, path=["response"]) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize async def test_streaming_response_edit(self, async_client: AsyncCloudflare) -> None: async with async_client.email_security.settings.allow_policies.with_streaming_response.edit( @@ -574,6 +583,7 @@ async def test_streaming_response_edit(self, async_client: AsyncCloudflare) -> N assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize async def test_path_params_edit(self, async_client: AsyncCloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): diff --git a/tests/api_resources/email_security/settings/test_block_senders.py b/tests/api_resources/email_security/settings/test_block_senders.py index aa4176eef0b..4be3b0b5cd8 100644 --- a/tests/api_resources/email_security/settings/test_block_senders.py +++ b/tests/api_resources/email_security/settings/test_block_senders.py @@ -185,6 +185,7 @@ def test_path_params_delete(self, client: Cloudflare) -> None: account_id="023e105f4ecef8ad9ca31a8372d0c353", ) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize def test_method_edit(self, client: Cloudflare) -> None: block_sender = client.email_security.settings.block_senders.edit( @@ -193,6 +194,7 @@ def test_method_edit(self, client: Cloudflare) -> None: ) assert_matches_type(Optional[BlockSenderEditResponse], block_sender, path=["response"]) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize def test_method_edit_with_all_params(self, client: Cloudflare) -> None: block_sender = client.email_security.settings.block_senders.edit( @@ -205,6 +207,7 @@ def test_method_edit_with_all_params(self, client: Cloudflare) -> None: ) assert_matches_type(Optional[BlockSenderEditResponse], block_sender, path=["response"]) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize def test_raw_response_edit(self, client: Cloudflare) -> None: response = client.email_security.settings.block_senders.with_raw_response.edit( @@ -217,6 +220,7 @@ def test_raw_response_edit(self, client: Cloudflare) -> None: block_sender = response.parse() assert_matches_type(Optional[BlockSenderEditResponse], block_sender, path=["response"]) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize def test_streaming_response_edit(self, client: Cloudflare) -> None: with client.email_security.settings.block_senders.with_streaming_response.edit( @@ -231,6 +235,7 @@ def test_streaming_response_edit(self, client: Cloudflare) -> None: assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize def test_path_params_edit(self, client: Cloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): @@ -460,6 +465,7 @@ async def test_path_params_delete(self, async_client: AsyncCloudflare) -> None: account_id="023e105f4ecef8ad9ca31a8372d0c353", ) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize async def test_method_edit(self, async_client: AsyncCloudflare) -> None: block_sender = await async_client.email_security.settings.block_senders.edit( @@ -468,6 +474,7 @@ async def test_method_edit(self, async_client: AsyncCloudflare) -> None: ) assert_matches_type(Optional[BlockSenderEditResponse], block_sender, path=["response"]) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize async def test_method_edit_with_all_params(self, async_client: AsyncCloudflare) -> None: block_sender = await async_client.email_security.settings.block_senders.edit( @@ -480,6 +487,7 @@ async def test_method_edit_with_all_params(self, async_client: AsyncCloudflare) ) assert_matches_type(Optional[BlockSenderEditResponse], block_sender, path=["response"]) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize async def test_raw_response_edit(self, async_client: AsyncCloudflare) -> None: response = await async_client.email_security.settings.block_senders.with_raw_response.edit( @@ -492,6 +500,7 @@ async def test_raw_response_edit(self, async_client: AsyncCloudflare) -> None: block_sender = await response.parse() assert_matches_type(Optional[BlockSenderEditResponse], block_sender, path=["response"]) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize async def test_streaming_response_edit(self, async_client: AsyncCloudflare) -> None: async with async_client.email_security.settings.block_senders.with_streaming_response.edit( @@ -506,6 +515,7 @@ async def test_streaming_response_edit(self, async_client: AsyncCloudflare) -> N assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize async def test_path_params_edit(self, async_client: AsyncCloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): diff --git a/tests/api_resources/email_security/settings/test_impersonation_registry.py b/tests/api_resources/email_security/settings/test_impersonation_registry.py index ebf6398be74..ae9f0fada97 100644 --- a/tests/api_resources/email_security/settings/test_impersonation_registry.py +++ b/tests/api_resources/email_security/settings/test_impersonation_registry.py @@ -202,6 +202,7 @@ def test_path_params_delete(self, client: Cloudflare) -> None: account_id="023e105f4ecef8ad9ca31a8372d0c353", ) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize def test_method_edit(self, client: Cloudflare) -> None: impersonation_registry = client.email_security.settings.impersonation_registry.edit( @@ -210,6 +211,7 @@ def test_method_edit(self, client: Cloudflare) -> None: ) assert_matches_type(Optional[ImpersonationRegistryEditResponse], impersonation_registry, path=["response"]) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize def test_method_edit_with_all_params(self, client: Cloudflare) -> None: impersonation_registry = client.email_security.settings.impersonation_registry.edit( @@ -226,6 +228,7 @@ def test_method_edit_with_all_params(self, client: Cloudflare) -> None: ) assert_matches_type(Optional[ImpersonationRegistryEditResponse], impersonation_registry, path=["response"]) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize def test_raw_response_edit(self, client: Cloudflare) -> None: response = client.email_security.settings.impersonation_registry.with_raw_response.edit( @@ -238,6 +241,7 @@ def test_raw_response_edit(self, client: Cloudflare) -> None: impersonation_registry = response.parse() assert_matches_type(Optional[ImpersonationRegistryEditResponse], impersonation_registry, path=["response"]) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize def test_streaming_response_edit(self, client: Cloudflare) -> None: with client.email_security.settings.impersonation_registry.with_streaming_response.edit( @@ -252,6 +256,7 @@ def test_streaming_response_edit(self, client: Cloudflare) -> None: assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize def test_path_params_edit(self, client: Cloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): @@ -502,6 +507,7 @@ async def test_path_params_delete(self, async_client: AsyncCloudflare) -> None: account_id="023e105f4ecef8ad9ca31a8372d0c353", ) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize async def test_method_edit(self, async_client: AsyncCloudflare) -> None: impersonation_registry = await async_client.email_security.settings.impersonation_registry.edit( @@ -510,6 +516,7 @@ async def test_method_edit(self, async_client: AsyncCloudflare) -> None: ) assert_matches_type(Optional[ImpersonationRegistryEditResponse], impersonation_registry, path=["response"]) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize async def test_method_edit_with_all_params(self, async_client: AsyncCloudflare) -> None: impersonation_registry = await async_client.email_security.settings.impersonation_registry.edit( @@ -526,6 +533,7 @@ async def test_method_edit_with_all_params(self, async_client: AsyncCloudflare) ) assert_matches_type(Optional[ImpersonationRegistryEditResponse], impersonation_registry, path=["response"]) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize async def test_raw_response_edit(self, async_client: AsyncCloudflare) -> None: response = await async_client.email_security.settings.impersonation_registry.with_raw_response.edit( @@ -538,6 +546,7 @@ async def test_raw_response_edit(self, async_client: AsyncCloudflare) -> None: impersonation_registry = await response.parse() assert_matches_type(Optional[ImpersonationRegistryEditResponse], impersonation_registry, path=["response"]) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize async def test_streaming_response_edit(self, async_client: AsyncCloudflare) -> None: async with async_client.email_security.settings.impersonation_registry.with_streaming_response.edit( @@ -552,6 +561,7 @@ async def test_streaming_response_edit(self, async_client: AsyncCloudflare) -> N assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize async def test_path_params_edit(self, async_client: AsyncCloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): diff --git a/tests/api_resources/email_security/settings/test_trusted_domains.py b/tests/api_resources/email_security/settings/test_trusted_domains.py index 9fef76ec686..c7bc53875a7 100644 --- a/tests/api_resources/email_security/settings/test_trusted_domains.py +++ b/tests/api_resources/email_security/settings/test_trusted_domains.py @@ -196,6 +196,7 @@ def test_path_params_delete(self, client: Cloudflare) -> None: account_id="023e105f4ecef8ad9ca31a8372d0c353", ) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize def test_method_edit(self, client: Cloudflare) -> None: trusted_domain = client.email_security.settings.trusted_domains.edit( @@ -204,6 +205,7 @@ def test_method_edit(self, client: Cloudflare) -> None: ) assert_matches_type(Optional[TrustedDomainEditResponse], trusted_domain, path=["response"]) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize def test_method_edit_with_all_params(self, client: Cloudflare) -> None: trusted_domain = client.email_security.settings.trusted_domains.edit( @@ -217,6 +219,7 @@ def test_method_edit_with_all_params(self, client: Cloudflare) -> None: ) assert_matches_type(Optional[TrustedDomainEditResponse], trusted_domain, path=["response"]) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize def test_raw_response_edit(self, client: Cloudflare) -> None: response = client.email_security.settings.trusted_domains.with_raw_response.edit( @@ -229,6 +232,7 @@ def test_raw_response_edit(self, client: Cloudflare) -> None: trusted_domain = response.parse() assert_matches_type(Optional[TrustedDomainEditResponse], trusted_domain, path=["response"]) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize def test_streaming_response_edit(self, client: Cloudflare) -> None: with client.email_security.settings.trusted_domains.with_streaming_response.edit( @@ -243,6 +247,7 @@ def test_streaming_response_edit(self, client: Cloudflare) -> None: assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize def test_path_params_edit(self, client: Cloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): @@ -485,6 +490,7 @@ async def test_path_params_delete(self, async_client: AsyncCloudflare) -> None: account_id="023e105f4ecef8ad9ca31a8372d0c353", ) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize async def test_method_edit(self, async_client: AsyncCloudflare) -> None: trusted_domain = await async_client.email_security.settings.trusted_domains.edit( @@ -493,6 +499,7 @@ async def test_method_edit(self, async_client: AsyncCloudflare) -> None: ) assert_matches_type(Optional[TrustedDomainEditResponse], trusted_domain, path=["response"]) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize async def test_method_edit_with_all_params(self, async_client: AsyncCloudflare) -> None: trusted_domain = await async_client.email_security.settings.trusted_domains.edit( @@ -506,6 +513,7 @@ async def test_method_edit_with_all_params(self, async_client: AsyncCloudflare) ) assert_matches_type(Optional[TrustedDomainEditResponse], trusted_domain, path=["response"]) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize async def test_raw_response_edit(self, async_client: AsyncCloudflare) -> None: response = await async_client.email_security.settings.trusted_domains.with_raw_response.edit( @@ -518,6 +526,7 @@ async def test_raw_response_edit(self, async_client: AsyncCloudflare) -> None: trusted_domain = await response.parse() assert_matches_type(Optional[TrustedDomainEditResponse], trusted_domain, path=["response"]) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize async def test_streaming_response_edit(self, async_client: AsyncCloudflare) -> None: async with async_client.email_security.settings.trusted_domains.with_streaming_response.edit( @@ -532,6 +541,7 @@ async def test_streaming_response_edit(self, async_client: AsyncCloudflare) -> N assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize async def test_path_params_edit(self, async_client: AsyncCloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): diff --git a/tests/api_resources/workers/observability/test_telemetry.py b/tests/api_resources/workers/observability/test_telemetry.py index f90311d998a..3d5d7594ef2 100644 --- a/tests/api_resources/workers/observability/test_telemetry.py +++ b/tests/api_resources/workers/observability/test_telemetry.py @@ -22,6 +22,7 @@ class TestTelemetry: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize def test_method_keys(self, client: Cloudflare) -> None: telemetry = client.workers.observability.telemetry.keys( @@ -29,6 +30,7 @@ def test_method_keys(self, client: Cloudflare) -> None: ) assert_matches_type(SyncSinglePage[TelemetryKeysResponse], telemetry, path=["response"]) + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize def test_method_keys_with_all_params(self, client: Cloudflare) -> None: telemetry = client.workers.observability.telemetry.keys( @@ -63,6 +65,7 @@ def test_method_keys_with_all_params(self, client: Cloudflare) -> None: ) assert_matches_type(SyncSinglePage[TelemetryKeysResponse], telemetry, path=["response"]) + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize def test_raw_response_keys(self, client: Cloudflare) -> None: response = client.workers.observability.telemetry.with_raw_response.keys( @@ -74,6 +77,7 @@ def test_raw_response_keys(self, client: Cloudflare) -> None: telemetry = response.parse() assert_matches_type(SyncSinglePage[TelemetryKeysResponse], telemetry, path=["response"]) + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize def test_streaming_response_keys(self, client: Cloudflare) -> None: with client.workers.observability.telemetry.with_streaming_response.keys( @@ -87,6 +91,7 @@ def test_streaming_response_keys(self, client: Cloudflare) -> None: assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize def test_path_params_keys(self, client: Cloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): @@ -94,7 +99,7 @@ def test_path_params_keys(self, client: Cloudflare) -> None: account_id="", ) - @pytest.mark.skip(reason="RunQueryParametersNeedleValue modeled as empty BaseModel, cannot deserialize string from Prism") + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize def test_method_query(self, client: Cloudflare) -> None: telemetry = client.workers.observability.telemetry.query( @@ -107,7 +112,7 @@ def test_method_query(self, client: Cloudflare) -> None: ) assert_matches_type(TelemetryQueryResponse, telemetry, path=["response"]) - @pytest.mark.skip(reason="RunQueryParametersNeedleValue modeled as empty BaseModel, cannot deserialize string from Prism") + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize def test_method_query_with_all_params(self, client: Cloudflare) -> None: telemetry = client.workers.observability.telemetry.query( @@ -178,7 +183,7 @@ def test_method_query_with_all_params(self, client: Cloudflare) -> None: ) assert_matches_type(TelemetryQueryResponse, telemetry, path=["response"]) - @pytest.mark.skip(reason="RunQueryParametersNeedleValue modeled as empty BaseModel, cannot deserialize string from Prism") + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize def test_raw_response_query(self, client: Cloudflare) -> None: response = client.workers.observability.telemetry.with_raw_response.query( @@ -195,7 +200,7 @@ def test_raw_response_query(self, client: Cloudflare) -> None: telemetry = response.parse() assert_matches_type(TelemetryQueryResponse, telemetry, path=["response"]) - @pytest.mark.skip(reason="RunQueryParametersNeedleValue modeled as empty BaseModel, cannot deserialize string from Prism") + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize def test_streaming_response_query(self, client: Cloudflare) -> None: with client.workers.observability.telemetry.with_streaming_response.query( @@ -214,6 +219,7 @@ def test_streaming_response_query(self, client: Cloudflare) -> None: assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize def test_path_params_query(self, client: Cloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): @@ -226,6 +232,7 @@ def test_path_params_query(self, client: Cloudflare) -> None: }, ) + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize def test_method_values(self, client: Cloudflare) -> None: telemetry = client.workers.observability.telemetry.values( @@ -240,6 +247,7 @@ def test_method_values(self, client: Cloudflare) -> None: ) assert_matches_type(SyncSinglePage[TelemetryValuesResponse], telemetry, path=["response"]) + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize def test_method_values_with_all_params(self, client: Cloudflare) -> None: telemetry = client.workers.observability.telemetry.values( @@ -273,6 +281,7 @@ def test_method_values_with_all_params(self, client: Cloudflare) -> None: ) assert_matches_type(SyncSinglePage[TelemetryValuesResponse], telemetry, path=["response"]) + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize def test_raw_response_values(self, client: Cloudflare) -> None: response = client.workers.observability.telemetry.with_raw_response.values( @@ -291,6 +300,7 @@ def test_raw_response_values(self, client: Cloudflare) -> None: telemetry = response.parse() assert_matches_type(SyncSinglePage[TelemetryValuesResponse], telemetry, path=["response"]) + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize def test_streaming_response_values(self, client: Cloudflare) -> None: with client.workers.observability.telemetry.with_streaming_response.values( @@ -311,6 +321,7 @@ def test_streaming_response_values(self, client: Cloudflare) -> None: assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize def test_path_params_values(self, client: Cloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): @@ -331,6 +342,7 @@ class TestAsyncTelemetry: "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] ) + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize async def test_method_keys(self, async_client: AsyncCloudflare) -> None: telemetry = await async_client.workers.observability.telemetry.keys( @@ -338,6 +350,7 @@ async def test_method_keys(self, async_client: AsyncCloudflare) -> None: ) assert_matches_type(AsyncSinglePage[TelemetryKeysResponse], telemetry, path=["response"]) + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize async def test_method_keys_with_all_params(self, async_client: AsyncCloudflare) -> None: telemetry = await async_client.workers.observability.telemetry.keys( @@ -372,6 +385,7 @@ async def test_method_keys_with_all_params(self, async_client: AsyncCloudflare) ) assert_matches_type(AsyncSinglePage[TelemetryKeysResponse], telemetry, path=["response"]) + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize async def test_raw_response_keys(self, async_client: AsyncCloudflare) -> None: response = await async_client.workers.observability.telemetry.with_raw_response.keys( @@ -383,6 +397,7 @@ async def test_raw_response_keys(self, async_client: AsyncCloudflare) -> None: telemetry = await response.parse() assert_matches_type(AsyncSinglePage[TelemetryKeysResponse], telemetry, path=["response"]) + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize async def test_streaming_response_keys(self, async_client: AsyncCloudflare) -> None: async with async_client.workers.observability.telemetry.with_streaming_response.keys( @@ -396,6 +411,7 @@ async def test_streaming_response_keys(self, async_client: AsyncCloudflare) -> N assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize async def test_path_params_keys(self, async_client: AsyncCloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): @@ -403,7 +419,7 @@ async def test_path_params_keys(self, async_client: AsyncCloudflare) -> None: account_id="", ) - @pytest.mark.skip(reason="RunQueryParametersNeedleValue modeled as empty BaseModel, cannot deserialize string from Prism") + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize async def test_method_query(self, async_client: AsyncCloudflare) -> None: telemetry = await async_client.workers.observability.telemetry.query( @@ -416,7 +432,7 @@ async def test_method_query(self, async_client: AsyncCloudflare) -> None: ) assert_matches_type(TelemetryQueryResponse, telemetry, path=["response"]) - @pytest.mark.skip(reason="RunQueryParametersNeedleValue modeled as empty BaseModel, cannot deserialize string from Prism") + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize async def test_method_query_with_all_params(self, async_client: AsyncCloudflare) -> None: telemetry = await async_client.workers.observability.telemetry.query( @@ -487,7 +503,7 @@ async def test_method_query_with_all_params(self, async_client: AsyncCloudflare) ) assert_matches_type(TelemetryQueryResponse, telemetry, path=["response"]) - @pytest.mark.skip(reason="RunQueryParametersNeedleValue modeled as empty BaseModel, cannot deserialize string from Prism") + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize async def test_raw_response_query(self, async_client: AsyncCloudflare) -> None: response = await async_client.workers.observability.telemetry.with_raw_response.query( @@ -504,7 +520,7 @@ async def test_raw_response_query(self, async_client: AsyncCloudflare) -> None: telemetry = await response.parse() assert_matches_type(TelemetryQueryResponse, telemetry, path=["response"]) - @pytest.mark.skip(reason="RunQueryParametersNeedleValue modeled as empty BaseModel, cannot deserialize string from Prism") + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize async def test_streaming_response_query(self, async_client: AsyncCloudflare) -> None: async with async_client.workers.observability.telemetry.with_streaming_response.query( @@ -523,6 +539,7 @@ async def test_streaming_response_query(self, async_client: AsyncCloudflare) -> assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize async def test_path_params_query(self, async_client: AsyncCloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): @@ -535,6 +552,7 @@ async def test_path_params_query(self, async_client: AsyncCloudflare) -> None: }, ) + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize async def test_method_values(self, async_client: AsyncCloudflare) -> None: telemetry = await async_client.workers.observability.telemetry.values( @@ -549,6 +567,7 @@ async def test_method_values(self, async_client: AsyncCloudflare) -> None: ) assert_matches_type(AsyncSinglePage[TelemetryValuesResponse], telemetry, path=["response"]) + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize async def test_method_values_with_all_params(self, async_client: AsyncCloudflare) -> None: telemetry = await async_client.workers.observability.telemetry.values( @@ -582,6 +601,7 @@ async def test_method_values_with_all_params(self, async_client: AsyncCloudflare ) assert_matches_type(AsyncSinglePage[TelemetryValuesResponse], telemetry, path=["response"]) + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize async def test_raw_response_values(self, async_client: AsyncCloudflare) -> None: response = await async_client.workers.observability.telemetry.with_raw_response.values( @@ -600,6 +620,7 @@ async def test_raw_response_values(self, async_client: AsyncCloudflare) -> None: telemetry = await response.parse() assert_matches_type(AsyncSinglePage[TelemetryValuesResponse], telemetry, path=["response"]) + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize async def test_streaming_response_values(self, async_client: AsyncCloudflare) -> None: async with async_client.workers.observability.telemetry.with_streaming_response.values( @@ -620,6 +641,7 @@ async def test_streaming_response_values(self, async_client: AsyncCloudflare) -> assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="HTTP 400 error from prism") @parametrize async def test_path_params_values(self, async_client: AsyncCloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): diff --git a/uv.lock b/uv.lock new file mode 100644 index 00000000000..7bd68eabf41 --- /dev/null +++ b/uv.lock @@ -0,0 +1,1236 @@ +version = 1 +revision = 3 +requires-python = ">=3.9" +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version < '3.10'", +] + +[[package]] +name = "aiohappyeyeballs" +version = "2.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" }, +] + +[[package]] +name = "aiohttp" +version = "3.13.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohappyeyeballs" }, + { name = "aiosignal" }, + { name = "async-timeout", marker = "python_full_version < '3.11'" }, + { name = "attrs" }, + { name = "frozenlist" }, + { name = "multidict" }, + { name = "propcache" }, + { name = "yarl", version = "1.22.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "yarl", version = "1.23.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/77/9a/152096d4808df8e4268befa55fba462f440f14beab85e8ad9bf990516918/aiohttp-3.13.5.tar.gz", hash = "sha256:9d98cc980ecc96be6eb4c1994ce35d28d8b1f5e5208a23b421187d1209dbb7d1", size = 7858271, upload-time = "2026-03-31T22:01:03.343Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bd/85/cebc47ee74d8b408749073a1a46c6fcba13d170dc8af7e61996c6c9394ac/aiohttp-3.13.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:02222e7e233295f40e011c1b00e3b0bd451f22cf853a0304c3595633ee47da4b", size = 750547, upload-time = "2026-03-31T21:56:30.024Z" }, + { url = "https://files.pythonhosted.org/packages/05/98/afd308e35b9d3d8c9ec54c0918f1d722c86dc17ddfec272fcdbcce5a3124/aiohttp-3.13.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bace460460ed20614fa6bc8cb09966c0b8517b8c58ad8046828c6078d25333b5", size = 503535, upload-time = "2026-03-31T21:56:31.935Z" }, + { url = "https://files.pythonhosted.org/packages/6f/4d/926c183e06b09d5270a309eb50fbde7b09782bfd305dec1e800f329834fb/aiohttp-3.13.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f546a4dc1e6a5edbb9fd1fd6ad18134550e096a5a43f4ad74acfbd834fc6670", size = 497830, upload-time = "2026-03-31T21:56:33.654Z" }, + { url = "https://files.pythonhosted.org/packages/e4/d6/f47d1c690f115a5c2a5e8938cce4a232a5be9aac5c5fb2647efcbbbda333/aiohttp-3.13.5-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c86969d012e51b8e415a8c6ce96f7857d6a87d6207303ab02d5d11ef0cad2274", size = 1682474, upload-time = "2026-03-31T21:56:35.513Z" }, + { url = "https://files.pythonhosted.org/packages/01/44/056fd37b1bb52eac760303e5196acc74d9d546631b035704ae5927f7b4ac/aiohttp-3.13.5-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b6f6cd1560c5fa427e3b6074bb24d2c64e225afbb7165008903bd42e4e33e28a", size = 1655259, upload-time = "2026-03-31T21:56:37.843Z" }, + { url = "https://files.pythonhosted.org/packages/91/9f/78eb1a20c1c28ae02f6a3c0f4d7b0dcc66abce5290cadd53d78ce3084175/aiohttp-3.13.5-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:636bc362f0c5bbc7372bc3ae49737f9e3030dbce469f0f422c8f38079780363d", size = 1736204, upload-time = "2026-03-31T21:56:39.822Z" }, + { url = "https://files.pythonhosted.org/packages/de/6c/d20d7de23f0b52b8c1d9e2033b2db1ac4dacbb470bb74c56de0f5f86bb4f/aiohttp-3.13.5-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6a7cbeb06d1070f1d14895eeeed4dac5913b22d7b456f2eb969f11f4b3993796", size = 1826198, upload-time = "2026-03-31T21:56:41.378Z" }, + { url = "https://files.pythonhosted.org/packages/2f/86/a6f3ff1fd795f49545a7c74b2c92f62729135d73e7e4055bf74da5a26c82/aiohttp-3.13.5-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bca9ef7517fd7874a1a08970ae88f497bf5c984610caa0bf40bd7e8450852b95", size = 1681329, upload-time = "2026-03-31T21:56:43.374Z" }, + { url = "https://files.pythonhosted.org/packages/fb/68/84cd3dab6b7b4f3e6fe9459a961acb142aaab846417f6e8905110d7027e5/aiohttp-3.13.5-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:019a67772e034a0e6b9b17c13d0a8fe56ad9fb150fc724b7f3ffd3724288d9e5", size = 1560023, upload-time = "2026-03-31T21:56:45.031Z" }, + { url = "https://files.pythonhosted.org/packages/41/2c/db61b64b0249e30f954a65ab4cb4970ced57544b1de2e3c98ee5dc24165f/aiohttp-3.13.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f34ecee82858e41dd217734f0c41a532bd066bcaab636ad830f03a30b2a96f2a", size = 1652372, upload-time = "2026-03-31T21:56:47.075Z" }, + { url = "https://files.pythonhosted.org/packages/25/6f/e96988a6c982d047810c772e28c43c64c300c943b0ed5c1c0c4ce1e1027c/aiohttp-3.13.5-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:4eac02d9af4813ee289cd63a361576da36dba57f5a1ab36377bc2600db0cbb73", size = 1662031, upload-time = "2026-03-31T21:56:48.835Z" }, + { url = "https://files.pythonhosted.org/packages/b7/26/a56feace81f3d347b4052403a9d03754a0ab23f7940780dada0849a38c92/aiohttp-3.13.5-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4beac52e9fe46d6abf98b0176a88154b742e878fdf209d2248e99fcdf73cd297", size = 1708118, upload-time = "2026-03-31T21:56:50.833Z" }, + { url = "https://files.pythonhosted.org/packages/78/6e/b6173a8ff03d01d5e1a694bc06764b5dad1df2d4ed8f0ceec12bb3277936/aiohttp-3.13.5-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:c180f480207a9b2475f2b8d8bd7204e47aec952d084b2a2be58a782ffcf96074", size = 1548667, upload-time = "2026-03-31T21:56:52.81Z" }, + { url = "https://files.pythonhosted.org/packages/16/13/13296ffe2c132d888b3fe2c195c8b9c0c24c89c3fa5cc2c44464dc23b22e/aiohttp-3.13.5-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2837fb92951564d6339cedae4a7231692aa9f73cbc4fb2e04263b96844e03b4e", size = 1724490, upload-time = "2026-03-31T21:56:54.541Z" }, + { url = "https://files.pythonhosted.org/packages/7a/b4/1f1c287f4a79782ef36e5a6e62954c85343bc30470d862d30bd5f26c9fa2/aiohttp-3.13.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d9010032a0b9710f58012a1e9c222528763d860ba2ee1422c03473eab47703e7", size = 1667109, upload-time = "2026-03-31T21:56:56.21Z" }, + { url = "https://files.pythonhosted.org/packages/ef/42/8461a2aaf60a8f4ea4549a4056be36b904b0eb03d97ca9a8a2604681a500/aiohttp-3.13.5-cp310-cp310-win32.whl", hash = "sha256:7c4b6668b2b2b9027f209ddf647f2a4407784b5d88b8be4efcc72036f365baf9", size = 439478, upload-time = "2026-03-31T21:56:58.292Z" }, + { url = "https://files.pythonhosted.org/packages/e5/71/06956304cb5ee439dfe8d86e1b2e70088bd88ed1ced1f42fb29e5d855f0e/aiohttp-3.13.5-cp310-cp310-win_amd64.whl", hash = "sha256:cd3db5927bf9167d5a6157ddb2f036f6b6b0ad001ac82355d43e97a4bde76d76", size = 462047, upload-time = "2026-03-31T21:57:00.257Z" }, + { url = "https://files.pythonhosted.org/packages/d6/f5/a20c4ac64aeaef1679e25c9983573618ff765d7aa829fa2b84ae7573169e/aiohttp-3.13.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7ab7229b6f9b5c1ba4910d6c41a9eb11f543eadb3f384df1b4c293f4e73d44d6", size = 757513, upload-time = "2026-03-31T21:57:02.146Z" }, + { url = "https://files.pythonhosted.org/packages/75/0a/39fa6c6b179b53fcb3e4b3d2b6d6cad0180854eda17060c7218540102bef/aiohttp-3.13.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8f14c50708bb156b3a3ca7230b3d820199d56a48e3af76fa21c2d6087190fe3d", size = 506748, upload-time = "2026-03-31T21:57:04.275Z" }, + { url = "https://files.pythonhosted.org/packages/87/ec/e38ce072e724fd7add6243613f8d1810da084f54175353d25ccf9f9c7e5a/aiohttp-3.13.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e7d2f8616f0ff60bd332022279011776c3ac0faa0f1b463f7bb12326fbc97a1c", size = 501673, upload-time = "2026-03-31T21:57:06.208Z" }, + { url = "https://files.pythonhosted.org/packages/ba/ba/3bc7525d7e2beaa11b309a70d48b0d3cfc3c2089ec6a7d0820d59c657053/aiohttp-3.13.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2567b72e1ffc3ab25510db43f355b29eeada56c0a622e58dcdb19530eb0a3cb", size = 1763757, upload-time = "2026-03-31T21:57:07.882Z" }, + { url = "https://files.pythonhosted.org/packages/5e/ab/e87744cf18f1bd78263aba24924d4953b41086bd3a31d22452378e9028a0/aiohttp-3.13.5-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fb0540c854ac9c0c5ad495908fdfd3e332d553ec731698c0e29b1877ba0d2ec6", size = 1720152, upload-time = "2026-03-31T21:57:09.946Z" }, + { url = "https://files.pythonhosted.org/packages/6b/f3/ed17a6f2d742af17b50bae2d152315ed1b164b07a5fd5cc1754d99e4dfa5/aiohttp-3.13.5-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c9883051c6972f58bfc4ebb2116345ee2aa151178e99c3f2b2bbe2af712abd13", size = 1818010, upload-time = "2026-03-31T21:57:12.157Z" }, + { url = "https://files.pythonhosted.org/packages/53/06/ecbc63dc937192e2a5cb46df4d3edb21deb8225535818802f210a6ea5816/aiohttp-3.13.5-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2294172ce08a82fb7c7273485895de1fa1186cc8294cfeb6aef4af42ad261174", size = 1907251, upload-time = "2026-03-31T21:57:14.023Z" }, + { url = "https://files.pythonhosted.org/packages/7e/a5/0521aa32c1ddf3aa1e71dcc466be0b7db2771907a13f18cddaa45967d97b/aiohttp-3.13.5-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3a807cabd5115fb55af198b98178997a5e0e57dead43eb74a93d9c07d6d4a7dc", size = 1759969, upload-time = "2026-03-31T21:57:16.146Z" }, + { url = "https://files.pythonhosted.org/packages/f6/78/a38f8c9105199dd3b9706745865a8a59d0041b6be0ca0cc4b2ccf1bab374/aiohttp-3.13.5-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:aa6d0d932e0f39c02b80744273cd5c388a2d9bc07760a03164f229c8e02662f6", size = 1616871, upload-time = "2026-03-31T21:57:17.856Z" }, + { url = "https://files.pythonhosted.org/packages/6f/41/27392a61ead8ab38072105c71aa44ff891e71653fe53d576a7067da2b4e8/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:60869c7ac4aaabe7110f26499f3e6e5696eae98144735b12a9c3d9eae2b51a49", size = 1739844, upload-time = "2026-03-31T21:57:19.679Z" }, + { url = "https://files.pythonhosted.org/packages/6e/55/5564e7ae26d94f3214250009a0b1c65a0c6af4bf88924ccb6fdab901de28/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:26d2f8546f1dfa75efa50c3488215a903c0168d253b75fba4210f57ab77a0fb8", size = 1731969, upload-time = "2026-03-31T21:57:22.006Z" }, + { url = "https://files.pythonhosted.org/packages/6d/c5/705a3929149865fc941bcbdd1047b238e4a72bcb215a9b16b9d7a2e8d992/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1162a1492032c82f14271e831c8f4b49f2b6078f4f5fc74de2c912fa225d51d", size = 1795193, upload-time = "2026-03-31T21:57:24.256Z" }, + { url = "https://files.pythonhosted.org/packages/a6/19/edabed62f718d02cff7231ca0db4ef1c72504235bc467f7b67adb1679f48/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:8b14eb3262fad0dc2f89c1a43b13727e709504972186ff6a99a3ecaa77102b6c", size = 1606477, upload-time = "2026-03-31T21:57:26.364Z" }, + { url = "https://files.pythonhosted.org/packages/de/fc/76f80ef008675637d88d0b21584596dc27410a990b0918cb1e5776545b5b/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:ca9ac61ac6db4eb6c2a0cd1d0f7e1357647b638ccc92f7e9d8d133e71ed3c6ac", size = 1813198, upload-time = "2026-03-31T21:57:28.316Z" }, + { url = "https://files.pythonhosted.org/packages/e5/67/5b3ac26b80adb20ea541c487f73730dc8fa107d632c998f25bbbab98fcda/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7996023b2ed59489ae4762256c8516df9820f751cf2c5da8ed2fb20ee50abab3", size = 1752321, upload-time = "2026-03-31T21:57:30.549Z" }, + { url = "https://files.pythonhosted.org/packages/88/06/e4a2e49255ea23fa4feeb5ab092d90240d927c15e47b5b5c48dff5a9ce29/aiohttp-3.13.5-cp311-cp311-win32.whl", hash = "sha256:77dfa48c9f8013271011e51c00f8ada19851f013cde2c48fca1ba5e0caf5bb06", size = 439069, upload-time = "2026-03-31T21:57:32.388Z" }, + { url = "https://files.pythonhosted.org/packages/c0/43/8c7163a596dab4f8be12c190cf467a1e07e4734cf90eebb39f7f5d53fc6a/aiohttp-3.13.5-cp311-cp311-win_amd64.whl", hash = "sha256:d3a4834f221061624b8887090637db9ad4f61752001eae37d56c52fddade2dc8", size = 462859, upload-time = "2026-03-31T21:57:34.455Z" }, + { url = "https://files.pythonhosted.org/packages/be/6f/353954c29e7dcce7cf00280a02c75f30e133c00793c7a2ed3776d7b2f426/aiohttp-3.13.5-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:023ecba036ddd840b0b19bf195bfae970083fd7024ce1ac22e9bba90464620e9", size = 748876, upload-time = "2026-03-31T21:57:36.319Z" }, + { url = "https://files.pythonhosted.org/packages/f5/1b/428a7c64687b3b2e9cd293186695affc0e1e54a445d0361743b231f11066/aiohttp-3.13.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:15c933ad7920b7d9a20de151efcd05a6e38302cbf0e10c9b2acb9a42210a2416", size = 499557, upload-time = "2026-03-31T21:57:38.236Z" }, + { url = "https://files.pythonhosted.org/packages/29/47/7be41556bfbb6917069d6a6634bb7dd5e163ba445b783a90d40f5ac7e3a7/aiohttp-3.13.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ab2899f9fa2f9f741896ebb6fa07c4c883bfa5c7f2ddd8cf2aafa86fa981b2d2", size = 500258, upload-time = "2026-03-31T21:57:39.923Z" }, + { url = "https://files.pythonhosted.org/packages/67/84/c9ecc5828cb0b3695856c07c0a6817a99d51e2473400f705275a2b3d9239/aiohttp-3.13.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a60eaa2d440cd4707696b52e40ed3e2b0f73f65be07fd0ef23b6b539c9c0b0b4", size = 1749199, upload-time = "2026-03-31T21:57:41.938Z" }, + { url = "https://files.pythonhosted.org/packages/f0/d3/3c6d610e66b495657622edb6ae7c7fd31b2e9086b4ec50b47897ad6042a9/aiohttp-3.13.5-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:55b3bdd3292283295774ab585160c4004f4f2f203946997f49aac032c84649e9", size = 1721013, upload-time = "2026-03-31T21:57:43.904Z" }, + { url = "https://files.pythonhosted.org/packages/49/a0/24409c12217456df0bae7babe3b014e460b0b38a8e60753d6cb339f6556d/aiohttp-3.13.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c2b2355dc094e5f7d45a7bb262fe7207aa0460b37a0d87027dcf21b5d890e7d5", size = 1781501, upload-time = "2026-03-31T21:57:46.285Z" }, + { url = "https://files.pythonhosted.org/packages/98/9d/b65ec649adc5bccc008b0957a9a9c691070aeac4e41cea18559fef49958b/aiohttp-3.13.5-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b38765950832f7d728297689ad78f5f2cf79ff82487131c4d26fe6ceecdc5f8e", size = 1878981, upload-time = "2026-03-31T21:57:48.734Z" }, + { url = "https://files.pythonhosted.org/packages/57/d8/8d44036d7eb7b6a8ec4c5494ea0c8c8b94fbc0ed3991c1a7adf230df03bf/aiohttp-3.13.5-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b18f31b80d5a33661e08c89e202edabf1986e9b49c42b4504371daeaa11b47c1", size = 1767934, upload-time = "2026-03-31T21:57:51.171Z" }, + { url = "https://files.pythonhosted.org/packages/31/04/d3f8211f273356f158e3464e9e45484d3fb8c4ce5eb2f6fe9405c3273983/aiohttp-3.13.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:33add2463dde55c4f2d9635c6ab33ce154e5ecf322bd26d09af95c5f81cfa286", size = 1566671, upload-time = "2026-03-31T21:57:53.326Z" }, + { url = "https://files.pythonhosted.org/packages/41/db/073e4ebe00b78e2dfcacff734291651729a62953b48933d765dc513bf798/aiohttp-3.13.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:327cc432fdf1356fb4fbc6fe833ad4e9f6aacb71a8acaa5f1855e4b25910e4a9", size = 1705219, upload-time = "2026-03-31T21:57:55.385Z" }, + { url = "https://files.pythonhosted.org/packages/48/45/7dfba71a2f9fd97b15c95c06819de7eb38113d2cdb6319669195a7d64270/aiohttp-3.13.5-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:7c35b0bf0b48a70b4cb4fc5d7bed9b932532728e124874355de1a0af8ec4bc88", size = 1743049, upload-time = "2026-03-31T21:57:57.341Z" }, + { url = "https://files.pythonhosted.org/packages/18/71/901db0061e0f717d226386a7f471bb59b19566f2cae5f0d93874b017271f/aiohttp-3.13.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:df23d57718f24badef8656c49743e11a89fd6f5358fa8a7b96e728fda2abf7d3", size = 1749557, upload-time = "2026-03-31T21:57:59.626Z" }, + { url = "https://files.pythonhosted.org/packages/08/d5/41eebd16066e59cd43728fe74bce953d7402f2b4ddfdfef2c0e9f17ca274/aiohttp-3.13.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:02e048037a6501a5ec1f6fc9736135aec6eb8a004ce48838cb951c515f32c80b", size = 1558931, upload-time = "2026-03-31T21:58:01.972Z" }, + { url = "https://files.pythonhosted.org/packages/30/e6/4a799798bf05740e66c3a1161079bda7a3dd8e22ca392481d7a7f9af82a6/aiohttp-3.13.5-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:31cebae8b26f8a615d2b546fee45d5ffb76852ae6450e2a03f42c9102260d6fe", size = 1774125, upload-time = "2026-03-31T21:58:04.007Z" }, + { url = "https://files.pythonhosted.org/packages/84/63/7749337c90f92bc2cb18f9560d67aa6258c7060d1397d21529b8004fcf6f/aiohttp-3.13.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:888e78eb5ca55a615d285c3c09a7a91b42e9dd6fc699b166ebd5dee87c9ccf14", size = 1732427, upload-time = "2026-03-31T21:58:06.337Z" }, + { url = "https://files.pythonhosted.org/packages/98/de/cf2f44ff98d307e72fb97d5f5bbae3bfcb442f0ea9790c0bf5c5c2331404/aiohttp-3.13.5-cp312-cp312-win32.whl", hash = "sha256:8bd3ec6376e68a41f9f95f5ed170e2fcf22d4eb27a1f8cb361d0508f6e0557f3", size = 433534, upload-time = "2026-03-31T21:58:08.712Z" }, + { url = "https://files.pythonhosted.org/packages/aa/ca/eadf6f9c8fa5e31d40993e3db153fb5ed0b11008ad5d9de98a95045bed84/aiohttp-3.13.5-cp312-cp312-win_amd64.whl", hash = "sha256:110e448e02c729bcebb18c60b9214a87ba33bac4a9fa5e9a5f139938b56c6cb1", size = 460446, upload-time = "2026-03-31T21:58:10.945Z" }, + { url = "https://files.pythonhosted.org/packages/78/e9/d76bf503005709e390122d34e15256b88f7008e246c4bdbe915cd4f1adce/aiohttp-3.13.5-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a5029cc80718bbd545123cd8fe5d15025eccaaaace5d0eeec6bd556ad6163d61", size = 742930, upload-time = "2026-03-31T21:58:13.155Z" }, + { url = "https://files.pythonhosted.org/packages/57/00/4b7b70223deaebd9bb85984d01a764b0d7bd6526fcdc73cca83bcbe7243e/aiohttp-3.13.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4bb6bf5811620003614076bdc807ef3b5e38244f9d25ca5fe888eaccea2a9832", size = 496927, upload-time = "2026-03-31T21:58:15.073Z" }, + { url = "https://files.pythonhosted.org/packages/9c/f5/0fb20fb49f8efdcdce6cd8127604ad2c503e754a8f139f5e02b01626523f/aiohttp-3.13.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a84792f8631bf5a94e52d9cc881c0b824ab42717165a5579c760b830d9392ac9", size = 497141, upload-time = "2026-03-31T21:58:17.009Z" }, + { url = "https://files.pythonhosted.org/packages/3b/86/b7c870053e36a94e8951b803cb5b909bfbc9b90ca941527f5fcafbf6b0fa/aiohttp-3.13.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:57653eac22c6a4c13eb22ecf4d673d64a12f266e72785ab1c8b8e5940d0e8090", size = 1732476, upload-time = "2026-03-31T21:58:18.925Z" }, + { url = "https://files.pythonhosted.org/packages/b5/e5/4e161f84f98d80c03a238671b4136e6530453d65262867d989bbe78244d0/aiohttp-3.13.5-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5e5f7debc7a57af53fdf5c5009f9391d9f4c12867049d509bf7bb164a6e295b", size = 1706507, upload-time = "2026-03-31T21:58:21.094Z" }, + { url = "https://files.pythonhosted.org/packages/d4/56/ea11a9f01518bd5a2a2fcee869d248c4b8a0cfa0bb13401574fa31adf4d4/aiohttp-3.13.5-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c719f65bebcdf6716f10e9eff80d27567f7892d8988c06de12bbbd39307c6e3a", size = 1773465, upload-time = "2026-03-31T21:58:23.159Z" }, + { url = "https://files.pythonhosted.org/packages/eb/40/333ca27fb74b0383f17c90570c748f7582501507307350a79d9f9f3c6eb1/aiohttp-3.13.5-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d97f93fdae594d886c5a866636397e2bcab146fd7a132fd6bb9ce182224452f8", size = 1873523, upload-time = "2026-03-31T21:58:25.59Z" }, + { url = "https://files.pythonhosted.org/packages/f0/d2/e2f77eef1acb7111405433c707dc735e63f67a56e176e72e9e7a2cd3f493/aiohttp-3.13.5-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3df334e39d4c2f899a914f1dba283c1aadc311790733f705182998c6f7cae665", size = 1754113, upload-time = "2026-03-31T21:58:27.624Z" }, + { url = "https://files.pythonhosted.org/packages/fb/56/3f653d7f53c89669301ec9e42c95233e2a0c0a6dd051269e6e678db4fdb0/aiohttp-3.13.5-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fe6970addfea9e5e081401bcbadf865d2b6da045472f58af08427e108d618540", size = 1562351, upload-time = "2026-03-31T21:58:29.918Z" }, + { url = "https://files.pythonhosted.org/packages/ec/a6/9b3e91eb8ae791cce4ee736da02211c85c6f835f1bdfac0594a8a3b7018c/aiohttp-3.13.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7becdf835feff2f4f335d7477f121af787e3504b48b449ff737afb35869ba7bb", size = 1693205, upload-time = "2026-03-31T21:58:32.214Z" }, + { url = "https://files.pythonhosted.org/packages/98/fc/bfb437a99a2fcebd6b6eaec609571954de2ed424f01c352f4b5504371dd3/aiohttp-3.13.5-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:676e5651705ad5d8a70aeb8eb6936c436d8ebbd56e63436cb7dd9bb36d2a9a46", size = 1730618, upload-time = "2026-03-31T21:58:34.728Z" }, + { url = "https://files.pythonhosted.org/packages/e4/b6/c8534862126191a034f68153194c389addc285a0f1347d85096d349bbc15/aiohttp-3.13.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:9b16c653d38eb1a611cc898c41e76859ca27f119d25b53c12875fd0474ae31a8", size = 1745185, upload-time = "2026-03-31T21:58:36.909Z" }, + { url = "https://files.pythonhosted.org/packages/0b/93/4ca8ee2ef5236e2707e0fd5fecb10ce214aee1ff4ab307af9c558bda3b37/aiohttp-3.13.5-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:999802d5fa0389f58decd24b537c54aa63c01c3219ce17d1214cbda3c2b22d2d", size = 1557311, upload-time = "2026-03-31T21:58:39.38Z" }, + { url = "https://files.pythonhosted.org/packages/57/ae/76177b15f18c5f5d094f19901d284025db28eccc5ae374d1d254181d33f4/aiohttp-3.13.5-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:ec707059ee75732b1ba130ed5f9580fe10ff75180c812bc267ded039db5128c6", size = 1773147, upload-time = "2026-03-31T21:58:41.476Z" }, + { url = "https://files.pythonhosted.org/packages/01/a4/62f05a0a98d88af59d93b7fcac564e5f18f513cb7471696ac286db970d6a/aiohttp-3.13.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2d6d44a5b48132053c2f6cd5c8cb14bc67e99a63594e336b0f2af81e94d5530c", size = 1730356, upload-time = "2026-03-31T21:58:44.049Z" }, + { url = "https://files.pythonhosted.org/packages/e4/85/fc8601f59dfa8c9523808281f2da571f8b4699685f9809a228adcc90838d/aiohttp-3.13.5-cp313-cp313-win32.whl", hash = "sha256:329f292ed14d38a6c4c435e465f48bebb47479fd676a0411936cc371643225cc", size = 432637, upload-time = "2026-03-31T21:58:46.167Z" }, + { url = "https://files.pythonhosted.org/packages/c0/1b/ac685a8882896acf0f6b31d689e3792199cfe7aba37969fa91da63a7fa27/aiohttp-3.13.5-cp313-cp313-win_amd64.whl", hash = "sha256:69f571de7500e0557801c0b51f4780482c0ec5fe2ac851af5a92cfce1af1cb83", size = 458896, upload-time = "2026-03-31T21:58:48.119Z" }, + { url = "https://files.pythonhosted.org/packages/5d/ce/46572759afc859e867a5bc8ec3487315869013f59281ce61764f76d879de/aiohttp-3.13.5-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:eb4639f32fd4a9904ab8fb45bf3383ba71137f3d9d4ba25b3b3f3109977c5b8c", size = 745721, upload-time = "2026-03-31T21:58:50.229Z" }, + { url = "https://files.pythonhosted.org/packages/13/fe/8a2efd7626dbe6049b2ef8ace18ffda8a4dfcbe1bcff3ac30c0c7575c20b/aiohttp-3.13.5-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:7e5dc4311bd5ac493886c63cbf76ab579dbe4641268e7c74e48e774c74b6f2be", size = 497663, upload-time = "2026-03-31T21:58:52.232Z" }, + { url = "https://files.pythonhosted.org/packages/9b/91/cc8cc78a111826c54743d88651e1687008133c37e5ee615fee9b57990fac/aiohttp-3.13.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:756c3c304d394977519824449600adaf2be0ccee76d206ee339c5e76b70ded25", size = 499094, upload-time = "2026-03-31T21:58:54.566Z" }, + { url = "https://files.pythonhosted.org/packages/0a/33/a8362cb15cf16a3af7e86ed11962d5cd7d59b449202dc576cdc731310bde/aiohttp-3.13.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecc26751323224cf8186efcf7fbcbc30f4e1d8c7970659daf25ad995e4032a56", size = 1726701, upload-time = "2026-03-31T21:58:56.864Z" }, + { url = "https://files.pythonhosted.org/packages/45/0c/c091ac5c3a17114bd76cbf85d674650969ddf93387876cf67f754204bd77/aiohttp-3.13.5-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:10a75acfcf794edf9d8db50e5a7ec5fc818b2a8d3f591ce93bc7b1210df016d2", size = 1683360, upload-time = "2026-03-31T21:58:59.072Z" }, + { url = "https://files.pythonhosted.org/packages/23/73/bcee1c2b79bc275e964d1446c55c54441a461938e70267c86afaae6fba27/aiohttp-3.13.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0f7a18f258d124cd678c5fe072fe4432a4d5232b0657fca7c1847f599233c83a", size = 1773023, upload-time = "2026-03-31T21:59:01.776Z" }, + { url = "https://files.pythonhosted.org/packages/c7/ef/720e639df03004fee2d869f771799d8c23046dec47d5b81e396c7cda583a/aiohttp-3.13.5-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:df6104c009713d3a89621096f3e3e88cc323fd269dbd7c20afe18535094320be", size = 1853795, upload-time = "2026-03-31T21:59:04.568Z" }, + { url = "https://files.pythonhosted.org/packages/bd/c9/989f4034fb46841208de7aeeac2c6d8300745ab4f28c42f629ba77c2d916/aiohttp-3.13.5-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:241a94f7de7c0c3b616627aaad530fe2cb620084a8b144d3be7b6ecfe95bae3b", size = 1730405, upload-time = "2026-03-31T21:59:07.221Z" }, + { url = "https://files.pythonhosted.org/packages/ce/75/ee1fd286ca7dc599d824b5651dad7b3be7ff8d9a7e7b3fe9820d9180f7db/aiohttp-3.13.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c974fb66180e58709b6fc402846f13791240d180b74de81d23913abe48e96d94", size = 1558082, upload-time = "2026-03-31T21:59:09.484Z" }, + { url = "https://files.pythonhosted.org/packages/c3/20/1e9e6650dfc436340116b7aa89ff8cb2bbdf0abc11dfaceaad8f74273a10/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:6e27ea05d184afac78aabbac667450c75e54e35f62238d44463131bd3f96753d", size = 1692346, upload-time = "2026-03-31T21:59:12.068Z" }, + { url = "https://files.pythonhosted.org/packages/d8/40/8ebc6658d48ea630ac7903912fe0dd4e262f0e16825aa4c833c56c9f1f56/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a79a6d399cef33a11b6f004c67bb07741d91f2be01b8d712d52c75711b1e07c7", size = 1698891, upload-time = "2026-03-31T21:59:14.552Z" }, + { url = "https://files.pythonhosted.org/packages/d8/78/ea0ae5ec8ba7a5c10bdd6e318f1ba5e76fcde17db8275188772afc7917a4/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c632ce9c0b534fbe25b52c974515ed674937c5b99f549a92127c85f771a78772", size = 1742113, upload-time = "2026-03-31T21:59:17.068Z" }, + { url = "https://files.pythonhosted.org/packages/8a/66/9d308ed71e3f2491be1acb8769d96c6f0c47d92099f3bc9119cada27b357/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:fceedde51fbd67ee2bcc8c0b33d0126cc8b51ef3bbde2f86662bd6d5a6f10ec5", size = 1553088, upload-time = "2026-03-31T21:59:19.541Z" }, + { url = "https://files.pythonhosted.org/packages/da/a6/6cc25ed8dfc6e00c90f5c6d126a98e2cf28957ad06fa1036bd34b6f24a2c/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f92995dfec9420bb69ae629abf422e516923ba79ba4403bc750d94fb4a6c68c1", size = 1757976, upload-time = "2026-03-31T21:59:22.311Z" }, + { url = "https://files.pythonhosted.org/packages/c1/2b/cce5b0ffe0de99c83e5e36d8f828e4161e415660a9f3e58339d07cce3006/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:20ae0ff08b1f2c8788d6fb85afcb798654ae6ba0b747575f8562de738078457b", size = 1712444, upload-time = "2026-03-31T21:59:24.635Z" }, + { url = "https://files.pythonhosted.org/packages/6c/cf/9e1795b4160c58d29421eafd1a69c6ce351e2f7c8d3c6b7e4ca44aea1a5b/aiohttp-3.13.5-cp314-cp314-win32.whl", hash = "sha256:b20df693de16f42b2472a9c485e1c948ee55524786a0a34345511afdd22246f3", size = 438128, upload-time = "2026-03-31T21:59:27.291Z" }, + { url = "https://files.pythonhosted.org/packages/22/4d/eaedff67fc805aeba4ba746aec891b4b24cebb1a7d078084b6300f79d063/aiohttp-3.13.5-cp314-cp314-win_amd64.whl", hash = "sha256:f85c6f327bf0b8c29da7d93b1cabb6363fb5e4e160a32fa241ed2dce21b73162", size = 464029, upload-time = "2026-03-31T21:59:29.429Z" }, + { url = "https://files.pythonhosted.org/packages/79/11/c27d9332ee20d68dd164dc12a6ecdef2e2e35ecc97ed6cf0d2442844624b/aiohttp-3.13.5-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:1efb06900858bb618ff5cee184ae2de5828896c448403d51fb633f09e109be0a", size = 778758, upload-time = "2026-03-31T21:59:31.547Z" }, + { url = "https://files.pythonhosted.org/packages/04/fb/377aead2e0a3ba5f09b7624f702a964bdf4f08b5b6728a9799830c80041e/aiohttp-3.13.5-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:fee86b7c4bd29bdaf0d53d14739b08a106fdda809ca5fe032a15f52fae5fe254", size = 512883, upload-time = "2026-03-31T21:59:34.098Z" }, + { url = "https://files.pythonhosted.org/packages/bb/a6/aa109a33671f7a5d3bd78b46da9d852797c5e665bfda7d6b373f56bff2ec/aiohttp-3.13.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:20058e23909b9e65f9da62b396b77dfa95965cbe840f8def6e572538b1d32e36", size = 516668, upload-time = "2026-03-31T21:59:36.497Z" }, + { url = "https://files.pythonhosted.org/packages/79/b3/ca078f9f2fa9563c36fb8ef89053ea2bb146d6f792c5104574d49d8acb63/aiohttp-3.13.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cf20a8d6868cb15a73cab329ffc07291ba8c22b1b88176026106ae39aa6df0f", size = 1883461, upload-time = "2026-03-31T21:59:38.723Z" }, + { url = "https://files.pythonhosted.org/packages/b7/e3/a7ad633ca1ca497b852233a3cce6906a56c3225fb6d9217b5e5e60b7419d/aiohttp-3.13.5-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:330f5da04c987f1d5bdb8ae189137c77139f36bd1cb23779ca1a354a4b027800", size = 1747661, upload-time = "2026-03-31T21:59:41.187Z" }, + { url = "https://files.pythonhosted.org/packages/33/b9/cd6fe579bed34a906d3d783fe60f2fa297ef55b27bb4538438ee49d4dc41/aiohttp-3.13.5-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6f1cbf0c7926d315c3c26c2da41fd2b5d2fe01ac0e157b78caefc51a782196cf", size = 1863800, upload-time = "2026-03-31T21:59:43.84Z" }, + { url = "https://files.pythonhosted.org/packages/c0/3f/2c1e2f5144cefa889c8afd5cf431994c32f3b29da9961698ff4e3811b79a/aiohttp-3.13.5-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:53fc049ed6390d05423ba33103ded7281fe897cf97878f369a527070bd95795b", size = 1958382, upload-time = "2026-03-31T21:59:46.187Z" }, + { url = "https://files.pythonhosted.org/packages/66/1d/f31ec3f1013723b3babe3609e7f119c2c2fb6ef33da90061a705ef3e1bc8/aiohttp-3.13.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:898703aa2667e3c5ca4c54ca36cd73f58b7a38ef87a5606414799ebce4d3fd3a", size = 1803724, upload-time = "2026-03-31T21:59:48.656Z" }, + { url = "https://files.pythonhosted.org/packages/0e/b4/57712dfc6f1542f067daa81eb61da282fab3e6f1966fca25db06c4fc62d5/aiohttp-3.13.5-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0494a01ca9584eea1e5fbd6d748e61ecff218c51b576ee1999c23db7066417d8", size = 1640027, upload-time = "2026-03-31T21:59:51.284Z" }, + { url = "https://files.pythonhosted.org/packages/25/3c/734c878fb43ec083d8e31bf029daae1beafeae582d1b35da234739e82ee7/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6cf81fe010b8c17b09495cbd15c1d35afbc8fb405c0c9cf4738e5ae3af1d65be", size = 1806644, upload-time = "2026-03-31T21:59:53.753Z" }, + { url = "https://files.pythonhosted.org/packages/20/a5/f671e5cbec1c21d044ff3078223f949748f3a7f86b14e34a365d74a5d21f/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:c564dd5f09ddc9d8f2c2d0a301cd30a79a2cc1b46dd1a73bef8f0038863d016b", size = 1791630, upload-time = "2026-03-31T21:59:56.239Z" }, + { url = "https://files.pythonhosted.org/packages/0b/63/fb8d0ad63a0b8a99be97deac8c04dacf0785721c158bdf23d679a87aa99e/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:2994be9f6e51046c4f864598fd9abeb4fba6e88f0b2152422c9666dcd4aea9c6", size = 1809403, upload-time = "2026-03-31T21:59:59.103Z" }, + { url = "https://files.pythonhosted.org/packages/59/0c/bfed7f30662fcf12206481c2aac57dedee43fe1c49275e85b3a1e1742294/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:157826e2fa245d2ef46c83ea8a5faf77ca19355d278d425c29fda0beb3318037", size = 1634924, upload-time = "2026-03-31T22:00:02.116Z" }, + { url = "https://files.pythonhosted.org/packages/17/d6/fd518d668a09fd5a3319ae5e984d4d80b9a4b3df4e21c52f02251ef5a32e/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:a8aca50daa9493e9e13c0f566201a9006f080e7c50e5e90d0b06f53146a54500", size = 1836119, upload-time = "2026-03-31T22:00:04.756Z" }, + { url = "https://files.pythonhosted.org/packages/78/b7/15fb7a9d52e112a25b621c67b69c167805cb1f2ab8f1708a5c490d1b52fe/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3b13560160d07e047a93f23aaa30718606493036253d5430887514715b67c9d9", size = 1772072, upload-time = "2026-03-31T22:00:07.494Z" }, + { url = "https://files.pythonhosted.org/packages/7e/df/57ba7f0c4a553fc2bd8b6321df236870ec6fd64a2a473a8a13d4f733214e/aiohttp-3.13.5-cp314-cp314t-win32.whl", hash = "sha256:9a0f4474b6ea6818b41f82172d799e4b3d29e22c2c520ce4357856fced9af2f8", size = 471819, upload-time = "2026-03-31T22:00:10.277Z" }, + { url = "https://files.pythonhosted.org/packages/62/29/2f8418269e46454a26171bfdd6a055d74febf32234e474930f2f60a17145/aiohttp-3.13.5-cp314-cp314t-win_amd64.whl", hash = "sha256:18a2f6c1182c51baa1d28d68fea51513cb2a76612f038853c0ad3c145423d3d9", size = 505441, upload-time = "2026-03-31T22:00:12.791Z" }, + { url = "https://files.pythonhosted.org/packages/e2/a5/630bc484695d4a1342bbae85fb8689bf979106525684fc88f05b397324ad/aiohttp-3.13.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:347542f0ea3f95b2a955ee6656461fa1c776e401ac50ebce055a6c38454a0adf", size = 752872, upload-time = "2026-03-31T22:00:15.553Z" }, + { url = "https://files.pythonhosted.org/packages/cd/b8/6a19dda37fda94a9ebefb3c1ae0ff419ac7fbf4fb40750e992829fc13614/aiohttp-3.13.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:178c7b5e62b454c2bc790786e6058c3cc968613b4419251b478c153a4aec32b1", size = 504582, upload-time = "2026-03-31T22:00:18.191Z" }, + { url = "https://files.pythonhosted.org/packages/d5/34/8413eafee3421ade2d6ce9e7c0da1213e1d7f0049be09dcdc342b03a39ba/aiohttp-3.13.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af545c2cffdb0967a96b6249e6f5f7b0d92cdfd267f9d5238d5b9ca63e8edb10", size = 499094, upload-time = "2026-03-31T22:00:21.118Z" }, + { url = "https://files.pythonhosted.org/packages/da/cf/c6f97006093d1e8ca40fbab843ff49ec7725ab668f0714dd1cb702c62cbd/aiohttp-3.13.5-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:206b7b3ef96e4ce211754f0cd003feb28b7d81f0ad26b8d077a5d5161436067f", size = 1669505, upload-time = "2026-03-31T22:00:24.01Z" }, + { url = "https://files.pythonhosted.org/packages/c2/27/3b2288e66dcec8b04771b2bee3909f70e4072bea995cde5ab7e775e73ddc/aiohttp-3.13.5-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ee5e86776273de1795947d17bddd6bb19e0365fd2af4289c0d2c5454b6b1d36b", size = 1648928, upload-time = "2026-03-31T22:00:27.001Z" }, + { url = "https://files.pythonhosted.org/packages/3a/7f/605d766887594a88dcc27a19663499c7c5e13e7aa87f129b763765a2ee63/aiohttp-3.13.5-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:95d14ca7abefde230f7639ec136ade282655431fd5db03c343b19dda72dd1643", size = 1731800, upload-time = "2026-03-31T22:00:29.603Z" }, + { url = "https://files.pythonhosted.org/packages/71/94/5a878e728e30699d22b118f1a6ad576ab6fff9eb2c6fc8a7faa9376a1c3e/aiohttp-3.13.5-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:912d4b6af530ddb1338a66229dac3a25ff11d4448be3ec3d6340583995f56031", size = 1824247, upload-time = "2026-03-31T22:00:32.139Z" }, + { url = "https://files.pythonhosted.org/packages/37/99/84b448291e9996bb83bf4fad3a71a9786d542f19c50a3ff0531bfaba6fac/aiohttp-3.13.5-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e999f0c88a458c836d5fb521814e92ed2172c649200336a6df514987c1488258", size = 1670742, upload-time = "2026-03-31T22:00:34.788Z" }, + { url = "https://files.pythonhosted.org/packages/14/a8/d8d5d1ab6d29a4a3bdb9db31f161e338bfdf6638f6574ea8380f1d4a243c/aiohttp-3.13.5-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:39380e12bd1f2fdab4285b6e055ad48efbaed5c836433b142ed4f5b9be71036a", size = 1562474, upload-time = "2026-03-31T22:00:37.623Z" }, + { url = "https://files.pythonhosted.org/packages/92/e8/bd889697916f10b65524422c61b4eeaf919eb35a170290cccb680cbe4eb4/aiohttp-3.13.5-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9efcc0f11d850cefcafdd9275b9576ad3bfb539bed96807663b32ad99c4d4b88", size = 1642235, upload-time = "2026-03-31T22:00:40.541Z" }, + { url = "https://files.pythonhosted.org/packages/60/42/3f1928107131f1413a5972ace14ddcd5364968e9bd7b3ad71272defafc9c/aiohttp-3.13.5-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:147b4f501d0292077f29d5268c16bb7c864a1f054d7001c4c1812c0421ea1ed0", size = 1655397, upload-time = "2026-03-31T22:00:43.167Z" }, + { url = "https://files.pythonhosted.org/packages/b2/79/c4bbcf4cac3a4715a326e49720ccdc3a4b5e14a367c5029eae7727d06029/aiohttp-3.13.5-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:d147004fede1b12f6013a6dbb2a26a986a671a03c6ea740ddc76500e5f1c399f", size = 1703509, upload-time = "2026-03-31T22:00:45.908Z" }, + { url = "https://files.pythonhosted.org/packages/d1/e6/32d245876f211a7308a7d5437707f9296b1f9837a2888a407ed04e61321c/aiohttp-3.13.5-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:9277145d36a01653863899c665243871434694bcc3431922c3b35c978061bdb8", size = 1550098, upload-time = "2026-03-31T22:00:49.48Z" }, + { url = "https://files.pythonhosted.org/packages/db/62/ab0f1304def56ce2356e6fbb9f0b024d6544010351430070f48f53b89e0a/aiohttp-3.13.5-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:4e704c52438f66fdd89588346183d898bb42167cf88f8b7ff1c0f9fc957c348f", size = 1724326, upload-time = "2026-03-31T22:00:52.165Z" }, + { url = "https://files.pythonhosted.org/packages/c4/9a/aab4469689024046220ea438aa020ea2ae04cd1dd71aea3057e094f8c357/aiohttp-3.13.5-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a8a4d3427e8de1312ddf309cc482186466c79895b3a139fed3259fc01dfa9a5b", size = 1658824, upload-time = "2026-03-31T22:00:55.122Z" }, + { url = "https://files.pythonhosted.org/packages/b0/98/bcc35d4db687acabf06d41f561a99fa88bca145292513388c858d99b72c5/aiohttp-3.13.5-cp39-cp39-win32.whl", hash = "sha256:6f497a6876aa4b1a102b04996ce4c1170c7040d83faa9387dd921c16e30d5c83", size = 440302, upload-time = "2026-03-31T22:00:57.673Z" }, + { url = "https://files.pythonhosted.org/packages/25/61/b0203c2ef6bd268fca0eda142f0efbba7cbebd7ad38f7bb01dd31c2ff68e/aiohttp-3.13.5-cp39-cp39-win_amd64.whl", hash = "sha256:cb979826071c0986a5f08333a36104153478ce6018c58cba7f9caddaf63d5d67", size = 463076, upload-time = "2026-03-31T22:01:00.264Z" }, +] + +[[package]] +name = "aiosignal" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "frozenlist" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" }, +] + +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, +] + +[[package]] +name = "anyio" +version = "4.12.1" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.10'", +] +dependencies = [ + { name = "exceptiongroup", marker = "python_full_version < '3.10'" }, + { name = "idna", marker = "python_full_version < '3.10'" }, + { name = "typing-extensions", marker = "python_full_version < '3.10'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/96/f0/5eb65b2bb0d09ac6776f2eb54adee6abe8228ea05b20a5ad0e4945de8aac/anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703", size = 228685, upload-time = "2026-01-06T11:45:21.246Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592, upload-time = "2026-01-06T11:45:19.497Z" }, +] + +[[package]] +name = "anyio" +version = "4.13.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", +] +dependencies = [ + { name = "exceptiongroup", marker = "python_full_version == '3.10.*'" }, + { name = "idna", marker = "python_full_version >= '3.10'" }, + { name = "typing-extensions", marker = "python_full_version >= '3.10' and python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/19/14/2c5dd9f512b66549ae92767a9c7b330ae88e1932ca57876909410251fe13/anyio-4.13.0.tar.gz", hash = "sha256:334b70e641fd2221c1505b3890c69882fe4a2df910cba14d97019b90b24439dc", size = 231622, upload-time = "2026-03-24T12:59:09.671Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl", hash = "sha256:08b310f9e24a9594186fd75b4f73f4a4152069e3853f1ed8bfbf58369f4ad708", size = 114353, upload-time = "2026-03-24T12:59:08.246Z" }, +] + +[[package]] +name = "async-timeout" +version = "5.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274, upload-time = "2024-11-06T16:41:39.6Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233, upload-time = "2024-11-06T16:41:37.9Z" }, +] + +[[package]] +name = "attrs" +version = "26.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9a/8e/82a0fe20a541c03148528be8cac2408564a6c9a0cc7e9171802bc1d26985/attrs-26.1.0.tar.gz", hash = "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32", size = 952055, upload-time = "2026-03-19T14:22:25.026Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", size = 67548, upload-time = "2026-03-19T14:22:23.645Z" }, +] + +[[package]] +name = "certifi" +version = "2026.4.22" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/25/ee/6caf7a40c36a1220410afe15a1cc64993a1f864871f698c0f93acb72842a/certifi-2026.4.22.tar.gz", hash = "sha256:8d455352a37b71bf76a79caa83a3d6c25afee4a385d632127b6afb3963f1c580", size = 137077, upload-time = "2026-04-22T11:26:11.191Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/30/7cd8fdcdfbc5b869528b079bfb76dcdf6056b1a2097a662e5e8c04f42965/certifi-2026.4.22-py3-none-any.whl", hash = "sha256:3cb2210c8f88ba2318d29b0388d1023c8492ff72ecdde4ebdaddbb13a31b1c4a", size = 135707, upload-time = "2026-04-22T11:26:09.372Z" }, +] + +[[package]] +name = "cloudflare" +version = "5.0.0b2" +source = { editable = "." } +dependencies = [ + { name = "anyio", version = "4.12.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "anyio", version = "4.13.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "distro" }, + { name = "httpx" }, + { name = "pydantic" }, + { name = "sniffio" }, + { name = "typing-extensions" }, +] + +[package.optional-dependencies] +aiohttp = [ + { name = "aiohttp" }, + { name = "httpx-aiohttp" }, +] + +[package.metadata] +requires-dist = [ + { name = "aiohttp", marker = "extra == 'aiohttp'" }, + { name = "anyio", specifier = ">=3.5.0,<5" }, + { name = "distro", specifier = ">=1.7.0,<2" }, + { name = "httpx", specifier = ">=0.23.0,<1" }, + { name = "httpx-aiohttp", marker = "extra == 'aiohttp'", specifier = ">=0.1.9" }, + { name = "pydantic", specifier = ">=1.9.0,<3" }, + { name = "sniffio" }, + { name = "typing-extensions", specifier = ">=4.14,<5" }, +] +provides-extras = ["aiohttp"] + +[[package]] +name = "distro" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722, upload-time = "2023-12-24T09:54:32.31Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" }, +] + +[[package]] +name = "exceptiongroup" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, +] + +[[package]] +name = "frozenlist" +version = "1.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875, upload-time = "2025-10-06T05:38:17.865Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/4a/557715d5047da48d54e659203b9335be7bfaafda2c3f627b7c47e0b3aaf3/frozenlist-1.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b37f6d31b3dcea7deb5e9696e529a6aa4a898adc33db82da12e4c60a7c4d2011", size = 86230, upload-time = "2025-10-06T05:35:23.699Z" }, + { url = "https://files.pythonhosted.org/packages/a2/fb/c85f9fed3ea8fe8740e5b46a59cc141c23b842eca617da8876cfce5f760e/frozenlist-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef2b7b394f208233e471abc541cc6991f907ffd47dc72584acee3147899d6565", size = 49621, upload-time = "2025-10-06T05:35:25.341Z" }, + { url = "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a88f062f072d1589b7b46e951698950e7da00442fc1cacbe17e19e025dc327ad", size = 49889, upload-time = "2025-10-06T05:35:26.797Z" }, + { url = "https://files.pythonhosted.org/packages/5d/ed/c7895fd2fde7f3ee70d248175f9b6cdf792fb741ab92dc59cd9ef3bd241b/frozenlist-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f57fb59d9f385710aa7060e89410aeb5058b99e62f4d16b08b91986b9a2140c2", size = 219464, upload-time = "2025-10-06T05:35:28.254Z" }, + { url = "https://files.pythonhosted.org/packages/6b/83/4d587dccbfca74cb8b810472392ad62bfa100bf8108c7223eb4c4fa2f7b3/frozenlist-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:799345ab092bee59f01a915620b5d014698547afd011e691a208637312db9186", size = 221649, upload-time = "2025-10-06T05:35:29.454Z" }, + { url = "https://files.pythonhosted.org/packages/6a/c6/fd3b9cd046ec5fff9dab66831083bc2077006a874a2d3d9247dea93ddf7e/frozenlist-1.8.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c23c3ff005322a6e16f71bf8692fcf4d5a304aaafe1e262c98c6d4adc7be863e", size = 219188, upload-time = "2025-10-06T05:35:30.951Z" }, + { url = "https://files.pythonhosted.org/packages/ce/80/6693f55eb2e085fc8afb28cf611448fb5b90e98e068fa1d1b8d8e66e5c7d/frozenlist-1.8.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8a76ea0f0b9dfa06f254ee06053d93a600865b3274358ca48a352ce4f0798450", size = 231748, upload-time = "2025-10-06T05:35:32.101Z" }, + { url = "https://files.pythonhosted.org/packages/97/d6/e9459f7c5183854abd989ba384fe0cc1a0fb795a83c033f0571ec5933ca4/frozenlist-1.8.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c7366fe1418a6133d5aa824ee53d406550110984de7637d65a178010f759c6ef", size = 236351, upload-time = "2025-10-06T05:35:33.834Z" }, + { url = "https://files.pythonhosted.org/packages/97/92/24e97474b65c0262e9ecd076e826bfd1d3074adcc165a256e42e7b8a7249/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13d23a45c4cebade99340c4165bd90eeb4a56c6d8a9d8aa49568cac19a6d0dc4", size = 218767, upload-time = "2025-10-06T05:35:35.205Z" }, + { url = "https://files.pythonhosted.org/packages/ee/bf/dc394a097508f15abff383c5108cb8ad880d1f64a725ed3b90d5c2fbf0bb/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4a3408834f65da56c83528fb52ce7911484f0d1eaf7b761fc66001db1646eff", size = 235887, upload-time = "2025-10-06T05:35:36.354Z" }, + { url = "https://files.pythonhosted.org/packages/40/90/25b201b9c015dbc999a5baf475a257010471a1fa8c200c843fd4abbee725/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:42145cd2748ca39f32801dad54aeea10039da6f86e303659db90db1c4b614c8c", size = 228785, upload-time = "2025-10-06T05:35:37.949Z" }, + { url = "https://files.pythonhosted.org/packages/84/f4/b5bc148df03082f05d2dd30c089e269acdbe251ac9a9cf4e727b2dbb8a3d/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e2de870d16a7a53901e41b64ffdf26f2fbb8917b3e6ebf398098d72c5b20bd7f", size = 230312, upload-time = "2025-10-06T05:35:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/db/4b/87e95b5d15097c302430e647136b7d7ab2398a702390cf4c8601975709e7/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:20e63c9493d33ee48536600d1a5c95eefc870cd71e7ab037763d1fbb89cc51e7", size = 217650, upload-time = "2025-10-06T05:35:40.377Z" }, + { url = "https://files.pythonhosted.org/packages/e5/70/78a0315d1fea97120591a83e0acd644da638c872f142fd72a6cebee825f3/frozenlist-1.8.0-cp310-cp310-win32.whl", hash = "sha256:adbeebaebae3526afc3c96fad434367cafbfd1b25d72369a9e5858453b1bb71a", size = 39659, upload-time = "2025-10-06T05:35:41.863Z" }, + { url = "https://files.pythonhosted.org/packages/66/aa/3f04523fb189a00e147e60c5b2205126118f216b0aa908035c45336e27e4/frozenlist-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:667c3777ca571e5dbeb76f331562ff98b957431df140b54c85fd4d52eea8d8f6", size = 43837, upload-time = "2025-10-06T05:35:43.205Z" }, + { url = "https://files.pythonhosted.org/packages/39/75/1135feecdd7c336938bd55b4dc3b0dfc46d85b9be12ef2628574b28de776/frozenlist-1.8.0-cp310-cp310-win_arm64.whl", hash = "sha256:80f85f0a7cc86e7a54c46d99c9e1318ff01f4687c172ede30fd52d19d1da1c8e", size = 39989, upload-time = "2025-10-06T05:35:44.596Z" }, + { url = "https://files.pythonhosted.org/packages/bc/03/077f869d540370db12165c0aa51640a873fb661d8b315d1d4d67b284d7ac/frozenlist-1.8.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:09474e9831bc2b2199fad6da3c14c7b0fbdd377cce9d3d77131be28906cb7d84", size = 86912, upload-time = "2025-10-06T05:35:45.98Z" }, + { url = "https://files.pythonhosted.org/packages/df/b5/7610b6bd13e4ae77b96ba85abea1c8cb249683217ef09ac9e0ae93f25a91/frozenlist-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:17c883ab0ab67200b5f964d2b9ed6b00971917d5d8a92df149dc2c9779208ee9", size = 50046, upload-time = "2025-10-06T05:35:47.009Z" }, + { url = "https://files.pythonhosted.org/packages/6e/ef/0e8f1fe32f8a53dd26bdd1f9347efe0778b0fddf62789ea683f4cc7d787d/frozenlist-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fa47e444b8ba08fffd1c18e8cdb9a75db1b6a27f17507522834ad13ed5922b93", size = 50119, upload-time = "2025-10-06T05:35:48.38Z" }, + { url = "https://files.pythonhosted.org/packages/11/b1/71a477adc7c36e5fb628245dfbdea2166feae310757dea848d02bd0689fd/frozenlist-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2552f44204b744fba866e573be4c1f9048d6a324dfe14475103fd51613eb1d1f", size = 231067, upload-time = "2025-10-06T05:35:49.97Z" }, + { url = "https://files.pythonhosted.org/packages/45/7e/afe40eca3a2dc19b9904c0f5d7edfe82b5304cb831391edec0ac04af94c2/frozenlist-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:957e7c38f250991e48a9a73e6423db1bb9dd14e722a10f6b8bb8e16a0f55f695", size = 233160, upload-time = "2025-10-06T05:35:51.729Z" }, + { url = "https://files.pythonhosted.org/packages/a6/aa/7416eac95603ce428679d273255ffc7c998d4132cfae200103f164b108aa/frozenlist-1.8.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8585e3bb2cdea02fc88ffa245069c36555557ad3609e83be0ec71f54fd4abb52", size = 228544, upload-time = "2025-10-06T05:35:53.246Z" }, + { url = "https://files.pythonhosted.org/packages/8b/3d/2a2d1f683d55ac7e3875e4263d28410063e738384d3adc294f5ff3d7105e/frozenlist-1.8.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:edee74874ce20a373d62dc28b0b18b93f645633c2943fd90ee9d898550770581", size = 243797, upload-time = "2025-10-06T05:35:54.497Z" }, + { url = "https://files.pythonhosted.org/packages/78/1e/2d5565b589e580c296d3bb54da08d206e797d941a83a6fdea42af23be79c/frozenlist-1.8.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c9a63152fe95756b85f31186bddf42e4c02c6321207fd6601a1c89ebac4fe567", size = 247923, upload-time = "2025-10-06T05:35:55.861Z" }, + { url = "https://files.pythonhosted.org/packages/aa/c3/65872fcf1d326a7f101ad4d86285c403c87be7d832b7470b77f6d2ed5ddc/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b6db2185db9be0a04fecf2f241c70b63b1a242e2805be291855078f2b404dd6b", size = 230886, upload-time = "2025-10-06T05:35:57.399Z" }, + { url = "https://files.pythonhosted.org/packages/a0/76/ac9ced601d62f6956f03cc794f9e04c81719509f85255abf96e2510f4265/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f4be2e3d8bc8aabd566f8d5b8ba7ecc09249d74ba3c9ed52e54dc23a293f0b92", size = 245731, upload-time = "2025-10-06T05:35:58.563Z" }, + { url = "https://files.pythonhosted.org/packages/b9/49/ecccb5f2598daf0b4a1415497eba4c33c1e8ce07495eb07d2860c731b8d5/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c8d1634419f39ea6f5c427ea2f90ca85126b54b50837f31497f3bf38266e853d", size = 241544, upload-time = "2025-10-06T05:35:59.719Z" }, + { url = "https://files.pythonhosted.org/packages/53/4b/ddf24113323c0bbcc54cb38c8b8916f1da7165e07b8e24a717b4a12cbf10/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:1a7fa382a4a223773ed64242dbe1c9c326ec09457e6b8428efb4118c685c3dfd", size = 241806, upload-time = "2025-10-06T05:36:00.959Z" }, + { url = "https://files.pythonhosted.org/packages/a7/fb/9b9a084d73c67175484ba2789a59f8eebebd0827d186a8102005ce41e1ba/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:11847b53d722050808926e785df837353bd4d75f1d494377e59b23594d834967", size = 229382, upload-time = "2025-10-06T05:36:02.22Z" }, + { url = "https://files.pythonhosted.org/packages/95/a3/c8fb25aac55bf5e12dae5c5aa6a98f85d436c1dc658f21c3ac73f9fa95e5/frozenlist-1.8.0-cp311-cp311-win32.whl", hash = "sha256:27c6e8077956cf73eadd514be8fb04d77fc946a7fe9f7fe167648b0b9085cc25", size = 39647, upload-time = "2025-10-06T05:36:03.409Z" }, + { url = "https://files.pythonhosted.org/packages/0a/f5/603d0d6a02cfd4c8f2a095a54672b3cf967ad688a60fb9faf04fc4887f65/frozenlist-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:ac913f8403b36a2c8610bbfd25b8013488533e71e62b4b4adce9c86c8cea905b", size = 44064, upload-time = "2025-10-06T05:36:04.368Z" }, + { url = "https://files.pythonhosted.org/packages/5d/16/c2c9ab44e181f043a86f9a8f84d5124b62dbcb3a02c0977ec72b9ac1d3e0/frozenlist-1.8.0-cp311-cp311-win_arm64.whl", hash = "sha256:d4d3214a0f8394edfa3e303136d0575eece0745ff2b47bd2cb2e66dd92d4351a", size = 39937, upload-time = "2025-10-06T05:36:05.669Z" }, + { url = "https://files.pythonhosted.org/packages/69/29/948b9aa87e75820a38650af445d2ef2b6b8a6fab1a23b6bb9e4ef0be2d59/frozenlist-1.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78f7b9e5d6f2fdb88cdde9440dc147259b62b9d3b019924def9f6478be254ac1", size = 87782, upload-time = "2025-10-06T05:36:06.649Z" }, + { url = "https://files.pythonhosted.org/packages/64/80/4f6e318ee2a7c0750ed724fa33a4bdf1eacdc5a39a7a24e818a773cd91af/frozenlist-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:229bf37d2e4acdaf808fd3f06e854a4a7a3661e871b10dc1f8f1896a3b05f18b", size = 50594, upload-time = "2025-10-06T05:36:07.69Z" }, + { url = "https://files.pythonhosted.org/packages/2b/94/5c8a2b50a496b11dd519f4a24cb5496cf125681dd99e94c604ccdea9419a/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f833670942247a14eafbb675458b4e61c82e002a148f49e68257b79296e865c4", size = 50448, upload-time = "2025-10-06T05:36:08.78Z" }, + { url = "https://files.pythonhosted.org/packages/6a/bd/d91c5e39f490a49df14320f4e8c80161cfcce09f1e2cde1edd16a551abb3/frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:494a5952b1c597ba44e0e78113a7266e656b9794eec897b19ead706bd7074383", size = 242411, upload-time = "2025-10-06T05:36:09.801Z" }, + { url = "https://files.pythonhosted.org/packages/8f/83/f61505a05109ef3293dfb1ff594d13d64a2324ac3482be2cedc2be818256/frozenlist-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f423a119f4777a4a056b66ce11527366a8bb92f54e541ade21f2374433f6d4", size = 243014, upload-time = "2025-10-06T05:36:11.394Z" }, + { url = "https://files.pythonhosted.org/packages/d8/cb/cb6c7b0f7d4023ddda30cf56b8b17494eb3a79e3fda666bf735f63118b35/frozenlist-1.8.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3462dd9475af2025c31cc61be6652dfa25cbfb56cbbf52f4ccfe029f38decaf8", size = 234909, upload-time = "2025-10-06T05:36:12.598Z" }, + { url = "https://files.pythonhosted.org/packages/31/c5/cd7a1f3b8b34af009fb17d4123c5a778b44ae2804e3ad6b86204255f9ec5/frozenlist-1.8.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4c800524c9cd9bac5166cd6f55285957fcfc907db323e193f2afcd4d9abd69b", size = 250049, upload-time = "2025-10-06T05:36:14.065Z" }, + { url = "https://files.pythonhosted.org/packages/c0/01/2f95d3b416c584a1e7f0e1d6d31998c4a795f7544069ee2e0962a4b60740/frozenlist-1.8.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d6a5df73acd3399d893dafc71663ad22534b5aa4f94e8a2fabfe856c3c1b6a52", size = 256485, upload-time = "2025-10-06T05:36:15.39Z" }, + { url = "https://files.pythonhosted.org/packages/ce/03/024bf7720b3abaebcff6d0793d73c154237b85bdf67b7ed55e5e9596dc9a/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:405e8fe955c2280ce66428b3ca55e12b3c4e9c336fb2103a4937e891c69a4a29", size = 237619, upload-time = "2025-10-06T05:36:16.558Z" }, + { url = "https://files.pythonhosted.org/packages/69/fa/f8abdfe7d76b731f5d8bd217827cf6764d4f1d9763407e42717b4bed50a0/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:908bd3f6439f2fef9e85031b59fd4f1297af54415fb60e4254a95f75b3cab3f3", size = 250320, upload-time = "2025-10-06T05:36:17.821Z" }, + { url = "https://files.pythonhosted.org/packages/f5/3c/b051329f718b463b22613e269ad72138cc256c540f78a6de89452803a47d/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:294e487f9ec720bd8ffcebc99d575f7eff3568a08a253d1ee1a0378754b74143", size = 246820, upload-time = "2025-10-06T05:36:19.046Z" }, + { url = "https://files.pythonhosted.org/packages/0f/ae/58282e8f98e444b3f4dd42448ff36fa38bef29e40d40f330b22e7108f565/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:74c51543498289c0c43656701be6b077f4b265868fa7f8a8859c197006efb608", size = 250518, upload-time = "2025-10-06T05:36:20.763Z" }, + { url = "https://files.pythonhosted.org/packages/8f/96/007e5944694d66123183845a106547a15944fbbb7154788cbf7272789536/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:776f352e8329135506a1d6bf16ac3f87bc25b28e765949282dcc627af36123aa", size = 239096, upload-time = "2025-10-06T05:36:22.129Z" }, + { url = "https://files.pythonhosted.org/packages/66/bb/852b9d6db2fa40be96f29c0d1205c306288f0684df8fd26ca1951d461a56/frozenlist-1.8.0-cp312-cp312-win32.whl", hash = "sha256:433403ae80709741ce34038da08511d4a77062aa924baf411ef73d1146e74faf", size = 39985, upload-time = "2025-10-06T05:36:23.661Z" }, + { url = "https://files.pythonhosted.org/packages/b8/af/38e51a553dd66eb064cdf193841f16f077585d4d28394c2fa6235cb41765/frozenlist-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:34187385b08f866104f0c0617404c8eb08165ab1272e884abc89c112e9c00746", size = 44591, upload-time = "2025-10-06T05:36:24.958Z" }, + { url = "https://files.pythonhosted.org/packages/a7/06/1dc65480ab147339fecc70797e9c2f69d9cea9cf38934ce08df070fdb9cb/frozenlist-1.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:fe3c58d2f5db5fbd18c2987cba06d51b0529f52bc3a6cdc33d3f4eab725104bd", size = 40102, upload-time = "2025-10-06T05:36:26.333Z" }, + { url = "https://files.pythonhosted.org/packages/2d/40/0832c31a37d60f60ed79e9dfb5a92e1e2af4f40a16a29abcc7992af9edff/frozenlist-1.8.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8d92f1a84bb12d9e56f818b3a746f3efba93c1b63c8387a73dde655e1e42282a", size = 85717, upload-time = "2025-10-06T05:36:27.341Z" }, + { url = "https://files.pythonhosted.org/packages/30/ba/b0b3de23f40bc55a7057bd38434e25c34fa48e17f20ee273bbde5e0650f3/frozenlist-1.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96153e77a591c8adc2ee805756c61f59fef4cf4073a9275ee86fe8cba41241f7", size = 49651, upload-time = "2025-10-06T05:36:28.855Z" }, + { url = "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f21f00a91358803399890ab167098c131ec2ddd5f8f5fd5fe9c9f2c6fcd91e40", size = 49417, upload-time = "2025-10-06T05:36:29.877Z" }, + { url = "https://files.pythonhosted.org/packages/d5/4e/e4691508f9477ce67da2015d8c00acd751e6287739123113a9fca6f1604e/frozenlist-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fb30f9626572a76dfe4293c7194a09fb1fe93ba94c7d4f720dfae3b646b45027", size = 234391, upload-time = "2025-10-06T05:36:31.301Z" }, + { url = "https://files.pythonhosted.org/packages/40/76/c202df58e3acdf12969a7895fd6f3bc016c642e6726aa63bd3025e0fc71c/frozenlist-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eaa352d7047a31d87dafcacbabe89df0aa506abb5b1b85a2fb91bc3faa02d822", size = 233048, upload-time = "2025-10-06T05:36:32.531Z" }, + { url = "https://files.pythonhosted.org/packages/f9/c0/8746afb90f17b73ca5979c7a3958116e105ff796e718575175319b5bb4ce/frozenlist-1.8.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:03ae967b4e297f58f8c774c7eabcce57fe3c2434817d4385c50661845a058121", size = 226549, upload-time = "2025-10-06T05:36:33.706Z" }, + { url = "https://files.pythonhosted.org/packages/7e/eb/4c7eefc718ff72f9b6c4893291abaae5fbc0c82226a32dcd8ef4f7a5dbef/frozenlist-1.8.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f6292f1de555ffcc675941d65fffffb0a5bcd992905015f85d0592201793e0e5", size = 239833, upload-time = "2025-10-06T05:36:34.947Z" }, + { url = "https://files.pythonhosted.org/packages/c2/4e/e5c02187cf704224f8b21bee886f3d713ca379535f16893233b9d672ea71/frozenlist-1.8.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29548f9b5b5e3460ce7378144c3010363d8035cea44bc0bf02d57f5a685e084e", size = 245363, upload-time = "2025-10-06T05:36:36.534Z" }, + { url = "https://files.pythonhosted.org/packages/1f/96/cb85ec608464472e82ad37a17f844889c36100eed57bea094518bf270692/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ec3cc8c5d4084591b4237c0a272cc4f50a5b03396a47d9caaf76f5d7b38a4f11", size = 229314, upload-time = "2025-10-06T05:36:38.582Z" }, + { url = "https://files.pythonhosted.org/packages/5d/6f/4ae69c550e4cee66b57887daeebe006fe985917c01d0fff9caab9883f6d0/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:517279f58009d0b1f2e7c1b130b377a349405da3f7621ed6bfae50b10adf20c1", size = 243365, upload-time = "2025-10-06T05:36:40.152Z" }, + { url = "https://files.pythonhosted.org/packages/7a/58/afd56de246cf11780a40a2c28dc7cbabbf06337cc8ddb1c780a2d97e88d8/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:db1e72ede2d0d7ccb213f218df6a078a9c09a7de257c2fe8fcef16d5925230b1", size = 237763, upload-time = "2025-10-06T05:36:41.355Z" }, + { url = "https://files.pythonhosted.org/packages/cb/36/cdfaf6ed42e2644740d4a10452d8e97fa1c062e2a8006e4b09f1b5fd7d63/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b4dec9482a65c54a5044486847b8a66bf10c9cb4926d42927ec4e8fd5db7fed8", size = 240110, upload-time = "2025-10-06T05:36:42.716Z" }, + { url = "https://files.pythonhosted.org/packages/03/a8/9ea226fbefad669f11b52e864c55f0bd57d3c8d7eb07e9f2e9a0b39502e1/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:21900c48ae04d13d416f0e1e0c4d81f7931f73a9dfa0b7a8746fb2fe7dd970ed", size = 233717, upload-time = "2025-10-06T05:36:44.251Z" }, + { url = "https://files.pythonhosted.org/packages/1e/0b/1b5531611e83ba7d13ccc9988967ea1b51186af64c42b7a7af465dcc9568/frozenlist-1.8.0-cp313-cp313-win32.whl", hash = "sha256:8b7b94a067d1c504ee0b16def57ad5738701e4ba10cec90529f13fa03c833496", size = 39628, upload-time = "2025-10-06T05:36:45.423Z" }, + { url = "https://files.pythonhosted.org/packages/d8/cf/174c91dbc9cc49bc7b7aab74d8b734e974d1faa8f191c74af9b7e80848e6/frozenlist-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:878be833caa6a3821caf85eb39c5ba92d28e85df26d57afb06b35b2efd937231", size = 43882, upload-time = "2025-10-06T05:36:46.796Z" }, + { url = "https://files.pythonhosted.org/packages/c1/17/502cd212cbfa96eb1388614fe39a3fc9ab87dbbe042b66f97acb57474834/frozenlist-1.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:44389d135b3ff43ba8cc89ff7f51f5a0bb6b63d829c8300f79a2fe4fe61bcc62", size = 39676, upload-time = "2025-10-06T05:36:47.8Z" }, + { url = "https://files.pythonhosted.org/packages/d2/5c/3bbfaa920dfab09e76946a5d2833a7cbdf7b9b4a91c714666ac4855b88b4/frozenlist-1.8.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e25ac20a2ef37e91c1b39938b591457666a0fa835c7783c3a8f33ea42870db94", size = 89235, upload-time = "2025-10-06T05:36:48.78Z" }, + { url = "https://files.pythonhosted.org/packages/d2/d6/f03961ef72166cec1687e84e8925838442b615bd0b8854b54923ce5b7b8a/frozenlist-1.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07cdca25a91a4386d2e76ad992916a85038a9b97561bf7a3fd12d5d9ce31870c", size = 50742, upload-time = "2025-10-06T05:36:49.837Z" }, + { url = "https://files.pythonhosted.org/packages/1e/bb/a6d12b7ba4c3337667d0e421f7181c82dda448ce4e7ad7ecd249a16fa806/frozenlist-1.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4e0c11f2cc6717e0a741f84a527c52616140741cd812a50422f83dc31749fb52", size = 51725, upload-time = "2025-10-06T05:36:50.851Z" }, + { url = "https://files.pythonhosted.org/packages/bc/71/d1fed0ffe2c2ccd70b43714c6cab0f4188f09f8a67a7914a6b46ee30f274/frozenlist-1.8.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b3210649ee28062ea6099cfda39e147fa1bc039583c8ee4481cb7811e2448c51", size = 284533, upload-time = "2025-10-06T05:36:51.898Z" }, + { url = "https://files.pythonhosted.org/packages/c9/1f/fb1685a7b009d89f9bf78a42d94461bc06581f6e718c39344754a5d9bada/frozenlist-1.8.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:581ef5194c48035a7de2aefc72ac6539823bb71508189e5de01d60c9dcd5fa65", size = 292506, upload-time = "2025-10-06T05:36:53.101Z" }, + { url = "https://files.pythonhosted.org/packages/e6/3b/b991fe1612703f7e0d05c0cf734c1b77aaf7c7d321df4572e8d36e7048c8/frozenlist-1.8.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3ef2d026f16a2b1866e1d86fc4e1291e1ed8a387b2c333809419a2f8b3a77b82", size = 274161, upload-time = "2025-10-06T05:36:54.309Z" }, + { url = "https://files.pythonhosted.org/packages/ca/ec/c5c618767bcdf66e88945ec0157d7f6c4a1322f1473392319b7a2501ded7/frozenlist-1.8.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5500ef82073f599ac84d888e3a8c1f77ac831183244bfd7f11eaa0289fb30714", size = 294676, upload-time = "2025-10-06T05:36:55.566Z" }, + { url = "https://files.pythonhosted.org/packages/7c/ce/3934758637d8f8a88d11f0585d6495ef54b2044ed6ec84492a91fa3b27aa/frozenlist-1.8.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50066c3997d0091c411a66e710f4e11752251e6d2d73d70d8d5d4c76442a199d", size = 300638, upload-time = "2025-10-06T05:36:56.758Z" }, + { url = "https://files.pythonhosted.org/packages/fc/4f/a7e4d0d467298f42de4b41cbc7ddaf19d3cfeabaf9ff97c20c6c7ee409f9/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5c1c8e78426e59b3f8005e9b19f6ff46e5845895adbde20ece9218319eca6506", size = 283067, upload-time = "2025-10-06T05:36:57.965Z" }, + { url = "https://files.pythonhosted.org/packages/dc/48/c7b163063d55a83772b268e6d1affb960771b0e203b632cfe09522d67ea5/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:eefdba20de0d938cec6a89bd4d70f346a03108a19b9df4248d3cf0d88f1b0f51", size = 292101, upload-time = "2025-10-06T05:36:59.237Z" }, + { url = "https://files.pythonhosted.org/packages/9f/d0/2366d3c4ecdc2fd391e0afa6e11500bfba0ea772764d631bbf82f0136c9d/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cf253e0e1c3ceb4aaff6df637ce033ff6535fb8c70a764a8f46aafd3d6ab798e", size = 289901, upload-time = "2025-10-06T05:37:00.811Z" }, + { url = "https://files.pythonhosted.org/packages/b8/94/daff920e82c1b70e3618a2ac39fbc01ae3e2ff6124e80739ce5d71c9b920/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:032efa2674356903cd0261c4317a561a6850f3ac864a63fc1583147fb05a79b0", size = 289395, upload-time = "2025-10-06T05:37:02.115Z" }, + { url = "https://files.pythonhosted.org/packages/e3/20/bba307ab4235a09fdcd3cc5508dbabd17c4634a1af4b96e0f69bfe551ebd/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6da155091429aeba16851ecb10a9104a108bcd32f6c1642867eadaee401c1c41", size = 283659, upload-time = "2025-10-06T05:37:03.711Z" }, + { url = "https://files.pythonhosted.org/packages/fd/00/04ca1c3a7a124b6de4f8a9a17cc2fcad138b4608e7a3fc5877804b8715d7/frozenlist-1.8.0-cp313-cp313t-win32.whl", hash = "sha256:0f96534f8bfebc1a394209427d0f8a63d343c9779cda6fc25e8e121b5fd8555b", size = 43492, upload-time = "2025-10-06T05:37:04.915Z" }, + { url = "https://files.pythonhosted.org/packages/59/5e/c69f733a86a94ab10f68e496dc6b7e8bc078ebb415281d5698313e3af3a1/frozenlist-1.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5d63a068f978fc69421fb0e6eb91a9603187527c86b7cd3f534a5b77a592b888", size = 48034, upload-time = "2025-10-06T05:37:06.343Z" }, + { url = "https://files.pythonhosted.org/packages/16/6c/be9d79775d8abe79b05fa6d23da99ad6e7763a1d080fbae7290b286093fd/frozenlist-1.8.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bf0a7e10b077bf5fb9380ad3ae8ce20ef919a6ad93b4552896419ac7e1d8e042", size = 41749, upload-time = "2025-10-06T05:37:07.431Z" }, + { url = "https://files.pythonhosted.org/packages/f1/c8/85da824b7e7b9b6e7f7705b2ecaf9591ba6f79c1177f324c2735e41d36a2/frozenlist-1.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cee686f1f4cadeb2136007ddedd0aaf928ab95216e7691c63e50a8ec066336d0", size = 86127, upload-time = "2025-10-06T05:37:08.438Z" }, + { url = "https://files.pythonhosted.org/packages/8e/e8/a1185e236ec66c20afd72399522f142c3724c785789255202d27ae992818/frozenlist-1.8.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:119fb2a1bd47307e899c2fac7f28e85b9a543864df47aa7ec9d3c1b4545f096f", size = 49698, upload-time = "2025-10-06T05:37:09.48Z" }, + { url = "https://files.pythonhosted.org/packages/a1/93/72b1736d68f03fda5fdf0f2180fb6caaae3894f1b854d006ac61ecc727ee/frozenlist-1.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4970ece02dbc8c3a92fcc5228e36a3e933a01a999f7094ff7c23fbd2beeaa67c", size = 49749, upload-time = "2025-10-06T05:37:10.569Z" }, + { url = "https://files.pythonhosted.org/packages/a7/b2/fabede9fafd976b991e9f1b9c8c873ed86f202889b864756f240ce6dd855/frozenlist-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:cba69cb73723c3f329622e34bdbf5ce1f80c21c290ff04256cff1cd3c2036ed2", size = 231298, upload-time = "2025-10-06T05:37:11.993Z" }, + { url = "https://files.pythonhosted.org/packages/3a/3b/d9b1e0b0eed36e70477ffb8360c49c85c8ca8ef9700a4e6711f39a6e8b45/frozenlist-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:778a11b15673f6f1df23d9586f83c4846c471a8af693a22e066508b77d201ec8", size = 232015, upload-time = "2025-10-06T05:37:13.194Z" }, + { url = "https://files.pythonhosted.org/packages/dc/94/be719d2766c1138148564a3960fc2c06eb688da592bdc25adcf856101be7/frozenlist-1.8.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0325024fe97f94c41c08872db482cf8ac4800d80e79222c6b0b7b162d5b13686", size = 225038, upload-time = "2025-10-06T05:37:14.577Z" }, + { url = "https://files.pythonhosted.org/packages/e4/09/6712b6c5465f083f52f50cf74167b92d4ea2f50e46a9eea0523d658454ae/frozenlist-1.8.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:97260ff46b207a82a7567b581ab4190bd4dfa09f4db8a8b49d1a958f6aa4940e", size = 240130, upload-time = "2025-10-06T05:37:15.781Z" }, + { url = "https://files.pythonhosted.org/packages/f8/d4/cd065cdcf21550b54f3ce6a22e143ac9e4836ca42a0de1022da8498eac89/frozenlist-1.8.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:54b2077180eb7f83dd52c40b2750d0a9f175e06a42e3213ce047219de902717a", size = 242845, upload-time = "2025-10-06T05:37:17.037Z" }, + { url = "https://files.pythonhosted.org/packages/62/c3/f57a5c8c70cd1ead3d5d5f776f89d33110b1addae0ab010ad774d9a44fb9/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2f05983daecab868a31e1da44462873306d3cbfd76d1f0b5b69c473d21dbb128", size = 229131, upload-time = "2025-10-06T05:37:18.221Z" }, + { url = "https://files.pythonhosted.org/packages/6c/52/232476fe9cb64f0742f3fde2b7d26c1dac18b6d62071c74d4ded55e0ef94/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:33f48f51a446114bc5d251fb2954ab0164d5be02ad3382abcbfe07e2531d650f", size = 240542, upload-time = "2025-10-06T05:37:19.771Z" }, + { url = "https://files.pythonhosted.org/packages/5f/85/07bf3f5d0fb5414aee5f47d33c6f5c77bfe49aac680bfece33d4fdf6a246/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:154e55ec0655291b5dd1b8731c637ecdb50975a2ae70c606d100750a540082f7", size = 237308, upload-time = "2025-10-06T05:37:20.969Z" }, + { url = "https://files.pythonhosted.org/packages/11/99/ae3a33d5befd41ac0ca2cc7fd3aa707c9c324de2e89db0e0f45db9a64c26/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:4314debad13beb564b708b4a496020e5306c7333fa9a3ab90374169a20ffab30", size = 238210, upload-time = "2025-10-06T05:37:22.252Z" }, + { url = "https://files.pythonhosted.org/packages/b2/60/b1d2da22f4970e7a155f0adde9b1435712ece01b3cd45ba63702aea33938/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:073f8bf8becba60aa931eb3bc420b217bb7d5b8f4750e6f8b3be7f3da85d38b7", size = 231972, upload-time = "2025-10-06T05:37:23.5Z" }, + { url = "https://files.pythonhosted.org/packages/3f/ab/945b2f32de889993b9c9133216c068b7fcf257d8595a0ac420ac8677cab0/frozenlist-1.8.0-cp314-cp314-win32.whl", hash = "sha256:bac9c42ba2ac65ddc115d930c78d24ab8d4f465fd3fc473cdedfccadb9429806", size = 40536, upload-time = "2025-10-06T05:37:25.581Z" }, + { url = "https://files.pythonhosted.org/packages/59/ad/9caa9b9c836d9ad6f067157a531ac48b7d36499f5036d4141ce78c230b1b/frozenlist-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:3e0761f4d1a44f1d1a47996511752cf3dcec5bbdd9cc2b4fe595caf97754b7a0", size = 44330, upload-time = "2025-10-06T05:37:26.928Z" }, + { url = "https://files.pythonhosted.org/packages/82/13/e6950121764f2676f43534c555249f57030150260aee9dcf7d64efda11dd/frozenlist-1.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:d1eaff1d00c7751b7c6662e9c5ba6eb2c17a2306ba5e2a37f24ddf3cc953402b", size = 40627, upload-time = "2025-10-06T05:37:28.075Z" }, + { url = "https://files.pythonhosted.org/packages/c0/c7/43200656ecc4e02d3f8bc248df68256cd9572b3f0017f0a0c4e93440ae23/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d3bb933317c52d7ea5004a1c442eef86f426886fba134ef8cf4226ea6ee1821d", size = 89238, upload-time = "2025-10-06T05:37:29.373Z" }, + { url = "https://files.pythonhosted.org/packages/d1/29/55c5f0689b9c0fb765055629f472c0de484dcaf0acee2f7707266ae3583c/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8009897cdef112072f93a0efdce29cd819e717fd2f649ee3016efd3cd885a7ed", size = 50738, upload-time = "2025-10-06T05:37:30.792Z" }, + { url = "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2c5dcbbc55383e5883246d11fd179782a9d07a986c40f49abe89ddf865913930", size = 51739, upload-time = "2025-10-06T05:37:32.127Z" }, + { url = "https://files.pythonhosted.org/packages/62/1c/3d8622e60d0b767a5510d1d3cf21065b9db874696a51ea6d7a43180a259c/frozenlist-1.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:39ecbc32f1390387d2aa4f5a995e465e9e2f79ba3adcac92d68e3e0afae6657c", size = 284186, upload-time = "2025-10-06T05:37:33.21Z" }, + { url = "https://files.pythonhosted.org/packages/2d/14/aa36d5f85a89679a85a1d44cd7a6657e0b1c75f61e7cad987b203d2daca8/frozenlist-1.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92db2bf818d5cc8d9c1f1fc56b897662e24ea5adb36ad1f1d82875bd64e03c24", size = 292196, upload-time = "2025-10-06T05:37:36.107Z" }, + { url = "https://files.pythonhosted.org/packages/05/23/6bde59eb55abd407d34f77d39a5126fb7b4f109a3f611d3929f14b700c66/frozenlist-1.8.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dc43a022e555de94c3b68a4ef0b11c4f747d12c024a520c7101709a2144fb37", size = 273830, upload-time = "2025-10-06T05:37:37.663Z" }, + { url = "https://files.pythonhosted.org/packages/d2/3f/22cff331bfad7a8afa616289000ba793347fcd7bc275f3b28ecea2a27909/frozenlist-1.8.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb89a7f2de3602cfed448095bab3f178399646ab7c61454315089787df07733a", size = 294289, upload-time = "2025-10-06T05:37:39.261Z" }, + { url = "https://files.pythonhosted.org/packages/a4/89/5b057c799de4838b6c69aa82b79705f2027615e01be996d2486a69ca99c4/frozenlist-1.8.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:33139dc858c580ea50e7e60a1b0ea003efa1fd42e6ec7fdbad78fff65fad2fd2", size = 300318, upload-time = "2025-10-06T05:37:43.213Z" }, + { url = "https://files.pythonhosted.org/packages/30/de/2c22ab3eb2a8af6d69dc799e48455813bab3690c760de58e1bf43b36da3e/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:168c0969a329b416119507ba30b9ea13688fafffac1b7822802537569a1cb0ef", size = 282814, upload-time = "2025-10-06T05:37:45.337Z" }, + { url = "https://files.pythonhosted.org/packages/59/f7/970141a6a8dbd7f556d94977858cfb36fa9b66e0892c6dd780d2219d8cd8/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:28bd570e8e189d7f7b001966435f9dac6718324b5be2990ac496cf1ea9ddb7fe", size = 291762, upload-time = "2025-10-06T05:37:46.657Z" }, + { url = "https://files.pythonhosted.org/packages/c1/15/ca1adae83a719f82df9116d66f5bb28bb95557b3951903d39135620ef157/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b2a095d45c5d46e5e79ba1e5b9cb787f541a8dee0433836cea4b96a2c439dcd8", size = 289470, upload-time = "2025-10-06T05:37:47.946Z" }, + { url = "https://files.pythonhosted.org/packages/ac/83/dca6dc53bf657d371fbc88ddeb21b79891e747189c5de990b9dfff2ccba1/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:eab8145831a0d56ec9c4139b6c3e594c7a83c2c8be25d5bcf2d86136a532287a", size = 289042, upload-time = "2025-10-06T05:37:49.499Z" }, + { url = "https://files.pythonhosted.org/packages/96/52/abddd34ca99be142f354398700536c5bd315880ed0a213812bc491cff5e4/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:974b28cf63cc99dfb2188d8d222bc6843656188164848c4f679e63dae4b0708e", size = 283148, upload-time = "2025-10-06T05:37:50.745Z" }, + { url = "https://files.pythonhosted.org/packages/af/d3/76bd4ed4317e7119c2b7f57c3f6934aba26d277acc6309f873341640e21f/frozenlist-1.8.0-cp314-cp314t-win32.whl", hash = "sha256:342c97bf697ac5480c0a7ec73cd700ecfa5a8a40ac923bd035484616efecc2df", size = 44676, upload-time = "2025-10-06T05:37:52.222Z" }, + { url = "https://files.pythonhosted.org/packages/89/76/c615883b7b521ead2944bb3480398cbb07e12b7b4e4d073d3752eb721558/frozenlist-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:06be8f67f39c8b1dc671f5d83aaefd3358ae5cdcf8314552c57e7ed3e6475bdd", size = 49451, upload-time = "2025-10-06T05:37:53.425Z" }, + { url = "https://files.pythonhosted.org/packages/e0/a3/5982da14e113d07b325230f95060e2169f5311b1017ea8af2a29b374c289/frozenlist-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:102e6314ca4da683dca92e3b1355490fed5f313b768500084fbe6371fddfdb79", size = 42507, upload-time = "2025-10-06T05:37:54.513Z" }, + { url = "https://files.pythonhosted.org/packages/c2/59/ae5cdac87a00962122ea37bb346d41b66aec05f9ce328fa2b9e216f8967b/frozenlist-1.8.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d8b7138e5cd0647e4523d6685b0eac5d4be9a184ae9634492f25c6eb38c12a47", size = 86967, upload-time = "2025-10-06T05:37:55.607Z" }, + { url = "https://files.pythonhosted.org/packages/8a/10/17059b2db5a032fd9323c41c39e9d1f5f9d0c8f04d1e4e3e788573086e61/frozenlist-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a6483e309ca809f1efd154b4d37dc6d9f61037d6c6a81c2dc7a15cb22c8c5dca", size = 49984, upload-time = "2025-10-06T05:37:57.049Z" }, + { url = "https://files.pythonhosted.org/packages/4b/de/ad9d82ca8e5fa8f0c636e64606553c79e2b859ad253030b62a21fe9986f5/frozenlist-1.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1b9290cf81e95e93fdf90548ce9d3c1211cf574b8e3f4b3b7cb0537cf2227068", size = 50240, upload-time = "2025-10-06T05:37:58.145Z" }, + { url = "https://files.pythonhosted.org/packages/4e/45/3dfb7767c2a67d123650122b62ce13c731b6c745bc14424eea67678b508c/frozenlist-1.8.0-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:59a6a5876ca59d1b63af8cd5e7ffffb024c3dc1e9cf9301b21a2e76286505c95", size = 219472, upload-time = "2025-10-06T05:37:59.239Z" }, + { url = "https://files.pythonhosted.org/packages/0b/bf/5bf23d913a741b960d5c1dac7c1985d8a2a1d015772b2d18ea168b08e7ff/frozenlist-1.8.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6dc4126390929823e2d2d9dc79ab4046ed74680360fc5f38b585c12c66cdf459", size = 221531, upload-time = "2025-10-06T05:38:00.521Z" }, + { url = "https://files.pythonhosted.org/packages/d0/03/27ec393f3b55860859f4b74cdc8c2a4af3dbf3533305e8eacf48a4fd9a54/frozenlist-1.8.0-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:332db6b2563333c5671fecacd085141b5800cb866be16d5e3eb15a2086476675", size = 219211, upload-time = "2025-10-06T05:38:01.842Z" }, + { url = "https://files.pythonhosted.org/packages/3a/ad/0fd00c404fa73fe9b169429e9a972d5ed807973c40ab6b3cf9365a33d360/frozenlist-1.8.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9ff15928d62a0b80bb875655c39bf517938c7d589554cbd2669be42d97c2cb61", size = 231775, upload-time = "2025-10-06T05:38:03.384Z" }, + { url = "https://files.pythonhosted.org/packages/8a/c3/86962566154cb4d2995358bc8331bfc4ea19d07db1a96f64935a1607f2b6/frozenlist-1.8.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7bf6cdf8e07c8151fba6fe85735441240ec7f619f935a5205953d58009aef8c6", size = 236631, upload-time = "2025-10-06T05:38:04.609Z" }, + { url = "https://files.pythonhosted.org/packages/ea/9e/6ffad161dbd83782d2c66dc4d378a9103b31770cb1e67febf43aea42d202/frozenlist-1.8.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:48e6d3f4ec5c7273dfe83ff27c91083c6c9065af655dc2684d2c200c94308bb5", size = 218632, upload-time = "2025-10-06T05:38:05.917Z" }, + { url = "https://files.pythonhosted.org/packages/58/b2/4677eee46e0a97f9b30735e6ad0bf6aba3e497986066eb68807ac85cf60f/frozenlist-1.8.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:1a7607e17ad33361677adcd1443edf6f5da0ce5e5377b798fba20fae194825f3", size = 235967, upload-time = "2025-10-06T05:38:07.614Z" }, + { url = "https://files.pythonhosted.org/packages/05/f3/86e75f8639c5a93745ca7addbbc9de6af56aebb930d233512b17e46f6493/frozenlist-1.8.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:5a3a935c3a4e89c733303a2d5a7c257ea44af3a56c8202df486b7f5de40f37e1", size = 228799, upload-time = "2025-10-06T05:38:08.845Z" }, + { url = "https://files.pythonhosted.org/packages/30/00/39aad3a7f0d98f5eb1d99a3c311215674ed87061aecee7851974b335c050/frozenlist-1.8.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:940d4a017dbfed9daf46a3b086e1d2167e7012ee297fef9e1c545c4d022f5178", size = 230566, upload-time = "2025-10-06T05:38:10.52Z" }, + { url = "https://files.pythonhosted.org/packages/0d/4d/aa144cac44568d137846ddc4d5210fb5d9719eb1d7ec6fa2728a54b5b94a/frozenlist-1.8.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b9be22a69a014bc47e78072d0ecae716f5eb56c15238acca0f43d6eb8e4a5bda", size = 217715, upload-time = "2025-10-06T05:38:11.832Z" }, + { url = "https://files.pythonhosted.org/packages/64/4c/8f665921667509d25a0dd72540513bc86b356c95541686f6442a3283019f/frozenlist-1.8.0-cp39-cp39-win32.whl", hash = "sha256:1aa77cb5697069af47472e39612976ed05343ff2e84a3dcf15437b232cbfd087", size = 39933, upload-time = "2025-10-06T05:38:13.061Z" }, + { url = "https://files.pythonhosted.org/packages/79/bd/bcc926f87027fad5e59926ff12d136e1082a115025d33c032d1cd69ab377/frozenlist-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:7398c222d1d405e796970320036b1b563892b65809d9e5261487bb2c7f7b5c6a", size = 44121, upload-time = "2025-10-06T05:38:14.572Z" }, + { url = "https://files.pythonhosted.org/packages/4c/07/9c2e4eb7584af4b705237b971b89a4155a8e57599c4483a131a39256a9a0/frozenlist-1.8.0-cp39-cp39-win_arm64.whl", hash = "sha256:b4f3b365f31c6cd4af24545ca0a244a53688cad8834e32f56831c4923b50a103", size = 40312, upload-time = "2025-10-06T05:38:15.699Z" }, + { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409, upload-time = "2025-10-06T05:38:16.721Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, +] + +[[package]] +name = "httpx" +version = "0.28.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio", version = "4.12.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "anyio", version = "4.13.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, +] + +[[package]] +name = "httpx-aiohttp" +version = "0.1.12" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp" }, + { name = "httpx" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/63/2c/b894861cecf030fb45675ea24aa55b5722e97c602a163d872fca66c5a6d8/httpx_aiohttp-0.1.12.tar.gz", hash = "sha256:81feec51fd82c0ecfa0e9aaf1b1a6c2591260d5e2bcbeb7eb0277a78e610df2c", size = 275945, upload-time = "2025-12-12T10:12:15.283Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/16/8d/85c9701e9af72ca132a1783e2a54364a90c6da832304416a30fc11196ab2/httpx_aiohttp-0.1.12-py3-none-any.whl", hash = "sha256:5b0eac39a7f360fa7867a60bcb46bb1024eada9c01cbfecdb54dc1edb3fb7141", size = 6367, upload-time = "2025-12-12T10:12:14.018Z" }, +] + +[[package]] +name = "idna" +version = "3.13" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ce/cc/762dfb036166873f0059f3b7de4565e1b5bc3d6f28a414c13da27e442f99/idna-3.13.tar.gz", hash = "sha256:585ea8fe5d69b9181ec1afba340451fba6ba764af97026f92a91d4eef164a242", size = 194210, upload-time = "2026-04-22T16:42:42.314Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/13/ad7d7ca3808a898b4612b6fe93cde56b53f3034dcde235acb1f0e1df24c6/idna-3.13-py3-none-any.whl", hash = "sha256:892ea0cde124a99ce773decba204c5552b69c3c67ffd5f232eb7696135bc8bb3", size = 68629, upload-time = "2026-04-22T16:42:40.909Z" }, +] + +[[package]] +name = "multidict" +version = "6.7.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1a/c2/c2d94cbe6ac1753f3fc980da97b3d930efe1da3af3c9f5125354436c073d/multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d", size = 102010, upload-time = "2026-01-26T02:46:45.979Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/0b/19348d4c98980c4851d2f943f8ebafdece2ae7ef737adcfa5994ce8e5f10/multidict-6.7.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c93c3db7ea657dd4637d57e74ab73de31bccefe144d3d4ce370052035bc85fb5", size = 77176, upload-time = "2026-01-26T02:42:59.784Z" }, + { url = "https://files.pythonhosted.org/packages/ef/04/9de3f8077852e3d438215c81e9b691244532d2e05b4270e89ce67b7d103c/multidict-6.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:974e72a2474600827abaeda71af0c53d9ebbc3c2eb7da37b37d7829ae31232d8", size = 44996, upload-time = "2026-01-26T02:43:01.674Z" }, + { url = "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cdea2e7b2456cfb6694fb113066fd0ec7ea4d67e3a35e1f4cbeea0b448bf5872", size = 44631, upload-time = "2026-01-26T02:43:03.169Z" }, + { url = "https://files.pythonhosted.org/packages/b7/7f/0e3b1390ae772f27501199996b94b52ceeb64fe6f9120a32c6c3f6b781be/multidict-6.7.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17207077e29342fdc2c9a82e4b306f1127bf1ea91f8b71e02d4798a70bb99991", size = 242561, upload-time = "2026-01-26T02:43:04.733Z" }, + { url = "https://files.pythonhosted.org/packages/dd/f4/8719f4f167586af317b69dd3e90f913416c91ca610cac79a45c53f590312/multidict-6.7.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4f49cb5661344764e4c7c7973e92a47a59b8fc19b6523649ec9dc4960e58a03", size = 242223, upload-time = "2026-01-26T02:43:06.695Z" }, + { url = "https://files.pythonhosted.org/packages/47/ab/7c36164cce64a6ad19c6d9a85377b7178ecf3b89f8fd589c73381a5eedfd/multidict-6.7.1-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a9fc4caa29e2e6ae408d1c450ac8bf19892c5fca83ee634ecd88a53332c59981", size = 222322, upload-time = "2026-01-26T02:43:08.472Z" }, + { url = "https://files.pythonhosted.org/packages/f5/79/a25add6fb38035b5337bc5734f296d9afc99163403bbcf56d4170f97eb62/multidict-6.7.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c5f0c21549ab432b57dcc82130f388d84ad8179824cc3f223d5e7cfbfd4143f6", size = 254005, upload-time = "2026-01-26T02:43:10.127Z" }, + { url = "https://files.pythonhosted.org/packages/4a/7b/64a87cf98e12f756fc8bd444b001232ffff2be37288f018ad0d3f0aae931/multidict-6.7.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7dfb78d966b2c906ae1d28ccf6e6712a3cd04407ee5088cd276fe8cb42186190", size = 251173, upload-time = "2026-01-26T02:43:11.731Z" }, + { url = "https://files.pythonhosted.org/packages/4b/ac/b605473de2bb404e742f2cc3583d12aedb2352a70e49ae8fce455b50c5aa/multidict-6.7.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9b0d9b91d1aa44db9c1f1ecd0d9d2ae610b2f4f856448664e01a3b35899f3f92", size = 243273, upload-time = "2026-01-26T02:43:13.063Z" }, + { url = "https://files.pythonhosted.org/packages/03/65/11492d6a0e259783720f3bc1d9ea55579a76f1407e31ed44045c99542004/multidict-6.7.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dd96c01a9dcd4889dcfcf9eb5544ca0c77603f239e3ffab0524ec17aea9a93ee", size = 238956, upload-time = "2026-01-26T02:43:14.843Z" }, + { url = "https://files.pythonhosted.org/packages/5f/a7/7ee591302af64e7c196fb63fe856c788993c1372df765102bd0448e7e165/multidict-6.7.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:067343c68cd6612d375710f895337b3a98a033c94f14b9a99eff902f205424e2", size = 233477, upload-time = "2026-01-26T02:43:16.025Z" }, + { url = "https://files.pythonhosted.org/packages/9c/99/c109962d58756c35fd9992fed7f2355303846ea2ff054bb5f5e9d6b888de/multidict-6.7.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5884a04f4ff56c6120f6ccf703bdeb8b5079d808ba604d4d53aec0d55dc33568", size = 243615, upload-time = "2026-01-26T02:43:17.84Z" }, + { url = "https://files.pythonhosted.org/packages/d5/5f/1973e7c771c86e93dcfe1c9cc55a5481b610f6614acfc28c0d326fe6bfad/multidict-6.7.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8affcf1c98b82bc901702eb73b6947a1bfa170823c153fe8a47b5f5f02e48e40", size = 249930, upload-time = "2026-01-26T02:43:19.06Z" }, + { url = "https://files.pythonhosted.org/packages/5d/a5/f170fc2268c3243853580203378cd522446b2df632061e0a5409817854c7/multidict-6.7.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:0d17522c37d03e85c8098ec8431636309b2682cf12e58f4dbc76121fb50e4962", size = 243807, upload-time = "2026-01-26T02:43:20.286Z" }, + { url = "https://files.pythonhosted.org/packages/de/01/73856fab6d125e5bc652c3986b90e8699a95e84b48d72f39ade6c0e74a8c/multidict-6.7.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:24c0cf81544ca5e17cfcb6e482e7a82cd475925242b308b890c9452a074d4505", size = 239103, upload-time = "2026-01-26T02:43:21.508Z" }, + { url = "https://files.pythonhosted.org/packages/e7/46/f1220bd9944d8aa40d8ccff100eeeee19b505b857b6f603d6078cb5315b0/multidict-6.7.1-cp310-cp310-win32.whl", hash = "sha256:d82dd730a95e6643802f4454b8fdecdf08667881a9c5670db85bc5a56693f122", size = 41416, upload-time = "2026-01-26T02:43:22.703Z" }, + { url = "https://files.pythonhosted.org/packages/68/00/9b38e272a770303692fc406c36e1a4c740f401522d5787691eb38a8925a8/multidict-6.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:cf37cbe5ced48d417ba045aca1b21bafca67489452debcde94778a576666a1df", size = 46022, upload-time = "2026-01-26T02:43:23.77Z" }, + { url = "https://files.pythonhosted.org/packages/64/65/d8d42490c02ee07b6bbe00f7190d70bb4738b3cce7629aaf9f213ef730dd/multidict-6.7.1-cp310-cp310-win_arm64.whl", hash = "sha256:59bc83d3f66b41dac1e7460aac1d196edc70c9ba3094965c467715a70ecb46db", size = 43238, upload-time = "2026-01-26T02:43:24.882Z" }, + { url = "https://files.pythonhosted.org/packages/ce/f1/a90635c4f88fb913fbf4ce660b83b7445b7a02615bda034b2f8eb38fd597/multidict-6.7.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7ff981b266af91d7b4b3793ca3382e53229088d193a85dfad6f5f4c27fc73e5d", size = 76626, upload-time = "2026-01-26T02:43:26.485Z" }, + { url = "https://files.pythonhosted.org/packages/a6/9b/267e64eaf6fc637a15b35f5de31a566634a2740f97d8d094a69d34f524a4/multidict-6.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:844c5bca0b5444adb44a623fb0a1310c2f4cd41f402126bb269cd44c9b3f3e1e", size = 44706, upload-time = "2026-01-26T02:43:27.607Z" }, + { url = "https://files.pythonhosted.org/packages/dd/a4/d45caf2b97b035c57267791ecfaafbd59c68212004b3842830954bb4b02e/multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f2a0a924d4c2e9afcd7ec64f9de35fcd96915149b2216e1cb2c10a56df483855", size = 44356, upload-time = "2026-01-26T02:43:28.661Z" }, + { url = "https://files.pythonhosted.org/packages/fd/d2/0a36c8473f0cbaeadd5db6c8b72d15bbceeec275807772bfcd059bef487d/multidict-6.7.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8be1802715a8e892c784c0197c2ace276ea52702a0ede98b6310c8f255a5afb3", size = 244355, upload-time = "2026-01-26T02:43:31.165Z" }, + { url = "https://files.pythonhosted.org/packages/5d/16/8c65be997fd7dd311b7d39c7b6e71a0cb449bad093761481eccbbe4b42a2/multidict-6.7.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2e2d2ed645ea29f31c4c7ea1552fcfd7cb7ba656e1eafd4134a6620c9f5fdd9e", size = 246433, upload-time = "2026-01-26T02:43:32.581Z" }, + { url = "https://files.pythonhosted.org/packages/01/fb/4dbd7e848d2799c6a026ec88ad39cf2b8416aa167fcc903baa55ecaa045c/multidict-6.7.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:95922cee9a778659e91db6497596435777bd25ed116701a4c034f8e46544955a", size = 225376, upload-time = "2026-01-26T02:43:34.417Z" }, + { url = "https://files.pythonhosted.org/packages/b6/8a/4a3a6341eac3830f6053062f8fbc9a9e54407c80755b3f05bc427295c2d0/multidict-6.7.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6b83cabdc375ffaaa15edd97eb7c0c672ad788e2687004990074d7d6c9b140c8", size = 257365, upload-time = "2026-01-26T02:43:35.741Z" }, + { url = "https://files.pythonhosted.org/packages/f7/a2/dd575a69c1aa206e12d27d0770cdf9b92434b48a9ef0cd0d1afdecaa93c4/multidict-6.7.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:38fb49540705369bab8484db0689d86c0a33a0a9f2c1b197f506b71b4b6c19b0", size = 254747, upload-time = "2026-01-26T02:43:36.976Z" }, + { url = "https://files.pythonhosted.org/packages/5a/56/21b27c560c13822ed93133f08aa6372c53a8e067f11fbed37b4adcdac922/multidict-6.7.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:439cbebd499f92e9aa6793016a8acaa161dfa749ae86d20960189f5398a19144", size = 246293, upload-time = "2026-01-26T02:43:38.258Z" }, + { url = "https://files.pythonhosted.org/packages/5a/a4/23466059dc3854763423d0ad6c0f3683a379d97673b1b89ec33826e46728/multidict-6.7.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6d3bc717b6fe763b8be3f2bee2701d3c8eb1b2a8ae9f60910f1b2860c82b6c49", size = 242962, upload-time = "2026-01-26T02:43:40.034Z" }, + { url = "https://files.pythonhosted.org/packages/1f/67/51dd754a3524d685958001e8fa20a0f5f90a6a856e0a9dcabff69be3dbb7/multidict-6.7.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:619e5a1ac57986dbfec9f0b301d865dddf763696435e2962f6d9cf2fdff2bb71", size = 237360, upload-time = "2026-01-26T02:43:41.752Z" }, + { url = "https://files.pythonhosted.org/packages/64/3f/036dfc8c174934d4b55d86ff4f978e558b0e585cef70cfc1ad01adc6bf18/multidict-6.7.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0b38ebffd9be37c1170d33bc0f36f4f262e0a09bc1aac1c34c7aa51a7293f0b3", size = 245940, upload-time = "2026-01-26T02:43:43.042Z" }, + { url = "https://files.pythonhosted.org/packages/3d/20/6214d3c105928ebc353a1c644a6ef1408bc5794fcb4f170bb524a3c16311/multidict-6.7.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:10ae39c9cfe6adedcdb764f5e8411d4a92b055e35573a2eaa88d3323289ef93c", size = 253502, upload-time = "2026-01-26T02:43:44.371Z" }, + { url = "https://files.pythonhosted.org/packages/b1/e2/c653bc4ae1be70a0f836b82172d643fcf1dade042ba2676ab08ec08bff0f/multidict-6.7.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:25167cc263257660290fba06b9318d2026e3c910be240a146e1f66dd114af2b0", size = 247065, upload-time = "2026-01-26T02:43:45.745Z" }, + { url = "https://files.pythonhosted.org/packages/c8/11/a854b4154cd3bd8b1fd375e8a8ca9d73be37610c361543d56f764109509b/multidict-6.7.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:128441d052254f42989ef98b7b6a6ecb1e6f708aa962c7984235316db59f50fa", size = 241870, upload-time = "2026-01-26T02:43:47.054Z" }, + { url = "https://files.pythonhosted.org/packages/13/bf/9676c0392309b5fdae322333d22a829715b570edb9baa8016a517b55b558/multidict-6.7.1-cp311-cp311-win32.whl", hash = "sha256:d62b7f64ffde3b99d06b707a280db04fb3855b55f5a06df387236051d0668f4a", size = 41302, upload-time = "2026-01-26T02:43:48.753Z" }, + { url = "https://files.pythonhosted.org/packages/c9/68/f16a3a8ba6f7b6dc92a1f19669c0810bd2c43fc5a02da13b1cbf8e253845/multidict-6.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:bdbf9f3b332abd0cdb306e7c2113818ab1e922dc84b8f8fd06ec89ed2a19ab8b", size = 45981, upload-time = "2026-01-26T02:43:49.921Z" }, + { url = "https://files.pythonhosted.org/packages/ac/ad/9dd5305253fa00cd3c7555dbef69d5bf4133debc53b87ab8d6a44d411665/multidict-6.7.1-cp311-cp311-win_arm64.whl", hash = "sha256:b8c990b037d2fff2f4e33d3f21b9b531c5745b33a49a7d6dbe7a177266af44f6", size = 43159, upload-time = "2026-01-26T02:43:51.635Z" }, + { url = "https://files.pythonhosted.org/packages/8d/9c/f20e0e2cf80e4b2e4b1c365bf5fe104ee633c751a724246262db8f1a0b13/multidict-6.7.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a90f75c956e32891a4eda3639ce6dd86e87105271f43d43442a3aedf3cddf172", size = 76893, upload-time = "2026-01-26T02:43:52.754Z" }, + { url = "https://files.pythonhosted.org/packages/fe/cf/18ef143a81610136d3da8193da9d80bfe1cb548a1e2d1c775f26b23d024a/multidict-6.7.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fccb473e87eaa1382689053e4a4618e7ba7b9b9b8d6adf2027ee474597128cd", size = 45456, upload-time = "2026-01-26T02:43:53.893Z" }, + { url = "https://files.pythonhosted.org/packages/a9/65/1caac9d4cd32e8433908683446eebc953e82d22b03d10d41a5f0fefe991b/multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0fa96985700739c4c7853a43c0b3e169360d6855780021bfc6d0f1ce7c123e7", size = 43872, upload-time = "2026-01-26T02:43:55.041Z" }, + { url = "https://files.pythonhosted.org/packages/cf/3b/d6bd75dc4f3ff7c73766e04e705b00ed6dbbaccf670d9e05a12b006f5a21/multidict-6.7.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cb2a55f408c3043e42b40cc8eecd575afa27b7e0b956dfb190de0f8499a57a53", size = 251018, upload-time = "2026-01-26T02:43:56.198Z" }, + { url = "https://files.pythonhosted.org/packages/fd/80/c959c5933adedb9ac15152e4067c702a808ea183a8b64cf8f31af8ad3155/multidict-6.7.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb0ce7b2a32d09892b3dd6cc44877a0d02a33241fafca5f25c8b6b62374f8b75", size = 258883, upload-time = "2026-01-26T02:43:57.499Z" }, + { url = "https://files.pythonhosted.org/packages/86/85/7ed40adafea3d4f1c8b916e3b5cc3a8e07dfcdcb9cd72800f4ed3ca1b387/multidict-6.7.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c3a32d23520ee37bf327d1e1a656fec76a2edd5c038bf43eddfa0572ec49c60b", size = 242413, upload-time = "2026-01-26T02:43:58.755Z" }, + { url = "https://files.pythonhosted.org/packages/d2/57/b8565ff533e48595503c785f8361ff9a4fde4d67de25c207cd0ba3befd03/multidict-6.7.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9c90fed18bffc0189ba814749fdcc102b536e83a9f738a9003e569acd540a733", size = 268404, upload-time = "2026-01-26T02:44:00.216Z" }, + { url = "https://files.pythonhosted.org/packages/e0/50/9810c5c29350f7258180dfdcb2e52783a0632862eb334c4896ac717cebcb/multidict-6.7.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:da62917e6076f512daccfbbde27f46fed1c98fee202f0559adec8ee0de67f71a", size = 269456, upload-time = "2026-01-26T02:44:02.202Z" }, + { url = "https://files.pythonhosted.org/packages/f3/8d/5e5be3ced1d12966fefb5c4ea3b2a5b480afcea36406559442c6e31d4a48/multidict-6.7.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bfde23ef6ed9db7eaee6c37dcec08524cb43903c60b285b172b6c094711b3961", size = 256322, upload-time = "2026-01-26T02:44:03.56Z" }, + { url = "https://files.pythonhosted.org/packages/31/6e/d8a26d81ac166a5592782d208dd90dfdc0a7a218adaa52b45a672b46c122/multidict-6.7.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3758692429e4e32f1ba0df23219cd0b4fc0a52f476726fff9337d1a57676a582", size = 253955, upload-time = "2026-01-26T02:44:04.845Z" }, + { url = "https://files.pythonhosted.org/packages/59/4c/7c672c8aad41534ba619bcd4ade7a0dc87ed6b8b5c06149b85d3dd03f0cd/multidict-6.7.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:398c1478926eca669f2fd6a5856b6de9c0acf23a2cb59a14c0ba5844fa38077e", size = 251254, upload-time = "2026-01-26T02:44:06.133Z" }, + { url = "https://files.pythonhosted.org/packages/7b/bd/84c24de512cbafbdbc39439f74e967f19570ce7924e3007174a29c348916/multidict-6.7.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c102791b1c4f3ab36ce4101154549105a53dc828f016356b3e3bcae2e3a039d3", size = 252059, upload-time = "2026-01-26T02:44:07.518Z" }, + { url = "https://files.pythonhosted.org/packages/fa/ba/f5449385510825b73d01c2d4087bf6d2fccc20a2d42ac34df93191d3dd03/multidict-6.7.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a088b62bd733e2ad12c50dad01b7d0166c30287c166e137433d3b410add807a6", size = 263588, upload-time = "2026-01-26T02:44:09.382Z" }, + { url = "https://files.pythonhosted.org/packages/d7/11/afc7c677f68f75c84a69fe37184f0f82fce13ce4b92f49f3db280b7e92b3/multidict-6.7.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3d51ff4785d58d3f6c91bdbffcb5e1f7ddfda557727043aa20d20ec4f65e324a", size = 259642, upload-time = "2026-01-26T02:44:10.73Z" }, + { url = "https://files.pythonhosted.org/packages/2b/17/ebb9644da78c4ab36403739e0e6e0e30ebb135b9caf3440825001a0bddcb/multidict-6.7.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc5907494fccf3e7d3f94f95c91d6336b092b5fc83811720fae5e2765890dfba", size = 251377, upload-time = "2026-01-26T02:44:12.042Z" }, + { url = "https://files.pythonhosted.org/packages/ca/a4/840f5b97339e27846c46307f2530a2805d9d537d8b8bd416af031cad7fa0/multidict-6.7.1-cp312-cp312-win32.whl", hash = "sha256:28ca5ce2fd9716631133d0e9a9b9a745ad7f60bac2bccafb56aa380fc0b6c511", size = 41887, upload-time = "2026-01-26T02:44:14.245Z" }, + { url = "https://files.pythonhosted.org/packages/80/31/0b2517913687895f5904325c2069d6a3b78f66cc641a86a2baf75a05dcbb/multidict-6.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcee94dfbd638784645b066074b338bc9cc155d4b4bffa4adce1615c5a426c19", size = 46053, upload-time = "2026-01-26T02:44:15.371Z" }, + { url = "https://files.pythonhosted.org/packages/0c/5b/aba28e4ee4006ae4c7df8d327d31025d760ffa992ea23812a601d226e682/multidict-6.7.1-cp312-cp312-win_arm64.whl", hash = "sha256:ba0a9fb644d0c1a2194cf7ffb043bd852cea63a57f66fbd33959f7dae18517bf", size = 43307, upload-time = "2026-01-26T02:44:16.852Z" }, + { url = "https://files.pythonhosted.org/packages/f2/22/929c141d6c0dba87d3e1d38fbdf1ba8baba86b7776469f2bc2d3227a1e67/multidict-6.7.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2b41f5fed0ed563624f1c17630cb9941cf2309d4df00e494b551b5f3e3d67a23", size = 76174, upload-time = "2026-01-26T02:44:18.509Z" }, + { url = "https://files.pythonhosted.org/packages/c7/75/bc704ae15fee974f8fccd871305e254754167dce5f9e42d88a2def741a1d/multidict-6.7.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84e61e3af5463c19b67ced91f6c634effb89ef8bfc5ca0267f954451ed4bb6a2", size = 45116, upload-time = "2026-01-26T02:44:19.745Z" }, + { url = "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:935434b9853c7c112eee7ac891bc4cb86455aa631269ae35442cb316790c1445", size = 43524, upload-time = "2026-01-26T02:44:21.571Z" }, + { url = "https://files.pythonhosted.org/packages/e9/3c/414842ef8d5a1628d68edee29ba0e5bcf235dbfb3ccd3ea303a7fe8c72ff/multidict-6.7.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:432feb25a1cb67fe82a9680b4d65fb542e4635cb3166cd9c01560651ad60f177", size = 249368, upload-time = "2026-01-26T02:44:22.803Z" }, + { url = "https://files.pythonhosted.org/packages/f6/32/befed7f74c458b4a525e60519fe8d87eef72bb1e99924fa2b0f9d97a221e/multidict-6.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e82d14e3c948952a1a85503817e038cba5905a3352de76b9a465075d072fba23", size = 256952, upload-time = "2026-01-26T02:44:24.306Z" }, + { url = "https://files.pythonhosted.org/packages/03/d6/c878a44ba877f366630c860fdf74bfb203c33778f12b6ac274936853c451/multidict-6.7.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4cfb48c6ea66c83bcaaf7e4dfa7ec1b6bbcf751b7db85a328902796dfde4c060", size = 240317, upload-time = "2026-01-26T02:44:25.772Z" }, + { url = "https://files.pythonhosted.org/packages/68/49/57421b4d7ad2e9e60e25922b08ceb37e077b90444bde6ead629095327a6f/multidict-6.7.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1d540e51b7e8e170174555edecddbd5538105443754539193e3e1061864d444d", size = 267132, upload-time = "2026-01-26T02:44:27.648Z" }, + { url = "https://files.pythonhosted.org/packages/b7/fe/ec0edd52ddbcea2a2e89e174f0206444a61440b40f39704e64dc807a70bd/multidict-6.7.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:273d23f4b40f3dce4d6c8a821c741a86dec62cded82e1175ba3d99be128147ed", size = 268140, upload-time = "2026-01-26T02:44:29.588Z" }, + { url = "https://files.pythonhosted.org/packages/b0/73/6e1b01cbeb458807aa0831742232dbdd1fa92bfa33f52a3f176b4ff3dc11/multidict-6.7.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d624335fd4fa1c08a53f8b4be7676ebde19cd092b3895c421045ca87895b429", size = 254277, upload-time = "2026-01-26T02:44:30.902Z" }, + { url = "https://files.pythonhosted.org/packages/6a/b2/5fb8c124d7561a4974c342bc8c778b471ebbeb3cc17df696f034a7e9afe7/multidict-6.7.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:12fad252f8b267cc75b66e8fc51b3079604e8d43a75428ffe193cd9e2195dfd6", size = 252291, upload-time = "2026-01-26T02:44:32.31Z" }, + { url = "https://files.pythonhosted.org/packages/5a/96/51d4e4e06bcce92577fcd488e22600bd38e4fd59c20cb49434d054903bd2/multidict-6.7.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:03ede2a6ffbe8ef936b92cb4529f27f42be7f56afcdab5ab739cd5f27fb1cbf9", size = 250156, upload-time = "2026-01-26T02:44:33.734Z" }, + { url = "https://files.pythonhosted.org/packages/db/6b/420e173eec5fba721a50e2a9f89eda89d9c98fded1124f8d5c675f7a0c0f/multidict-6.7.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:90efbcf47dbe33dcf643a1e400d67d59abeac5db07dc3f27d6bdeae497a2198c", size = 249742, upload-time = "2026-01-26T02:44:35.222Z" }, + { url = "https://files.pythonhosted.org/packages/44/a3/ec5b5bd98f306bc2aa297b8c6f11a46714a56b1e6ef5ebda50a4f5d7c5fb/multidict-6.7.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5c4b9bfc148f5a91be9244d6264c53035c8a0dcd2f51f1c3c6e30e30ebaa1c84", size = 262221, upload-time = "2026-01-26T02:44:36.604Z" }, + { url = "https://files.pythonhosted.org/packages/cd/f7/e8c0d0da0cd1e28d10e624604e1a36bcc3353aaebdfdc3a43c72bc683a12/multidict-6.7.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:401c5a650f3add2472d1d288c26deebc540f99e2fb83e9525007a74cd2116f1d", size = 258664, upload-time = "2026-01-26T02:44:38.008Z" }, + { url = "https://files.pythonhosted.org/packages/52/da/151a44e8016dd33feed44f730bd856a66257c1ee7aed4f44b649fb7edeb3/multidict-6.7.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:97891f3b1b3ffbded884e2916cacf3c6fc87b66bb0dde46f7357404750559f33", size = 249490, upload-time = "2026-01-26T02:44:39.386Z" }, + { url = "https://files.pythonhosted.org/packages/87/af/a3b86bf9630b732897f6fc3f4c4714b90aa4361983ccbdcd6c0339b21b0c/multidict-6.7.1-cp313-cp313-win32.whl", hash = "sha256:e1c5988359516095535c4301af38d8a8838534158f649c05dd1050222321bcb3", size = 41695, upload-time = "2026-01-26T02:44:41.318Z" }, + { url = "https://files.pythonhosted.org/packages/b2/35/e994121b0e90e46134673422dd564623f93304614f5d11886b1b3e06f503/multidict-6.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:960c83bf01a95b12b08fd54324a4eb1d5b52c88932b5cba5d6e712bb3ed12eb5", size = 45884, upload-time = "2026-01-26T02:44:42.488Z" }, + { url = "https://files.pythonhosted.org/packages/ca/61/42d3e5dbf661242a69c97ea363f2d7b46c567da8eadef8890022be6e2ab0/multidict-6.7.1-cp313-cp313-win_arm64.whl", hash = "sha256:563fe25c678aaba333d5399408f5ec3c383ca5b663e7f774dd179a520b8144df", size = 43122, upload-time = "2026-01-26T02:44:43.664Z" }, + { url = "https://files.pythonhosted.org/packages/6d/b3/e6b21c6c4f314bb956016b0b3ef2162590a529b84cb831c257519e7fde44/multidict-6.7.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:c76c4bec1538375dad9d452d246ca5368ad6e1c9039dadcf007ae59c70619ea1", size = 83175, upload-time = "2026-01-26T02:44:44.894Z" }, + { url = "https://files.pythonhosted.org/packages/fb/76/23ecd2abfe0957b234f6c960f4ade497f55f2c16aeb684d4ecdbf1c95791/multidict-6.7.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:57b46b24b5d5ebcc978da4ec23a819a9402b4228b8a90d9c656422b4bdd8a963", size = 48460, upload-time = "2026-01-26T02:44:46.106Z" }, + { url = "https://files.pythonhosted.org/packages/c4/57/a0ed92b23f3a042c36bc4227b72b97eca803f5f1801c1ab77c8a212d455e/multidict-6.7.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e954b24433c768ce78ab7929e84ccf3422e46deb45a4dc9f93438f8217fa2d34", size = 46930, upload-time = "2026-01-26T02:44:47.278Z" }, + { url = "https://files.pythonhosted.org/packages/b5/66/02ec7ace29162e447f6382c495dc95826bf931d3818799bbef11e8f7df1a/multidict-6.7.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3bd231490fa7217cc832528e1cd8752a96f0125ddd2b5749390f7c3ec8721b65", size = 242582, upload-time = "2026-01-26T02:44:48.604Z" }, + { url = "https://files.pythonhosted.org/packages/58/18/64f5a795e7677670e872673aca234162514696274597b3708b2c0d276cce/multidict-6.7.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:253282d70d67885a15c8a7716f3a73edf2d635793ceda8173b9ecc21f2fb8292", size = 250031, upload-time = "2026-01-26T02:44:50.544Z" }, + { url = "https://files.pythonhosted.org/packages/c8/ed/e192291dbbe51a8290c5686f482084d31bcd9d09af24f63358c3d42fd284/multidict-6.7.1-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0b4c48648d7649c9335cf1927a8b87fa692de3dcb15faa676c6a6f1f1aabda43", size = 228596, upload-time = "2026-01-26T02:44:51.951Z" }, + { url = "https://files.pythonhosted.org/packages/1e/7e/3562a15a60cf747397e7f2180b0a11dc0c38d9175a650e75fa1b4d325e15/multidict-6.7.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:98bc624954ec4d2c7cb074b8eefc2b5d0ce7d482e410df446414355d158fe4ca", size = 257492, upload-time = "2026-01-26T02:44:53.902Z" }, + { url = "https://files.pythonhosted.org/packages/24/02/7d0f9eae92b5249bb50ac1595b295f10e263dd0078ebb55115c31e0eaccd/multidict-6.7.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1b99af4d9eec0b49927b4402bcbb58dea89d3e0db8806a4086117019939ad3dd", size = 255899, upload-time = "2026-01-26T02:44:55.316Z" }, + { url = "https://files.pythonhosted.org/packages/00/e3/9b60ed9e23e64c73a5cde95269ef1330678e9c6e34dd4eb6b431b85b5a10/multidict-6.7.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6aac4f16b472d5b7dc6f66a0d49dd57b0e0902090be16594dc9ebfd3d17c47e7", size = 247970, upload-time = "2026-01-26T02:44:56.783Z" }, + { url = "https://files.pythonhosted.org/packages/3e/06/538e58a63ed5cfb0bd4517e346b91da32fde409d839720f664e9a4ae4f9d/multidict-6.7.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:21f830fe223215dffd51f538e78c172ed7c7f60c9b96a2bf05c4848ad49921c3", size = 245060, upload-time = "2026-01-26T02:44:58.195Z" }, + { url = "https://files.pythonhosted.org/packages/b2/2f/d743a3045a97c895d401e9bd29aaa09b94f5cbdf1bd561609e5a6c431c70/multidict-6.7.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f5dd81c45b05518b9aa4da4aa74e1c93d715efa234fd3e8a179df611cc85e5f4", size = 235888, upload-time = "2026-01-26T02:44:59.57Z" }, + { url = "https://files.pythonhosted.org/packages/38/83/5a325cac191ab28b63c52f14f1131f3b0a55ba3b9aa65a6d0bf2a9b921a0/multidict-6.7.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:eb304767bca2bb92fb9c5bd33cedc95baee5bb5f6c88e63706533a1c06ad08c8", size = 243554, upload-time = "2026-01-26T02:45:01.054Z" }, + { url = "https://files.pythonhosted.org/packages/20/1f/9d2327086bd15da2725ef6aae624208e2ef828ed99892b17f60c344e57ed/multidict-6.7.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c9035dde0f916702850ef66460bc4239d89d08df4d02023a5926e7446724212c", size = 252341, upload-time = "2026-01-26T02:45:02.484Z" }, + { url = "https://files.pythonhosted.org/packages/e8/2c/2a1aa0280cf579d0f6eed8ee5211c4f1730bd7e06c636ba2ee6aafda302e/multidict-6.7.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:af959b9beeb66c822380f222f0e0a1889331597e81f1ded7f374f3ecb0fd6c52", size = 246391, upload-time = "2026-01-26T02:45:03.862Z" }, + { url = "https://files.pythonhosted.org/packages/e5/03/7ca022ffc36c5a3f6e03b179a5ceb829be9da5783e6fe395f347c0794680/multidict-6.7.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:41f2952231456154ee479651491e94118229844dd7226541788be783be2b5108", size = 243422, upload-time = "2026-01-26T02:45:05.296Z" }, + { url = "https://files.pythonhosted.org/packages/dc/1d/b31650eab6c5778aceed46ba735bd97f7c7d2f54b319fa916c0f96e7805b/multidict-6.7.1-cp313-cp313t-win32.whl", hash = "sha256:df9f19c28adcb40b6aae30bbaa1478c389efd50c28d541d76760199fc1037c32", size = 47770, upload-time = "2026-01-26T02:45:06.754Z" }, + { url = "https://files.pythonhosted.org/packages/ac/5b/2d2d1d522e51285bd61b1e20df8f47ae1a9d80839db0b24ea783b3832832/multidict-6.7.1-cp313-cp313t-win_amd64.whl", hash = "sha256:d54ecf9f301853f2c5e802da559604b3e95bb7a3b01a9c295c6ee591b9882de8", size = 53109, upload-time = "2026-01-26T02:45:08.044Z" }, + { url = "https://files.pythonhosted.org/packages/3d/a3/cc409ba012c83ca024a308516703cf339bdc4b696195644a7215a5164a24/multidict-6.7.1-cp313-cp313t-win_arm64.whl", hash = "sha256:5a37ca18e360377cfda1d62f5f382ff41f2b8c4ccb329ed974cc2e1643440118", size = 45573, upload-time = "2026-01-26T02:45:09.349Z" }, + { url = "https://files.pythonhosted.org/packages/91/cc/db74228a8be41884a567e88a62fd589a913708fcf180d029898c17a9a371/multidict-6.7.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8f333ec9c5eb1b7105e3b84b53141e66ca05a19a605368c55450b6ba208cb9ee", size = 75190, upload-time = "2026-01-26T02:45:10.651Z" }, + { url = "https://files.pythonhosted.org/packages/d5/22/492f2246bb5b534abd44804292e81eeaf835388901f0c574bac4eeec73c5/multidict-6.7.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a407f13c188f804c759fc6a9f88286a565c242a76b27626594c133b82883b5c2", size = 44486, upload-time = "2026-01-26T02:45:11.938Z" }, + { url = "https://files.pythonhosted.org/packages/f1/4f/733c48f270565d78b4544f2baddc2fb2a245e5a8640254b12c36ac7ac68e/multidict-6.7.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0e161ddf326db5577c3a4cc2d8648f81456e8a20d40415541587a71620d7a7d1", size = 43219, upload-time = "2026-01-26T02:45:14.346Z" }, + { url = "https://files.pythonhosted.org/packages/24/bb/2c0c2287963f4259c85e8bcbba9182ced8d7fca65c780c38e99e61629d11/multidict-6.7.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1e3a8bb24342a8201d178c3b4984c26ba81a577c80d4d525727427460a50c22d", size = 245132, upload-time = "2026-01-26T02:45:15.712Z" }, + { url = "https://files.pythonhosted.org/packages/a7/f9/44d4b3064c65079d2467888794dea218d1601898ac50222ab8a9a8094460/multidict-6.7.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97231140a50f5d447d3164f994b86a0bed7cd016e2682f8650d6a9158e14fd31", size = 252420, upload-time = "2026-01-26T02:45:17.293Z" }, + { url = "https://files.pythonhosted.org/packages/8b/13/78f7275e73fa17b24c9a51b0bd9d73ba64bb32d0ed51b02a746eb876abe7/multidict-6.7.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6b10359683bd8806a200fd2909e7c8ca3a7b24ec1d8132e483d58e791d881048", size = 233510, upload-time = "2026-01-26T02:45:19.356Z" }, + { url = "https://files.pythonhosted.org/packages/4b/25/8167187f62ae3cbd52da7893f58cb036b47ea3fb67138787c76800158982/multidict-6.7.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:283ddac99f7ac25a4acadbf004cb5ae34480bbeb063520f70ce397b281859362", size = 264094, upload-time = "2026-01-26T02:45:20.834Z" }, + { url = "https://files.pythonhosted.org/packages/a1/e7/69a3a83b7b030cf283fb06ce074a05a02322359783424d7edf0f15fe5022/multidict-6.7.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:538cec1e18c067d0e6103aa9a74f9e832904c957adc260e61cd9d8cf0c3b3d37", size = 260786, upload-time = "2026-01-26T02:45:22.818Z" }, + { url = "https://files.pythonhosted.org/packages/fe/3b/8ec5074bcfc450fe84273713b4b0a0dd47c0249358f5d82eb8104ffe2520/multidict-6.7.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7eee46ccb30ff48a1e35bb818cc90846c6be2b68240e42a78599166722cea709", size = 248483, upload-time = "2026-01-26T02:45:24.368Z" }, + { url = "https://files.pythonhosted.org/packages/48/5a/d5a99e3acbca0e29c5d9cba8f92ceb15dce78bab963b308ae692981e3a5d/multidict-6.7.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fa263a02f4f2dd2d11a7b1bb4362aa7cb1049f84a9235d31adf63f30143469a0", size = 248403, upload-time = "2026-01-26T02:45:25.982Z" }, + { url = "https://files.pythonhosted.org/packages/35/48/e58cd31f6c7d5102f2a4bf89f96b9cf7e00b6c6f3d04ecc44417c00a5a3c/multidict-6.7.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:2e1425e2f99ec5bd36c15a01b690a1a2456209c5deed58f95469ffb46039ccbb", size = 240315, upload-time = "2026-01-26T02:45:27.487Z" }, + { url = "https://files.pythonhosted.org/packages/94/33/1cd210229559cb90b6786c30676bb0c58249ff42f942765f88793b41fdce/multidict-6.7.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:497394b3239fc6f0e13a78a3e1b61296e72bf1c5f94b4c4eb80b265c37a131cd", size = 245528, upload-time = "2026-01-26T02:45:28.991Z" }, + { url = "https://files.pythonhosted.org/packages/64/f2/6e1107d226278c876c783056b7db43d800bb64c6131cec9c8dfb6903698e/multidict-6.7.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:233b398c29d3f1b9676b4b6f75c518a06fcb2ea0b925119fb2c1bc35c05e1601", size = 258784, upload-time = "2026-01-26T02:45:30.503Z" }, + { url = "https://files.pythonhosted.org/packages/4d/c1/11f664f14d525e4a1b5327a82d4de61a1db604ab34c6603bb3c2cc63ad34/multidict-6.7.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:93b1818e4a6e0930454f0f2af7dfce69307ca03cdcfb3739bf4d91241967b6c1", size = 251980, upload-time = "2026-01-26T02:45:32.603Z" }, + { url = "https://files.pythonhosted.org/packages/e1/9f/75a9ac888121d0c5bbd4ecf4eead45668b1766f6baabfb3b7f66a410e231/multidict-6.7.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f33dc2a3abe9249ea5d8360f969ec7f4142e7ac45ee7014d8f8d5acddf178b7b", size = 243602, upload-time = "2026-01-26T02:45:34.043Z" }, + { url = "https://files.pythonhosted.org/packages/9a/e7/50bf7b004cc8525d80dbbbedfdc7aed3e4c323810890be4413e589074032/multidict-6.7.1-cp314-cp314-win32.whl", hash = "sha256:3ab8b9d8b75aef9df299595d5388b14530839f6422333357af1339443cff777d", size = 40930, upload-time = "2026-01-26T02:45:36.278Z" }, + { url = "https://files.pythonhosted.org/packages/e0/bf/52f25716bbe93745595800f36fb17b73711f14da59ed0bb2eba141bc9f0f/multidict-6.7.1-cp314-cp314-win_amd64.whl", hash = "sha256:5e01429a929600e7dab7b166062d9bb54a5eed752384c7384c968c2afab8f50f", size = 45074, upload-time = "2026-01-26T02:45:37.546Z" }, + { url = "https://files.pythonhosted.org/packages/97/ab/22803b03285fa3a525f48217963da3a65ae40f6a1b6f6cf2768879e208f9/multidict-6.7.1-cp314-cp314-win_arm64.whl", hash = "sha256:4885cb0e817aef5d00a2e8451d4665c1808378dc27c2705f1bf4ef8505c0d2e5", size = 42471, upload-time = "2026-01-26T02:45:38.889Z" }, + { url = "https://files.pythonhosted.org/packages/e0/6d/f9293baa6146ba9507e360ea0292b6422b016907c393e2f63fc40ab7b7b5/multidict-6.7.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:0458c978acd8e6ea53c81eefaddbbee9c6c5e591f41b3f5e8e194780fe026581", size = 82401, upload-time = "2026-01-26T02:45:40.254Z" }, + { url = "https://files.pythonhosted.org/packages/7a/68/53b5494738d83558d87c3c71a486504d8373421c3e0dbb6d0db48ad42ee0/multidict-6.7.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:c0abd12629b0af3cf590982c0b413b1e7395cd4ec026f30986818ab95bfaa94a", size = 48143, upload-time = "2026-01-26T02:45:41.635Z" }, + { url = "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:14525a5f61d7d0c94b368a42cff4c9a4e7ba2d52e2672a7b23d84dc86fb02b0c", size = 46507, upload-time = "2026-01-26T02:45:42.99Z" }, + { url = "https://files.pythonhosted.org/packages/e4/fc/6800d0e5b3875568b4083ecf5f310dcf91d86d52573160834fb4bfcf5e4f/multidict-6.7.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17307b22c217b4cf05033dabefe68255a534d637c6c9b0cc8382718f87be4262", size = 239358, upload-time = "2026-01-26T02:45:44.376Z" }, + { url = "https://files.pythonhosted.org/packages/41/75/4ad0973179361cdf3a113905e6e088173198349131be2b390f9fa4da5fc6/multidict-6.7.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a7e590ff876a3eaf1c02a4dfe0724b6e69a9e9de6d8f556816f29c496046e59", size = 246884, upload-time = "2026-01-26T02:45:47.167Z" }, + { url = "https://files.pythonhosted.org/packages/c3/9c/095bb28b5da139bd41fb9a5d5caff412584f377914bd8787c2aa98717130/multidict-6.7.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5fa6a95dfee63893d80a34758cd0e0c118a30b8dcb46372bf75106c591b77889", size = 225878, upload-time = "2026-01-26T02:45:48.698Z" }, + { url = "https://files.pythonhosted.org/packages/07/d0/c0a72000243756e8f5a277b6b514fa005f2c73d481b7d9e47cd4568aa2e4/multidict-6.7.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a0543217a6a017692aa6ae5cc39adb75e587af0f3a82288b1492eb73dd6cc2a4", size = 253542, upload-time = "2026-01-26T02:45:50.164Z" }, + { url = "https://files.pythonhosted.org/packages/c0/6b/f69da15289e384ecf2a68837ec8b5ad8c33e973aa18b266f50fe55f24b8c/multidict-6.7.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f99fe611c312b3c1c0ace793f92464d8cd263cc3b26b5721950d977b006b6c4d", size = 252403, upload-time = "2026-01-26T02:45:51.779Z" }, + { url = "https://files.pythonhosted.org/packages/a2/76/b9669547afa5a1a25cd93eaca91c0da1c095b06b6d2d8ec25b713588d3a1/multidict-6.7.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9004d8386d133b7e6135679424c91b0b854d2d164af6ea3f289f8f2761064609", size = 244889, upload-time = "2026-01-26T02:45:53.27Z" }, + { url = "https://files.pythonhosted.org/packages/7e/a9/a50d2669e506dad33cfc45b5d574a205587b7b8a5f426f2fbb2e90882588/multidict-6.7.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e628ef0e6859ffd8273c69412a2465c4be4a9517d07261b33334b5ec6f3c7489", size = 241982, upload-time = "2026-01-26T02:45:54.919Z" }, + { url = "https://files.pythonhosted.org/packages/c5/bb/1609558ad8b456b4827d3c5a5b775c93b87878fd3117ed3db3423dfbce1b/multidict-6.7.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:841189848ba629c3552035a6a7f5bf3b02eb304e9fea7492ca220a8eda6b0e5c", size = 232415, upload-time = "2026-01-26T02:45:56.981Z" }, + { url = "https://files.pythonhosted.org/packages/d8/59/6f61039d2aa9261871e03ab9dc058a550d240f25859b05b67fd70f80d4b3/multidict-6.7.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:ce1bbd7d780bb5a0da032e095c951f7014d6b0a205f8318308140f1a6aba159e", size = 240337, upload-time = "2026-01-26T02:45:58.698Z" }, + { url = "https://files.pythonhosted.org/packages/a1/29/fdc6a43c203890dc2ae9249971ecd0c41deaedfe00d25cb6564b2edd99eb/multidict-6.7.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b26684587228afed0d50cf804cc71062cc9c1cdf55051c4c6345d372947b268c", size = 248788, upload-time = "2026-01-26T02:46:00.862Z" }, + { url = "https://files.pythonhosted.org/packages/a9/14/a153a06101323e4cf086ecee3faadba52ff71633d471f9685c42e3736163/multidict-6.7.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9f9af11306994335398293f9958071019e3ab95e9a707dc1383a35613f6abcb9", size = 242842, upload-time = "2026-01-26T02:46:02.824Z" }, + { url = "https://files.pythonhosted.org/packages/41/5f/604ae839e64a4a6efc80db94465348d3b328ee955e37acb24badbcd24d83/multidict-6.7.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b4938326284c4f1224178a560987b6cf8b4d38458b113d9b8c1db1a836e640a2", size = 240237, upload-time = "2026-01-26T02:46:05.898Z" }, + { url = "https://files.pythonhosted.org/packages/5f/60/c3a5187bf66f6fb546ff4ab8fb5a077cbdd832d7b1908d4365c7f74a1917/multidict-6.7.1-cp314-cp314t-win32.whl", hash = "sha256:98655c737850c064a65e006a3df7c997cd3b220be4ec8fe26215760b9697d4d7", size = 48008, upload-time = "2026-01-26T02:46:07.468Z" }, + { url = "https://files.pythonhosted.org/packages/0c/f7/addf1087b860ac60e6f382240f64fb99f8bfb532bb06f7c542b83c29ca61/multidict-6.7.1-cp314-cp314t-win_amd64.whl", hash = "sha256:497bde6223c212ba11d462853cfa4f0ae6ef97465033e7dc9940cdb3ab5b48e5", size = 53542, upload-time = "2026-01-26T02:46:08.809Z" }, + { url = "https://files.pythonhosted.org/packages/4c/81/4629d0aa32302ef7b2ec65c75a728cc5ff4fa410c50096174c1632e70b3e/multidict-6.7.1-cp314-cp314t-win_arm64.whl", hash = "sha256:2bbd113e0d4af5db41d5ebfe9ccaff89de2120578164f86a5d17d5a576d1e5b2", size = 44719, upload-time = "2026-01-26T02:46:11.146Z" }, + { url = "https://files.pythonhosted.org/packages/9e/ee/74525ebe3eb5fddcd6735fc03cbea3feeed4122b53bc798ac32d297ac9ae/multidict-6.7.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:65573858d27cdeaca41893185677dc82395159aa28875a8867af66532d413a8f", size = 77107, upload-time = "2026-01-26T02:46:12.608Z" }, + { url = "https://files.pythonhosted.org/packages/f0/9a/ce8744e777a74b3050b1bf56be3eed1053b3457302ea055f1ea437200a23/multidict-6.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c524c6fb8fc342793708ab111c4dbc90ff9abd568de220432500e47e990c0358", size = 44943, upload-time = "2026-01-26T02:46:14.016Z" }, + { url = "https://files.pythonhosted.org/packages/83/9c/1d2a283d9c6f31e260cb6c2fccadc3edcf6c4c14ee0929cd2af4d2606dd7/multidict-6.7.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:aa23b001d968faef416ff70dc0f1ab045517b9b42a90edd3e9bcdb06479e31d5", size = 44603, upload-time = "2026-01-26T02:46:15.391Z" }, + { url = "https://files.pythonhosted.org/packages/87/9d/3b186201671583d8e8d6d79c07481a5aafd0ba7575e3d8566baec80c1e82/multidict-6.7.1-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6704fa2b7453b2fb121740555fa1ee20cd98c4d011120caf4d2b8d4e7c76eec0", size = 240573, upload-time = "2026-01-26T02:46:16.783Z" }, + { url = "https://files.pythonhosted.org/packages/42/7d/a52f5d4d0754311d1ac78478e34dff88de71259a8585e05ee14e5f877caf/multidict-6.7.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:121a34e5bfa410cdf2c8c49716de160de3b1dbcd86b49656f5681e4543bcd1a8", size = 240106, upload-time = "2026-01-26T02:46:18.432Z" }, + { url = "https://files.pythonhosted.org/packages/84/9f/d80118e6c30ff55b7d171bdc5520aad4b9626e657520b8d7c8ca8c2fad12/multidict-6.7.1-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:026d264228bcd637d4e060844e39cdc60f86c479e463d49075dedc21b18fbbe0", size = 219418, upload-time = "2026-01-26T02:46:20.526Z" }, + { url = "https://files.pythonhosted.org/packages/c7/bd/896e60b3457f194de77c7de64f9acce9f75da0518a5230ce1df534f6747b/multidict-6.7.1-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0e697826df7eb63418ee190fd06ce9f1803593bb4b9517d08c60d9b9a7f69d8f", size = 252124, upload-time = "2026-01-26T02:46:22.157Z" }, + { url = "https://files.pythonhosted.org/packages/f4/de/ba6b30447c36a37078d0ba604aa12c1a52887af0c355236ca6e0a9d5286f/multidict-6.7.1-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bb08271280173720e9fea9ede98e5231defcbad90f1624bea26f32ec8a956e2f", size = 249402, upload-time = "2026-01-26T02:46:23.718Z" }, + { url = "https://files.pythonhosted.org/packages/c2/b2/50a383c96230e432895a2fd3bcfe1b65785899598259d871d5de6b93180c/multidict-6.7.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c6b3228e1d80af737b72925ce5fb4daf5a335e49cd7ab77ed7b9fdfbf58c526e", size = 240346, upload-time = "2026-01-26T02:46:25.393Z" }, + { url = "https://files.pythonhosted.org/packages/89/37/16d391fd8da544b1489306e38a46785fa41dd0f0ef766837ed7d4676dde0/multidict-6.7.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3943debf0fbb57bdde5901695c11094a9a36723e5c03875f87718ee15ca2f4d2", size = 237010, upload-time = "2026-01-26T02:46:27.408Z" }, + { url = "https://files.pythonhosted.org/packages/b0/24/3152ee026eda86d5d3e3685182911e6951af7a016579da931080ce6ac9ad/multidict-6.7.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:98c5787b0a0d9a41d9311eae44c3b76e6753def8d8870ab501320efe75a6a5f8", size = 232018, upload-time = "2026-01-26T02:46:29.941Z" }, + { url = "https://files.pythonhosted.org/packages/9c/1f/48d3c27a72be7fd23a55d8847193c459959bf35a5bb5844530dab00b739b/multidict-6.7.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:08ccb2a6dc72009093ebe7f3f073e5ec5964cba9a706fa94b1a1484039b87941", size = 241498, upload-time = "2026-01-26T02:46:32.052Z" }, + { url = "https://files.pythonhosted.org/packages/1a/45/413643ae2952d0decdf6c1250f86d08a43e143271441e81027e38d598bd7/multidict-6.7.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:eb351f72c26dc9abe338ca7294661aa22969ad8ffe7ef7d5541d19f368dc854a", size = 247957, upload-time = "2026-01-26T02:46:33.666Z" }, + { url = "https://files.pythonhosted.org/packages/50/f8/f1d0ac23df15e0470776388bdb261506f63af1f81d28bacb5e262d6e12b6/multidict-6.7.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ac1c665bad8b5d762f5f85ebe4d94130c26965f11de70c708c75671297c776de", size = 241651, upload-time = "2026-01-26T02:46:35.7Z" }, + { url = "https://files.pythonhosted.org/packages/2c/c9/1a2a18f383cf129add66b6c36b75c3911a7ba95cf26cb141482de085cc12/multidict-6.7.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1fa6609d0364f4f6f58351b4659a1f3e0e898ba2a8c5cac04cb2c7bc556b0bc5", size = 236371, upload-time = "2026-01-26T02:46:37.37Z" }, + { url = "https://files.pythonhosted.org/packages/bb/aa/77d87e3fca31325b87e0eb72d5fe9a7472dcb51391a42df7ac1f3842f6c0/multidict-6.7.1-cp39-cp39-win32.whl", hash = "sha256:6f77ce314a29263e67adadc7e7c1bc699fcb3a305059ab973d038f87caa42ed0", size = 41426, upload-time = "2026-01-26T02:46:39.026Z" }, + { url = "https://files.pythonhosted.org/packages/e3/b3/e8863e6a2da15a9d7e98976ff402e871b7352c76566df6c18d0378e0d9cf/multidict-6.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:f537b55778cd3cbee430abe3131255d3a78202e0f9ea7ffc6ada893a4bcaeea4", size = 46180, upload-time = "2026-01-26T02:46:40.422Z" }, + { url = "https://files.pythonhosted.org/packages/93/d3/dd4fa951ad5b5fa216bf30054d705683d13405eea7459833d78f31b74c9c/multidict-6.7.1-cp39-cp39-win_arm64.whl", hash = "sha256:749aa54f578f2e5f439538706a475aa844bfa8ef75854b1401e6e528e4937cf9", size = 43231, upload-time = "2026-01-26T02:46:41.945Z" }, + { url = "https://files.pythonhosted.org/packages/81/08/7036c080d7117f28a4af526d794aab6a84463126db031b007717c1a6676e/multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56", size = 12319, upload-time = "2026-01-26T02:46:44.004Z" }, +] + +[[package]] +name = "propcache" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9e/da/e9fc233cf63743258bff22b3dfa7ea5baef7b5bc324af47a0ad89b8ffc6f/propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d", size = 46442, upload-time = "2025-10-08T19:49:02.291Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/0e/934b541323035566a9af292dba85a195f7b78179114f2c6ebb24551118a9/propcache-0.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c2d1fa3201efaf55d730400d945b5b3ab6e672e100ba0f9a409d950ab25d7db", size = 79534, upload-time = "2025-10-08T19:46:02.083Z" }, + { url = "https://files.pythonhosted.org/packages/a1/6b/db0d03d96726d995dc7171286c6ba9d8d14251f37433890f88368951a44e/propcache-0.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1eb2994229cc8ce7fe9b3db88f5465f5fd8651672840b2e426b88cdb1a30aac8", size = 45526, upload-time = "2025-10-08T19:46:03.884Z" }, + { url = "https://files.pythonhosted.org/packages/e4/c3/82728404aea669e1600f304f2609cde9e665c18df5a11cdd57ed73c1dceb/propcache-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:66c1f011f45a3b33d7bcb22daed4b29c0c9e2224758b6be00686731e1b46f925", size = 47263, upload-time = "2025-10-08T19:46:05.405Z" }, + { url = "https://files.pythonhosted.org/packages/df/1b/39313ddad2bf9187a1432654c38249bab4562ef535ef07f5eb6eb04d0b1b/propcache-0.4.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9a52009f2adffe195d0b605c25ec929d26b36ef986ba85244891dee3b294df21", size = 201012, upload-time = "2025-10-08T19:46:07.165Z" }, + { url = "https://files.pythonhosted.org/packages/5b/01/f1d0b57d136f294a142acf97f4ed58c8e5b974c21e543000968357115011/propcache-0.4.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5d4e2366a9c7b837555cf02fb9be2e3167d333aff716332ef1b7c3a142ec40c5", size = 209491, upload-time = "2025-10-08T19:46:08.909Z" }, + { url = "https://files.pythonhosted.org/packages/a1/c8/038d909c61c5bb039070b3fb02ad5cccdb1dde0d714792e251cdb17c9c05/propcache-0.4.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9d2b6caef873b4f09e26ea7e33d65f42b944837563a47a94719cc3544319a0db", size = 215319, upload-time = "2025-10-08T19:46:10.7Z" }, + { url = "https://files.pythonhosted.org/packages/08/57/8c87e93142b2c1fa2408e45695205a7ba05fb5db458c0bf5c06ba0e09ea6/propcache-0.4.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b16ec437a8c8a965ecf95739448dd938b5c7f56e67ea009f4300d8df05f32b7", size = 196856, upload-time = "2025-10-08T19:46:12.003Z" }, + { url = "https://files.pythonhosted.org/packages/42/df/5615fec76aa561987a534759b3686008a288e73107faa49a8ae5795a9f7a/propcache-0.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:296f4c8ed03ca7476813fe666c9ea97869a8d7aec972618671b33a38a5182ef4", size = 193241, upload-time = "2025-10-08T19:46:13.495Z" }, + { url = "https://files.pythonhosted.org/packages/d5/21/62949eb3a7a54afe8327011c90aca7e03547787a88fb8bd9726806482fea/propcache-0.4.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:1f0978529a418ebd1f49dad413a2b68af33f85d5c5ca5c6ca2a3bed375a7ac60", size = 190552, upload-time = "2025-10-08T19:46:14.938Z" }, + { url = "https://files.pythonhosted.org/packages/30/ee/ab4d727dd70806e5b4de96a798ae7ac6e4d42516f030ee60522474b6b332/propcache-0.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fd138803047fb4c062b1c1dd95462f5209456bfab55c734458f15d11da288f8f", size = 200113, upload-time = "2025-10-08T19:46:16.695Z" }, + { url = "https://files.pythonhosted.org/packages/8a/0b/38b46208e6711b016aa8966a3ac793eee0d05c7159d8342aa27fc0bc365e/propcache-0.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8c9b3cbe4584636d72ff556d9036e0c9317fa27b3ac1f0f558e7e84d1c9c5900", size = 200778, upload-time = "2025-10-08T19:46:18.023Z" }, + { url = "https://files.pythonhosted.org/packages/cf/81/5abec54355ed344476bee711e9f04815d4b00a311ab0535599204eecc257/propcache-0.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f93243fdc5657247533273ac4f86ae106cc6445a0efacb9a1bfe982fcfefd90c", size = 193047, upload-time = "2025-10-08T19:46:19.449Z" }, + { url = "https://files.pythonhosted.org/packages/ec/b6/1f237c04e32063cb034acd5f6ef34ef3a394f75502e72703545631ab1ef6/propcache-0.4.1-cp310-cp310-win32.whl", hash = "sha256:a0ee98db9c5f80785b266eb805016e36058ac72c51a064040f2bc43b61101cdb", size = 38093, upload-time = "2025-10-08T19:46:20.643Z" }, + { url = "https://files.pythonhosted.org/packages/a6/67/354aac4e0603a15f76439caf0427781bcd6797f370377f75a642133bc954/propcache-0.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:1cdb7988c4e5ac7f6d175a28a9aa0c94cb6f2ebe52756a3c0cda98d2809a9e37", size = 41638, upload-time = "2025-10-08T19:46:21.935Z" }, + { url = "https://files.pythonhosted.org/packages/e0/e1/74e55b9fd1a4c209ff1a9a824bf6c8b3d1fc5a1ac3eabe23462637466785/propcache-0.4.1-cp310-cp310-win_arm64.whl", hash = "sha256:d82ad62b19645419fe79dd63b3f9253e15b30e955c0170e5cebc350c1844e581", size = 38229, upload-time = "2025-10-08T19:46:23.368Z" }, + { url = "https://files.pythonhosted.org/packages/8c/d4/4e2c9aaf7ac2242b9358f98dccd8f90f2605402f5afeff6c578682c2c491/propcache-0.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:60a8fda9644b7dfd5dece8c61d8a85e271cb958075bfc4e01083c148b61a7caf", size = 80208, upload-time = "2025-10-08T19:46:24.597Z" }, + { url = "https://files.pythonhosted.org/packages/c2/21/d7b68e911f9c8e18e4ae43bdbc1e1e9bbd971f8866eb81608947b6f585ff/propcache-0.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c30b53e7e6bda1d547cabb47c825f3843a0a1a42b0496087bb58d8fedf9f41b5", size = 45777, upload-time = "2025-10-08T19:46:25.733Z" }, + { url = "https://files.pythonhosted.org/packages/d3/1d/11605e99ac8ea9435651ee71ab4cb4bf03f0949586246476a25aadfec54a/propcache-0.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6918ecbd897443087a3b7cd978d56546a812517dcaaca51b49526720571fa93e", size = 47647, upload-time = "2025-10-08T19:46:27.304Z" }, + { url = "https://files.pythonhosted.org/packages/58/1a/3c62c127a8466c9c843bccb503d40a273e5cc69838805f322e2826509e0d/propcache-0.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3d902a36df4e5989763425a8ab9e98cd8ad5c52c823b34ee7ef307fd50582566", size = 214929, upload-time = "2025-10-08T19:46:28.62Z" }, + { url = "https://files.pythonhosted.org/packages/56/b9/8fa98f850960b367c4b8fe0592e7fc341daa7a9462e925228f10a60cf74f/propcache-0.4.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a9695397f85973bb40427dedddf70d8dc4a44b22f1650dd4af9eedf443d45165", size = 221778, upload-time = "2025-10-08T19:46:30.358Z" }, + { url = "https://files.pythonhosted.org/packages/46/a6/0ab4f660eb59649d14b3d3d65c439421cf2f87fe5dd68591cbe3c1e78a89/propcache-0.4.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2bb07ffd7eaad486576430c89f9b215f9e4be68c4866a96e97db9e97fead85dc", size = 228144, upload-time = "2025-10-08T19:46:32.607Z" }, + { url = "https://files.pythonhosted.org/packages/52/6a/57f43e054fb3d3a56ac9fc532bc684fc6169a26c75c353e65425b3e56eef/propcache-0.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd6f30fdcf9ae2a70abd34da54f18da086160e4d7d9251f81f3da0ff84fc5a48", size = 210030, upload-time = "2025-10-08T19:46:33.969Z" }, + { url = "https://files.pythonhosted.org/packages/40/e2/27e6feebb5f6b8408fa29f5efbb765cd54c153ac77314d27e457a3e993b7/propcache-0.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fc38cba02d1acba4e2869eef1a57a43dfbd3d49a59bf90dda7444ec2be6a5570", size = 208252, upload-time = "2025-10-08T19:46:35.309Z" }, + { url = "https://files.pythonhosted.org/packages/9e/f8/91c27b22ccda1dbc7967f921c42825564fa5336a01ecd72eb78a9f4f53c2/propcache-0.4.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:67fad6162281e80e882fb3ec355398cf72864a54069d060321f6cd0ade95fe85", size = 202064, upload-time = "2025-10-08T19:46:36.993Z" }, + { url = "https://files.pythonhosted.org/packages/f2/26/7f00bd6bd1adba5aafe5f4a66390f243acab58eab24ff1a08bebb2ef9d40/propcache-0.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f10207adf04d08bec185bae14d9606a1444715bc99180f9331c9c02093e1959e", size = 212429, upload-time = "2025-10-08T19:46:38.398Z" }, + { url = "https://files.pythonhosted.org/packages/84/89/fd108ba7815c1117ddca79c228f3f8a15fc82a73bca8b142eb5de13b2785/propcache-0.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e9b0d8d0845bbc4cfcdcbcdbf5086886bc8157aa963c31c777ceff7846c77757", size = 216727, upload-time = "2025-10-08T19:46:39.732Z" }, + { url = "https://files.pythonhosted.org/packages/79/37/3ec3f7e3173e73f1d600495d8b545b53802cbf35506e5732dd8578db3724/propcache-0.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:981333cb2f4c1896a12f4ab92a9cc8f09ea664e9b7dbdc4eff74627af3a11c0f", size = 205097, upload-time = "2025-10-08T19:46:41.025Z" }, + { url = "https://files.pythonhosted.org/packages/61/b0/b2631c19793f869d35f47d5a3a56fb19e9160d3c119f15ac7344fc3ccae7/propcache-0.4.1-cp311-cp311-win32.whl", hash = "sha256:f1d2f90aeec838a52f1c1a32fe9a619fefd5e411721a9117fbf82aea638fe8a1", size = 38084, upload-time = "2025-10-08T19:46:42.693Z" }, + { url = "https://files.pythonhosted.org/packages/f4/78/6cce448e2098e9f3bfc91bb877f06aa24b6ccace872e39c53b2f707c4648/propcache-0.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:364426a62660f3f699949ac8c621aad6977be7126c5807ce48c0aeb8e7333ea6", size = 41637, upload-time = "2025-10-08T19:46:43.778Z" }, + { url = "https://files.pythonhosted.org/packages/9c/e9/754f180cccd7f51a39913782c74717c581b9cc8177ad0e949f4d51812383/propcache-0.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:e53f3a38d3510c11953f3e6a33f205c6d1b001129f972805ca9b42fc308bc239", size = 38064, upload-time = "2025-10-08T19:46:44.872Z" }, + { url = "https://files.pythonhosted.org/packages/a2/0f/f17b1b2b221d5ca28b4b876e8bb046ac40466513960646bda8e1853cdfa2/propcache-0.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e153e9cd40cc8945138822807139367f256f89c6810c2634a4f6902b52d3b4e2", size = 80061, upload-time = "2025-10-08T19:46:46.075Z" }, + { url = "https://files.pythonhosted.org/packages/76/47/8ccf75935f51448ba9a16a71b783eb7ef6b9ee60f5d14c7f8a8a79fbeed7/propcache-0.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cd547953428f7abb73c5ad82cbb32109566204260d98e41e5dfdc682eb7f8403", size = 46037, upload-time = "2025-10-08T19:46:47.23Z" }, + { url = "https://files.pythonhosted.org/packages/0a/b6/5c9a0e42df4d00bfb4a3cbbe5cf9f54260300c88a0e9af1f47ca5ce17ac0/propcache-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f048da1b4f243fc44f205dfd320933a951b8d89e0afd4c7cacc762a8b9165207", size = 47324, upload-time = "2025-10-08T19:46:48.384Z" }, + { url = "https://files.pythonhosted.org/packages/9e/d3/6c7ee328b39a81ee877c962469f1e795f9db87f925251efeb0545e0020d0/propcache-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ec17c65562a827bba85e3872ead335f95405ea1674860d96483a02f5c698fa72", size = 225505, upload-time = "2025-10-08T19:46:50.055Z" }, + { url = "https://files.pythonhosted.org/packages/01/5d/1c53f4563490b1d06a684742cc6076ef944bc6457df6051b7d1a877c057b/propcache-0.4.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:405aac25c6394ef275dee4c709be43745d36674b223ba4eb7144bf4d691b7367", size = 230242, upload-time = "2025-10-08T19:46:51.815Z" }, + { url = "https://files.pythonhosted.org/packages/20/e1/ce4620633b0e2422207c3cb774a0ee61cac13abc6217763a7b9e2e3f4a12/propcache-0.4.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0013cb6f8dde4b2a2f66903b8ba740bdfe378c943c4377a200551ceb27f379e4", size = 238474, upload-time = "2025-10-08T19:46:53.208Z" }, + { url = "https://files.pythonhosted.org/packages/46/4b/3aae6835b8e5f44ea6a68348ad90f78134047b503765087be2f9912140ea/propcache-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:15932ab57837c3368b024473a525e25d316d8353016e7cc0e5ba9eb343fbb1cf", size = 221575, upload-time = "2025-10-08T19:46:54.511Z" }, + { url = "https://files.pythonhosted.org/packages/6e/a5/8a5e8678bcc9d3a1a15b9a29165640d64762d424a16af543f00629c87338/propcache-0.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:031dce78b9dc099f4c29785d9cf5577a3faf9ebf74ecbd3c856a7b92768c3df3", size = 216736, upload-time = "2025-10-08T19:46:56.212Z" }, + { url = "https://files.pythonhosted.org/packages/f1/63/b7b215eddeac83ca1c6b934f89d09a625aa9ee4ba158338854c87210cc36/propcache-0.4.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ab08df6c9a035bee56e31af99be621526bd237bea9f32def431c656b29e41778", size = 213019, upload-time = "2025-10-08T19:46:57.595Z" }, + { url = "https://files.pythonhosted.org/packages/57/74/f580099a58c8af587cac7ba19ee7cb418506342fbbe2d4a4401661cca886/propcache-0.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4d7af63f9f93fe593afbf104c21b3b15868efb2c21d07d8732c0c4287e66b6a6", size = 220376, upload-time = "2025-10-08T19:46:59.067Z" }, + { url = "https://files.pythonhosted.org/packages/c4/ee/542f1313aff7eaf19c2bb758c5d0560d2683dac001a1c96d0774af799843/propcache-0.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cfc27c945f422e8b5071b6e93169679e4eb5bf73bbcbf1ba3ae3a83d2f78ebd9", size = 226988, upload-time = "2025-10-08T19:47:00.544Z" }, + { url = "https://files.pythonhosted.org/packages/8f/18/9c6b015dd9c6930f6ce2229e1f02fb35298b847f2087ea2b436a5bfa7287/propcache-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:35c3277624a080cc6ec6f847cbbbb5b49affa3598c4535a0a4682a697aaa5c75", size = 215615, upload-time = "2025-10-08T19:47:01.968Z" }, + { url = "https://files.pythonhosted.org/packages/80/9e/e7b85720b98c45a45e1fca6a177024934dc9bc5f4d5dd04207f216fc33ed/propcache-0.4.1-cp312-cp312-win32.whl", hash = "sha256:671538c2262dadb5ba6395e26c1731e1d52534bfe9ae56d0b5573ce539266aa8", size = 38066, upload-time = "2025-10-08T19:47:03.503Z" }, + { url = "https://files.pythonhosted.org/packages/54/09/d19cff2a5aaac632ec8fc03737b223597b1e347416934c1b3a7df079784c/propcache-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:cb2d222e72399fcf5890d1d5cc1060857b9b236adff2792ff48ca2dfd46c81db", size = 41655, upload-time = "2025-10-08T19:47:04.973Z" }, + { url = "https://files.pythonhosted.org/packages/68/ab/6b5c191bb5de08036a8c697b265d4ca76148efb10fa162f14af14fb5f076/propcache-0.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:204483131fb222bdaaeeea9f9e6c6ed0cac32731f75dfc1d4a567fc1926477c1", size = 37789, upload-time = "2025-10-08T19:47:06.077Z" }, + { url = "https://files.pythonhosted.org/packages/bf/df/6d9c1b6ac12b003837dde8a10231a7344512186e87b36e855bef32241942/propcache-0.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:43eedf29202c08550aac1d14e0ee619b0430aaef78f85864c1a892294fbc28cf", size = 77750, upload-time = "2025-10-08T19:47:07.648Z" }, + { url = "https://files.pythonhosted.org/packages/8b/e8/677a0025e8a2acf07d3418a2e7ba529c9c33caf09d3c1f25513023c1db56/propcache-0.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d62cdfcfd89ccb8de04e0eda998535c406bf5e060ffd56be6c586cbcc05b3311", size = 44780, upload-time = "2025-10-08T19:47:08.851Z" }, + { url = "https://files.pythonhosted.org/packages/89/a4/92380f7ca60f99ebae761936bc48a72a639e8a47b29050615eef757cb2a7/propcache-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cae65ad55793da34db5f54e4029b89d3b9b9490d8abe1b4c7ab5d4b8ec7ebf74", size = 46308, upload-time = "2025-10-08T19:47:09.982Z" }, + { url = "https://files.pythonhosted.org/packages/2d/48/c5ac64dee5262044348d1d78a5f85dd1a57464a60d30daee946699963eb3/propcache-0.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:333ddb9031d2704a301ee3e506dc46b1fe5f294ec198ed6435ad5b6a085facfe", size = 208182, upload-time = "2025-10-08T19:47:11.319Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0c/cd762dd011a9287389a6a3eb43aa30207bde253610cca06824aeabfe9653/propcache-0.4.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fd0858c20f078a32cf55f7e81473d96dcf3b93fd2ccdb3d40fdf54b8573df3af", size = 211215, upload-time = "2025-10-08T19:47:13.146Z" }, + { url = "https://files.pythonhosted.org/packages/30/3e/49861e90233ba36890ae0ca4c660e95df565b2cd15d4a68556ab5865974e/propcache-0.4.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:678ae89ebc632c5c204c794f8dab2837c5f159aeb59e6ed0539500400577298c", size = 218112, upload-time = "2025-10-08T19:47:14.913Z" }, + { url = "https://files.pythonhosted.org/packages/f1/8b/544bc867e24e1bd48f3118cecd3b05c694e160a168478fa28770f22fd094/propcache-0.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d472aeb4fbf9865e0c6d622d7f4d54a4e101a89715d8904282bb5f9a2f476c3f", size = 204442, upload-time = "2025-10-08T19:47:16.277Z" }, + { url = "https://files.pythonhosted.org/packages/50/a6/4282772fd016a76d3e5c0df58380a5ea64900afd836cec2c2f662d1b9bb3/propcache-0.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4d3df5fa7e36b3225954fba85589da77a0fe6a53e3976de39caf04a0db4c36f1", size = 199398, upload-time = "2025-10-08T19:47:17.962Z" }, + { url = "https://files.pythonhosted.org/packages/3e/ec/d8a7cd406ee1ddb705db2139f8a10a8a427100347bd698e7014351c7af09/propcache-0.4.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ee17f18d2498f2673e432faaa71698032b0127ebf23ae5974eeaf806c279df24", size = 196920, upload-time = "2025-10-08T19:47:19.355Z" }, + { url = "https://files.pythonhosted.org/packages/f6/6c/f38ab64af3764f431e359f8baf9e0a21013e24329e8b85d2da32e8ed07ca/propcache-0.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:580e97762b950f993ae618e167e7be9256b8353c2dcd8b99ec100eb50f5286aa", size = 203748, upload-time = "2025-10-08T19:47:21.338Z" }, + { url = "https://files.pythonhosted.org/packages/d6/e3/fa846bd70f6534d647886621388f0a265254d30e3ce47e5c8e6e27dbf153/propcache-0.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:501d20b891688eb8e7aa903021f0b72d5a55db40ffaab27edefd1027caaafa61", size = 205877, upload-time = "2025-10-08T19:47:23.059Z" }, + { url = "https://files.pythonhosted.org/packages/e2/39/8163fc6f3133fea7b5f2827e8eba2029a0277ab2c5beee6c1db7b10fc23d/propcache-0.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a0bd56e5b100aef69bd8562b74b46254e7c8812918d3baa700c8a8009b0af66", size = 199437, upload-time = "2025-10-08T19:47:24.445Z" }, + { url = "https://files.pythonhosted.org/packages/93/89/caa9089970ca49c7c01662bd0eeedfe85494e863e8043565aeb6472ce8fe/propcache-0.4.1-cp313-cp313-win32.whl", hash = "sha256:bcc9aaa5d80322bc2fb24bb7accb4a30f81e90ab8d6ba187aec0744bc302ad81", size = 37586, upload-time = "2025-10-08T19:47:25.736Z" }, + { url = "https://files.pythonhosted.org/packages/f5/ab/f76ec3c3627c883215b5c8080debb4394ef5a7a29be811f786415fc1e6fd/propcache-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:381914df18634f5494334d201e98245c0596067504b9372d8cf93f4bb23e025e", size = 40790, upload-time = "2025-10-08T19:47:26.847Z" }, + { url = "https://files.pythonhosted.org/packages/59/1b/e71ae98235f8e2ba5004d8cb19765a74877abf189bc53fc0c80d799e56c3/propcache-0.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:8873eb4460fd55333ea49b7d189749ecf6e55bf85080f11b1c4530ed3034cba1", size = 37158, upload-time = "2025-10-08T19:47:27.961Z" }, + { url = "https://files.pythonhosted.org/packages/83/ce/a31bbdfc24ee0dcbba458c8175ed26089cf109a55bbe7b7640ed2470cfe9/propcache-0.4.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:92d1935ee1f8d7442da9c0c4fa7ac20d07e94064184811b685f5c4fada64553b", size = 81451, upload-time = "2025-10-08T19:47:29.445Z" }, + { url = "https://files.pythonhosted.org/packages/25/9c/442a45a470a68456e710d96cacd3573ef26a1d0a60067e6a7d5e655621ed/propcache-0.4.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:473c61b39e1460d386479b9b2f337da492042447c9b685f28be4f74d3529e566", size = 46374, upload-time = "2025-10-08T19:47:30.579Z" }, + { url = "https://files.pythonhosted.org/packages/f4/bf/b1d5e21dbc3b2e889ea4327044fb16312a736d97640fb8b6aa3f9c7b3b65/propcache-0.4.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c0ef0aaafc66fbd87842a3fe3902fd889825646bc21149eafe47be6072725835", size = 48396, upload-time = "2025-10-08T19:47:31.79Z" }, + { url = "https://files.pythonhosted.org/packages/f4/04/5b4c54a103d480e978d3c8a76073502b18db0c4bc17ab91b3cb5092ad949/propcache-0.4.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95393b4d66bfae908c3ca8d169d5f79cd65636ae15b5e7a4f6e67af675adb0e", size = 275950, upload-time = "2025-10-08T19:47:33.481Z" }, + { url = "https://files.pythonhosted.org/packages/b4/c1/86f846827fb969c4b78b0af79bba1d1ea2156492e1b83dea8b8a6ae27395/propcache-0.4.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c07fda85708bc48578467e85099645167a955ba093be0a2dcba962195676e859", size = 273856, upload-time = "2025-10-08T19:47:34.906Z" }, + { url = "https://files.pythonhosted.org/packages/36/1d/fc272a63c8d3bbad6878c336c7a7dea15e8f2d23a544bda43205dfa83ada/propcache-0.4.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:af223b406d6d000830c6f65f1e6431783fc3f713ba3e6cc8c024d5ee96170a4b", size = 280420, upload-time = "2025-10-08T19:47:36.338Z" }, + { url = "https://files.pythonhosted.org/packages/07/0c/01f2219d39f7e53d52e5173bcb09c976609ba30209912a0680adfb8c593a/propcache-0.4.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a78372c932c90ee474559c5ddfffd718238e8673c340dc21fe45c5b8b54559a0", size = 263254, upload-time = "2025-10-08T19:47:37.692Z" }, + { url = "https://files.pythonhosted.org/packages/2d/18/cd28081658ce597898f0c4d174d4d0f3c5b6d4dc27ffafeef835c95eb359/propcache-0.4.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:564d9f0d4d9509e1a870c920a89b2fec951b44bf5ba7d537a9e7c1ccec2c18af", size = 261205, upload-time = "2025-10-08T19:47:39.659Z" }, + { url = "https://files.pythonhosted.org/packages/7a/71/1f9e22eb8b8316701c2a19fa1f388c8a3185082607da8e406a803c9b954e/propcache-0.4.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:17612831fda0138059cc5546f4d12a2aacfb9e47068c06af35c400ba58ba7393", size = 247873, upload-time = "2025-10-08T19:47:41.084Z" }, + { url = "https://files.pythonhosted.org/packages/4a/65/3d4b61f36af2b4eddba9def857959f1016a51066b4f1ce348e0cf7881f58/propcache-0.4.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:41a89040cb10bd345b3c1a873b2bf36413d48da1def52f268a055f7398514874", size = 262739, upload-time = "2025-10-08T19:47:42.51Z" }, + { url = "https://files.pythonhosted.org/packages/2a/42/26746ab087faa77c1c68079b228810436ccd9a5ce9ac85e2b7307195fd06/propcache-0.4.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e35b88984e7fa64aacecea39236cee32dd9bd8c55f57ba8a75cf2399553f9bd7", size = 263514, upload-time = "2025-10-08T19:47:43.927Z" }, + { url = "https://files.pythonhosted.org/packages/94/13/630690fe201f5502d2403dd3cfd451ed8858fe3c738ee88d095ad2ff407b/propcache-0.4.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f8b465489f927b0df505cbe26ffbeed4d6d8a2bbc61ce90eb074ff129ef0ab1", size = 257781, upload-time = "2025-10-08T19:47:45.448Z" }, + { url = "https://files.pythonhosted.org/packages/92/f7/1d4ec5841505f423469efbfc381d64b7b467438cd5a4bbcbb063f3b73d27/propcache-0.4.1-cp313-cp313t-win32.whl", hash = "sha256:2ad890caa1d928c7c2965b48f3a3815c853180831d0e5503d35cf00c472f4717", size = 41396, upload-time = "2025-10-08T19:47:47.202Z" }, + { url = "https://files.pythonhosted.org/packages/48/f0/615c30622316496d2cbbc29f5985f7777d3ada70f23370608c1d3e081c1f/propcache-0.4.1-cp313-cp313t-win_amd64.whl", hash = "sha256:f7ee0e597f495cf415bcbd3da3caa3bd7e816b74d0d52b8145954c5e6fd3ff37", size = 44897, upload-time = "2025-10-08T19:47:48.336Z" }, + { url = "https://files.pythonhosted.org/packages/fd/ca/6002e46eccbe0e33dcd4069ef32f7f1c9e243736e07adca37ae8c4830ec3/propcache-0.4.1-cp313-cp313t-win_arm64.whl", hash = "sha256:929d7cbe1f01bb7baffb33dc14eb5691c95831450a26354cd210a8155170c93a", size = 39789, upload-time = "2025-10-08T19:47:49.876Z" }, + { url = "https://files.pythonhosted.org/packages/8e/5c/bca52d654a896f831b8256683457ceddd490ec18d9ec50e97dfd8fc726a8/propcache-0.4.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3f7124c9d820ba5548d431afb4632301acf965db49e666aa21c305cbe8c6de12", size = 78152, upload-time = "2025-10-08T19:47:51.051Z" }, + { url = "https://files.pythonhosted.org/packages/65/9b/03b04e7d82a5f54fb16113d839f5ea1ede58a61e90edf515f6577c66fa8f/propcache-0.4.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:c0d4b719b7da33599dfe3b22d3db1ef789210a0597bc650b7cee9c77c2be8c5c", size = 44869, upload-time = "2025-10-08T19:47:52.594Z" }, + { url = "https://files.pythonhosted.org/packages/b2/fa/89a8ef0468d5833a23fff277b143d0573897cf75bd56670a6d28126c7d68/propcache-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9f302f4783709a78240ebc311b793f123328716a60911d667e0c036bc5dcbded", size = 46596, upload-time = "2025-10-08T19:47:54.073Z" }, + { url = "https://files.pythonhosted.org/packages/86/bd/47816020d337f4a746edc42fe8d53669965138f39ee117414c7d7a340cfe/propcache-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c80ee5802e3fb9ea37938e7eecc307fb984837091d5fd262bb37238b1ae97641", size = 206981, upload-time = "2025-10-08T19:47:55.715Z" }, + { url = "https://files.pythonhosted.org/packages/df/f6/c5fa1357cc9748510ee55f37173eb31bfde6d94e98ccd9e6f033f2fc06e1/propcache-0.4.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ed5a841e8bb29a55fb8159ed526b26adc5bdd7e8bd7bf793ce647cb08656cdf4", size = 211490, upload-time = "2025-10-08T19:47:57.499Z" }, + { url = "https://files.pythonhosted.org/packages/80/1e/e5889652a7c4a3846683401a48f0f2e5083ce0ec1a8a5221d8058fbd1adf/propcache-0.4.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:55c72fd6ea2da4c318e74ffdf93c4fe4e926051133657459131a95c846d16d44", size = 215371, upload-time = "2025-10-08T19:47:59.317Z" }, + { url = "https://files.pythonhosted.org/packages/b2/f2/889ad4b2408f72fe1a4f6a19491177b30ea7bf1a0fd5f17050ca08cfc882/propcache-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8326e144341460402713f91df60ade3c999d601e7eb5ff8f6f7862d54de0610d", size = 201424, upload-time = "2025-10-08T19:48:00.67Z" }, + { url = "https://files.pythonhosted.org/packages/27/73/033d63069b57b0812c8bd19f311faebeceb6ba31b8f32b73432d12a0b826/propcache-0.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:060b16ae65bc098da7f6d25bf359f1f31f688384858204fe5d652979e0015e5b", size = 197566, upload-time = "2025-10-08T19:48:02.604Z" }, + { url = "https://files.pythonhosted.org/packages/dc/89/ce24f3dc182630b4e07aa6d15f0ff4b14ed4b9955fae95a0b54c58d66c05/propcache-0.4.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:89eb3fa9524f7bec9de6e83cf3faed9d79bffa560672c118a96a171a6f55831e", size = 193130, upload-time = "2025-10-08T19:48:04.499Z" }, + { url = "https://files.pythonhosted.org/packages/a9/24/ef0d5fd1a811fb5c609278d0209c9f10c35f20581fcc16f818da959fc5b4/propcache-0.4.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:dee69d7015dc235f526fe80a9c90d65eb0039103fe565776250881731f06349f", size = 202625, upload-time = "2025-10-08T19:48:06.213Z" }, + { url = "https://files.pythonhosted.org/packages/f5/02/98ec20ff5546f68d673df2f7a69e8c0d076b5abd05ca882dc7ee3a83653d/propcache-0.4.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:5558992a00dfd54ccbc64a32726a3357ec93825a418a401f5cc67df0ac5d9e49", size = 204209, upload-time = "2025-10-08T19:48:08.432Z" }, + { url = "https://files.pythonhosted.org/packages/a0/87/492694f76759b15f0467a2a93ab68d32859672b646aa8a04ce4864e7932d/propcache-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c9b822a577f560fbd9554812526831712c1436d2c046cedee4c3796d3543b144", size = 197797, upload-time = "2025-10-08T19:48:09.968Z" }, + { url = "https://files.pythonhosted.org/packages/ee/36/66367de3575db1d2d3f3d177432bd14ee577a39d3f5d1b3d5df8afe3b6e2/propcache-0.4.1-cp314-cp314-win32.whl", hash = "sha256:ab4c29b49d560fe48b696cdcb127dd36e0bc2472548f3bf56cc5cb3da2b2984f", size = 38140, upload-time = "2025-10-08T19:48:11.232Z" }, + { url = "https://files.pythonhosted.org/packages/0c/2a/a758b47de253636e1b8aef181c0b4f4f204bf0dd964914fb2af90a95b49b/propcache-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:5a103c3eb905fcea0ab98be99c3a9a5ab2de60228aa5aceedc614c0281cf6153", size = 41257, upload-time = "2025-10-08T19:48:12.707Z" }, + { url = "https://files.pythonhosted.org/packages/34/5e/63bd5896c3fec12edcbd6f12508d4890d23c265df28c74b175e1ef9f4f3b/propcache-0.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:74c1fb26515153e482e00177a1ad654721bf9207da8a494a0c05e797ad27b992", size = 38097, upload-time = "2025-10-08T19:48:13.923Z" }, + { url = "https://files.pythonhosted.org/packages/99/85/9ff785d787ccf9bbb3f3106f79884a130951436f58392000231b4c737c80/propcache-0.4.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:824e908bce90fb2743bd6b59db36eb4f45cd350a39637c9f73b1c1ea66f5b75f", size = 81455, upload-time = "2025-10-08T19:48:15.16Z" }, + { url = "https://files.pythonhosted.org/packages/90/85/2431c10c8e7ddb1445c1f7c4b54d886e8ad20e3c6307e7218f05922cad67/propcache-0.4.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c2b5e7db5328427c57c8e8831abda175421b709672f6cfc3d630c3b7e2146393", size = 46372, upload-time = "2025-10-08T19:48:16.424Z" }, + { url = "https://files.pythonhosted.org/packages/01/20/b0972d902472da9bcb683fa595099911f4d2e86e5683bcc45de60dd05dc3/propcache-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6f6ff873ed40292cd4969ef5310179afd5db59fdf055897e282485043fc80ad0", size = 48411, upload-time = "2025-10-08T19:48:17.577Z" }, + { url = "https://files.pythonhosted.org/packages/e2/e3/7dc89f4f21e8f99bad3d5ddb3a3389afcf9da4ac69e3deb2dcdc96e74169/propcache-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49a2dc67c154db2c1463013594c458881a069fcf98940e61a0569016a583020a", size = 275712, upload-time = "2025-10-08T19:48:18.901Z" }, + { url = "https://files.pythonhosted.org/packages/20/67/89800c8352489b21a8047c773067644e3897f02ecbbd610f4d46b7f08612/propcache-0.4.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:005f08e6a0529984491e37d8dbc3dd86f84bd78a8ceb5fa9a021f4c48d4984be", size = 273557, upload-time = "2025-10-08T19:48:20.762Z" }, + { url = "https://files.pythonhosted.org/packages/e2/a1/b52b055c766a54ce6d9c16d9aca0cad8059acd9637cdf8aa0222f4a026ef/propcache-0.4.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5c3310452e0d31390da9035c348633b43d7e7feb2e37be252be6da45abd1abcc", size = 280015, upload-time = "2025-10-08T19:48:22.592Z" }, + { url = "https://files.pythonhosted.org/packages/48/c8/33cee30bd890672c63743049f3c9e4be087e6780906bfc3ec58528be59c1/propcache-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c3c70630930447f9ef1caac7728c8ad1c56bc5015338b20fed0d08ea2480b3a", size = 262880, upload-time = "2025-10-08T19:48:23.947Z" }, + { url = "https://files.pythonhosted.org/packages/0c/b1/8f08a143b204b418285c88b83d00edbd61afbc2c6415ffafc8905da7038b/propcache-0.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8e57061305815dfc910a3634dcf584f08168a8836e6999983569f51a8544cd89", size = 260938, upload-time = "2025-10-08T19:48:25.656Z" }, + { url = "https://files.pythonhosted.org/packages/cf/12/96e4664c82ca2f31e1c8dff86afb867348979eb78d3cb8546a680287a1e9/propcache-0.4.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:521a463429ef54143092c11a77e04056dd00636f72e8c45b70aaa3140d639726", size = 247641, upload-time = "2025-10-08T19:48:27.207Z" }, + { url = "https://files.pythonhosted.org/packages/18/ed/e7a9cfca28133386ba52278136d42209d3125db08d0a6395f0cba0c0285c/propcache-0.4.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:120c964da3fdc75e3731aa392527136d4ad35868cc556fd09bb6d09172d9a367", size = 262510, upload-time = "2025-10-08T19:48:28.65Z" }, + { url = "https://files.pythonhosted.org/packages/f5/76/16d8bf65e8845dd62b4e2b57444ab81f07f40caa5652b8969b87ddcf2ef6/propcache-0.4.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:d8f353eb14ee3441ee844ade4277d560cdd68288838673273b978e3d6d2c8f36", size = 263161, upload-time = "2025-10-08T19:48:30.133Z" }, + { url = "https://files.pythonhosted.org/packages/e7/70/c99e9edb5d91d5ad8a49fa3c1e8285ba64f1476782fed10ab251ff413ba1/propcache-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ab2943be7c652f09638800905ee1bab2c544e537edb57d527997a24c13dc1455", size = 257393, upload-time = "2025-10-08T19:48:31.567Z" }, + { url = "https://files.pythonhosted.org/packages/08/02/87b25304249a35c0915d236575bc3574a323f60b47939a2262b77632a3ee/propcache-0.4.1-cp314-cp314t-win32.whl", hash = "sha256:05674a162469f31358c30bcaa8883cb7829fa3110bf9c0991fe27d7896c42d85", size = 42546, upload-time = "2025-10-08T19:48:32.872Z" }, + { url = "https://files.pythonhosted.org/packages/cb/ef/3c6ecf8b317aa982f309835e8f96987466123c6e596646d4e6a1dfcd080f/propcache-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:990f6b3e2a27d683cb7602ed6c86f15ee6b43b1194736f9baaeb93d0016633b1", size = 46259, upload-time = "2025-10-08T19:48:34.226Z" }, + { url = "https://files.pythonhosted.org/packages/c4/2d/346e946d4951f37eca1e4f55be0f0174c52cd70720f84029b02f296f4a38/propcache-0.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:ecef2343af4cc68e05131e45024ba34f6095821988a9d0a02aa7c73fcc448aa9", size = 40428, upload-time = "2025-10-08T19:48:35.441Z" }, + { url = "https://files.pythonhosted.org/packages/9b/01/0ebaec9003f5d619a7475165961f8e3083cf8644d704b60395df3601632d/propcache-0.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3d233076ccf9e450c8b3bc6720af226b898ef5d051a2d145f7d765e6e9f9bcff", size = 80277, upload-time = "2025-10-08T19:48:36.647Z" }, + { url = "https://files.pythonhosted.org/packages/34/58/04af97ac586b4ef6b9026c3fd36ee7798b737a832f5d3440a4280dcebd3a/propcache-0.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:357f5bb5c377a82e105e44bd3d52ba22b616f7b9773714bff93573988ef0a5fb", size = 45865, upload-time = "2025-10-08T19:48:37.859Z" }, + { url = "https://files.pythonhosted.org/packages/7c/19/b65d98ae21384518b291d9939e24a8aeac4fdb5101b732576f8f7540e834/propcache-0.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cbc3b6dfc728105b2a57c06791eb07a94229202ea75c59db644d7d496b698cac", size = 47636, upload-time = "2025-10-08T19:48:39.038Z" }, + { url = "https://files.pythonhosted.org/packages/b3/0f/317048c6d91c356c7154dca5af019e6effeb7ee15fa6a6db327cc19e12b4/propcache-0.4.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:182b51b421f0501952d938dc0b0eb45246a5b5153c50d42b495ad5fb7517c888", size = 201126, upload-time = "2025-10-08T19:48:40.774Z" }, + { url = "https://files.pythonhosted.org/packages/71/69/0b2a7a5a6ee83292b4b997dbd80549d8ce7d40b6397c1646c0d9495f5a85/propcache-0.4.1-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4b536b39c5199b96fc6245eb5fb796c497381d3942f169e44e8e392b29c9ebcc", size = 209837, upload-time = "2025-10-08T19:48:42.167Z" }, + { url = "https://files.pythonhosted.org/packages/a5/92/c699ac495a6698df6e497fc2de27af4b6ace10d8e76528357ce153722e45/propcache-0.4.1-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:db65d2af507bbfbdcedb254a11149f894169d90488dd3e7190f7cdcb2d6cd57a", size = 215578, upload-time = "2025-10-08T19:48:43.56Z" }, + { url = "https://files.pythonhosted.org/packages/b3/ee/14de81c5eb02c0ee4f500b4e39c4e1bd0677c06e72379e6ab18923c773fc/propcache-0.4.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd2dbc472da1f772a4dae4fa24be938a6c544671a912e30529984dd80400cd88", size = 197187, upload-time = "2025-10-08T19:48:45.309Z" }, + { url = "https://files.pythonhosted.org/packages/1d/94/48dce9aaa6d8dd5a0859bad75158ec522546d4ac23f8e2f05fac469477dd/propcache-0.4.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:daede9cd44e0f8bdd9e6cc9a607fc81feb80fae7a5fc6cecaff0e0bb32e42d00", size = 193478, upload-time = "2025-10-08T19:48:47.743Z" }, + { url = "https://files.pythonhosted.org/packages/60/b5/0516b563e801e1ace212afde869a0596a0d7115eec0b12d296d75633fb29/propcache-0.4.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:71b749281b816793678ae7f3d0d84bd36e694953822eaad408d682efc5ca18e0", size = 190650, upload-time = "2025-10-08T19:48:49.373Z" }, + { url = "https://files.pythonhosted.org/packages/24/89/e0f7d4a5978cd56f8cd67735f74052f257dc471ec901694e430f0d1572fe/propcache-0.4.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:0002004213ee1f36cfb3f9a42b5066100c44276b9b72b4e1504cddd3d692e86e", size = 200251, upload-time = "2025-10-08T19:48:51.4Z" }, + { url = "https://files.pythonhosted.org/packages/06/7d/a1fac863d473876ed4406c914f2e14aa82d2f10dd207c9e16fc383cc5a24/propcache-0.4.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:fe49d0a85038f36ba9e3ffafa1103e61170b28e95b16622e11be0a0ea07c6781", size = 200919, upload-time = "2025-10-08T19:48:53.227Z" }, + { url = "https://files.pythonhosted.org/packages/c3/4e/f86a256ff24944cf5743e4e6c6994e3526f6acfcfb55e21694c2424f758c/propcache-0.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:99d43339c83aaf4d32bda60928231848eee470c6bda8d02599cc4cebe872d183", size = 193211, upload-time = "2025-10-08T19:48:55.027Z" }, + { url = "https://files.pythonhosted.org/packages/6e/3f/3fbad5f4356b068f1b047d300a6ff2c66614d7030f078cd50be3fec04228/propcache-0.4.1-cp39-cp39-win32.whl", hash = "sha256:a129e76735bc792794d5177069691c3217898b9f5cee2b2661471e52ffe13f19", size = 38314, upload-time = "2025-10-08T19:48:56.792Z" }, + { url = "https://files.pythonhosted.org/packages/a4/45/d78d136c3a3d215677abb886785aae744da2c3005bcb99e58640c56529b1/propcache-0.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:948dab269721ae9a87fd16c514a0a2c2a1bdb23a9a61b969b0f9d9ee2968546f", size = 41912, upload-time = "2025-10-08T19:48:57.995Z" }, + { url = "https://files.pythonhosted.org/packages/fc/2a/b0632941f25139f4e58450b307242951f7c2717a5704977c6d5323a800af/propcache-0.4.1-cp39-cp39-win_arm64.whl", hash = "sha256:5fd37c406dd6dc85aa743e214cef35dc54bbdd1419baac4f6ae5e5b1a2976938", size = 38450, upload-time = "2025-10-08T19:48:59.349Z" }, + { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" }, +] + +[[package]] +name = "pydantic" +version = "2.13.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d9/e4/40d09941a2cebcb20609b86a559817d5b9291c49dd6f8c87e5feffbe703a/pydantic-2.13.3.tar.gz", hash = "sha256:af09e9d1d09f4e7fe37145c1f577e1d61ceb9a41924bf0094a36506285d0a84d", size = 844068, upload-time = "2026-04-20T14:46:43.632Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f3/0a/fd7d723f8f8153418fb40cf9c940e82004fce7e987026b08a68a36dd3fe7/pydantic-2.13.3-py3-none-any.whl", hash = "sha256:6db14ac8dfc9a1e57f87ea2c0de670c251240f43cb0c30a5130e9720dc612927", size = 471981, upload-time = "2026-04-20T14:46:41.402Z" }, +] + +[[package]] +name = "pydantic-core" +version = "2.46.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2a/ef/f7abb56c49382a246fd2ce9c799691e3c3e7175ec74b14d99e798bcddb1a/pydantic_core-2.46.3.tar.gz", hash = "sha256:41c178f65b8c29807239d47e6050262eb6bf84eb695e41101e62e38df4a5bc2c", size = 471412, upload-time = "2026-04-20T14:40:56.672Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/98/b50eb9a411e87483b5c65dba4fa430a06bac4234d3403a40e5a9905ebcd0/pydantic_core-2.46.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:1da3786b8018e60349680720158cc19161cc3b4bdd815beb0a321cd5ce1ad5b1", size = 2108971, upload-time = "2026-04-20T14:43:51.945Z" }, + { url = "https://files.pythonhosted.org/packages/08/4b/f364b9d161718ff2217160a4b5d41ce38de60aed91c3689ebffa1c939d23/pydantic_core-2.46.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cc0988cb29d21bf4a9d5cf2ef970b5c0e38d8d8e107a493278c05dc6c1dda69f", size = 1949588, upload-time = "2026-04-20T14:44:10.386Z" }, + { url = "https://files.pythonhosted.org/packages/8f/8b/30bd03ee83b2f5e29f5ba8e647ab3c456bf56f2ec72fdbcc0215484a0854/pydantic_core-2.46.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27f9067c3bfadd04c55484b89c0d267981b2f3512850f6f66e1e74204a4e4ce3", size = 1975986, upload-time = "2026-04-20T14:43:57.106Z" }, + { url = "https://files.pythonhosted.org/packages/3c/54/13ccf954d84ec275d5d023d5786e4aa48840bc9f161f2838dc98e1153518/pydantic_core-2.46.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a642ac886ecf6402d9882d10c405dcf4b902abeb2972cd5fb4a48c83cd59279a", size = 2055830, upload-time = "2026-04-20T14:44:15.499Z" }, + { url = "https://files.pythonhosted.org/packages/be/0e/65f38125e660fdbd72aa858e7dfae893645cfa0e7b13d333e174a367cd23/pydantic_core-2.46.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:79f561438481f28681584b89e2effb22855e2179880314bcddbf5968e935e807", size = 2222340, upload-time = "2026-04-20T14:41:51.353Z" }, + { url = "https://files.pythonhosted.org/packages/d1/88/f3ab7739efe0e7e80777dbb84c59eb98518e3f57ea433206194c2e425272/pydantic_core-2.46.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57a973eae4665352a47cf1a99b4ee864620f2fe663a217d7a8da68a1f3a5bfda", size = 2280727, upload-time = "2026-04-20T14:41:30.461Z" }, + { url = "https://files.pythonhosted.org/packages/2a/6d/c228219080817bec4982f9531cadb18da6aaa770fdeb114f49c237ac2c9f/pydantic_core-2.46.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83d002b97072a53ea150d63e0a3adfae5670cef5aa8a6e490240e482d3b22e57", size = 2092158, upload-time = "2026-04-20T14:44:07.305Z" }, + { url = "https://files.pythonhosted.org/packages/0f/b1/525a16711e7c6d61635fac3b0bd54600b5c5d9f60c6fc5aaab26b64a2297/pydantic_core-2.46.3-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:b40ddd51e7c44b28cfaef746c9d3c506d658885e0a46f9eeef2ee815cbf8e045", size = 2116626, upload-time = "2026-04-20T14:42:34.118Z" }, + { url = "https://files.pythonhosted.org/packages/ef/7c/17d30673351439a6951bf54f564cf2443ab00ae264ec9df00e2efd710eb5/pydantic_core-2.46.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ac5ec7fb9b87f04ee839af2d53bcadea57ded7d229719f56c0ed895bff987943", size = 2160691, upload-time = "2026-04-20T14:41:14.023Z" }, + { url = "https://files.pythonhosted.org/packages/86/66/af8adbcbc0886ead7f1a116606a534d75a307e71e6e08226000d51b880d2/pydantic_core-2.46.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:a3b11c812f61b3129c4905781a2601dfdfdea5fe1e6c1cfb696b55d14e9c054f", size = 2182543, upload-time = "2026-04-20T14:40:48.886Z" }, + { url = "https://files.pythonhosted.org/packages/b0/37/6de71e0f54c54a4190010f57deb749e1ddf75c568ada3b1320b70067f121/pydantic_core-2.46.3-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:1108da631e602e5b3c38d6d04fe5bb3bfa54349e6918e3ca6cf570b2e2b2f9d4", size = 2324513, upload-time = "2026-04-20T14:42:36.121Z" }, + { url = "https://files.pythonhosted.org/packages/51/b1/9fc74ce94f603d5ef59ff258ca9c2c8fb902fb548d340a96f77f4d1c3b7f/pydantic_core-2.46.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:de885175515bcfa98ae618c1df7a072f13d179f81376c8007112af20567fd08a", size = 2361853, upload-time = "2026-04-20T14:43:24.886Z" }, + { url = "https://files.pythonhosted.org/packages/40/d0/4c652fc592db35f100279ee751d5a145aca1b9a7984b9684ba7c1b5b0535/pydantic_core-2.46.3-cp310-cp310-win32.whl", hash = "sha256:d11058e3201527d41bc6b545c79187c9e4bf85e15a236a6007f0e991518882b7", size = 1980465, upload-time = "2026-04-20T14:44:46.239Z" }, + { url = "https://files.pythonhosted.org/packages/27/b8/a920453c38afbe1f355e1ea0b0d94a0a3e0b0879d32d793108755fa171d5/pydantic_core-2.46.3-cp310-cp310-win_amd64.whl", hash = "sha256:3612edf65c8ea67ac13616c4d23af12faef1ae435a8a93e5934c2a0cbbdd1fd6", size = 2073884, upload-time = "2026-04-20T14:43:01.201Z" }, + { url = "https://files.pythonhosted.org/packages/22/a2/1ba90a83e85a3f94c796b184f3efde9c72f2830dcda493eea8d59ba78e6d/pydantic_core-2.46.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ab124d49d0459b2373ecf54118a45c28a1e6d4192a533fbc915e70f556feb8e5", size = 2106740, upload-time = "2026-04-20T14:41:20.932Z" }, + { url = "https://files.pythonhosted.org/packages/b6/f6/99ae893c89a0b9d3daec9f95487aa676709aa83f67643b3f0abaf4ab628a/pydantic_core-2.46.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cca67d52a5c7a16aed2b3999e719c4bcf644074eac304a5d3d62dd70ae7d4b2c", size = 1948293, upload-time = "2026-04-20T14:43:42.115Z" }, + { url = "https://files.pythonhosted.org/packages/3e/b8/2e8e636dc9e3f16c2e16bf0849e24be82c5ee82c603c65fc0326666328fc/pydantic_core-2.46.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c024e08c0ba23e6fd68c771a521e9d6a792f2ebb0fa734296b36394dc30390e", size = 1973222, upload-time = "2026-04-20T14:41:57.841Z" }, + { url = "https://files.pythonhosted.org/packages/34/36/0e730beec4d83c5306f417afbd82ff237d9a21e83c5edf675f31ed84c1fe/pydantic_core-2.46.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6645ce7eec4928e29a1e3b3d5c946621d105d3e79f0c9cddf07c2a9770949287", size = 2053852, upload-time = "2026-04-20T14:40:43.077Z" }, + { url = "https://files.pythonhosted.org/packages/4b/f0/3071131f47e39136a17814576e0fada9168569f7f8c0e6ac4d1ede6a4958/pydantic_core-2.46.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a712c7118e6c5ea96562f7b488435172abb94a3c53c22c9efc1412264a45cbbe", size = 2221134, upload-time = "2026-04-20T14:43:03.349Z" }, + { url = "https://files.pythonhosted.org/packages/2f/a9/a2dc023eec5aa4b02a467874bad32e2446957d2adcab14e107eab502e978/pydantic_core-2.46.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:69a868ef3ff206343579021c40faf3b1edc64b1cc508ff243a28b0a514ccb050", size = 2279785, upload-time = "2026-04-20T14:41:19.285Z" }, + { url = "https://files.pythonhosted.org/packages/0a/44/93f489d16fb63fbd41c670441536541f6e8cfa1e5a69f40bc9c5d30d8c90/pydantic_core-2.46.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc7e8c32db809aa0f6ea1d6869ebc8518a65d5150fdfad8bcae6a49ae32a22e2", size = 2089404, upload-time = "2026-04-20T14:43:10.108Z" }, + { url = "https://files.pythonhosted.org/packages/2a/78/8692e3aa72b2d004f7a5d937f1dfdc8552ba26caf0bec75f342c40f00dec/pydantic_core-2.46.3-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:3481bd1341dc85779ee506bc8e1196a277ace359d89d28588a9468c3ecbe63fa", size = 2114898, upload-time = "2026-04-20T14:44:51.475Z" }, + { url = "https://files.pythonhosted.org/packages/6a/62/e83133f2e7832532060175cebf1f13748f4c7e7e7165cdd1f611f174494b/pydantic_core-2.46.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8690eba565c6d68ffd3a8655525cbdd5246510b44a637ee2c6c03a7ebfe64d3c", size = 2157856, upload-time = "2026-04-20T14:43:46.64Z" }, + { url = "https://files.pythonhosted.org/packages/6d/ec/6a500e3ad7718ee50583fae79c8651f5d37e3abce1fa9ae177ae65842c53/pydantic_core-2.46.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4de88889d7e88d50d40ee5b39d5dac0bcaef9ba91f7e536ac064e6b2834ecccf", size = 2180168, upload-time = "2026-04-20T14:42:00.302Z" }, + { url = "https://files.pythonhosted.org/packages/d8/53/8267811054b1aa7fc1dc7ded93812372ef79a839f5e23558136a6afbfde1/pydantic_core-2.46.3-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:e480080975c1ef7f780b8f99ed72337e7cc5efea2e518a20a692e8e7b278eb8b", size = 2322885, upload-time = "2026-04-20T14:41:05.253Z" }, + { url = "https://files.pythonhosted.org/packages/c8/c1/1c0acdb3aa0856ddc4ecc55214578f896f2de16f400cf51627eb3c26c1c4/pydantic_core-2.46.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:de3a5c376f8cd94da9a1b8fd3dd1c16c7a7b216ed31dc8ce9fd7a22bf13b836e", size = 2360328, upload-time = "2026-04-20T14:41:43.991Z" }, + { url = "https://files.pythonhosted.org/packages/f0/d0/ef39cd0f4a926814f360e71c1adeab48ad214d9727e4deb48eedfb5bce1a/pydantic_core-2.46.3-cp311-cp311-win32.whl", hash = "sha256:fc331a5314ffddd5385b9ee9d0d2fee0b13c27e0e02dad71b1ae5d6561f51eeb", size = 1979464, upload-time = "2026-04-20T14:43:12.215Z" }, + { url = "https://files.pythonhosted.org/packages/18/9c/f41951b0d858e343f1cf09398b2a7b3014013799744f2c4a8ad6a3eec4f2/pydantic_core-2.46.3-cp311-cp311-win_amd64.whl", hash = "sha256:b5b9c6cf08a8a5e502698f5e153056d12c34b8fb30317e0c5fd06f45162a6346", size = 2070837, upload-time = "2026-04-20T14:41:47.707Z" }, + { url = "https://files.pythonhosted.org/packages/9f/1e/264a17cd582f6ed50950d4d03dd5fefd84e570e238afe1cb3e25cf238769/pydantic_core-2.46.3-cp311-cp311-win_arm64.whl", hash = "sha256:5dfd51cf457482f04ec49491811a2b8fd5b843b64b11eecd2d7a1ee596ea78a6", size = 2053647, upload-time = "2026-04-20T14:42:27.535Z" }, + { url = "https://files.pythonhosted.org/packages/4b/cb/5b47425556ecc1f3fe18ed2a0083188aa46e1dd812b06e406475b3a5d536/pydantic_core-2.46.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:b11b59b3eee90a80a36701ddb4576d9ae31f93f05cb9e277ceaa09e6bf074a67", size = 2101946, upload-time = "2026-04-20T14:40:52.581Z" }, + { url = "https://files.pythonhosted.org/packages/a1/4f/2fb62c2267cae99b815bbf4a7b9283812c88ca3153ef29f7707200f1d4e5/pydantic_core-2.46.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:af8653713055ea18a3abc1537fe2ebc42f5b0bbb768d1eb79fd74eb47c0ac089", size = 1951612, upload-time = "2026-04-20T14:42:42.996Z" }, + { url = "https://files.pythonhosted.org/packages/50/6e/b7348fd30d6556d132cddd5bd79f37f96f2601fe0608afac4f5fb01ec0b3/pydantic_core-2.46.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:75a519dab6d63c514f3a81053e5266c549679e4aa88f6ec57f2b7b854aceb1b0", size = 1977027, upload-time = "2026-04-20T14:42:02.001Z" }, + { url = "https://files.pythonhosted.org/packages/82/11/31d60ee2b45540d3fb0b29302a393dbc01cd771c473f5b5147bcd353e593/pydantic_core-2.46.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a6cd87cb1575b1ad05ba98894c5b5c96411ef678fa2f6ed2576607095b8d9789", size = 2063008, upload-time = "2026-04-20T14:44:17.952Z" }, + { url = "https://files.pythonhosted.org/packages/8a/db/3a9d1957181b59258f44a2300ab0f0be9d1e12d662a4f57bb31250455c52/pydantic_core-2.46.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f80a55484b8d843c8ada81ebf70a682f3f00a3d40e378c06cf17ecb44d280d7d", size = 2233082, upload-time = "2026-04-20T14:40:57.934Z" }, + { url = "https://files.pythonhosted.org/packages/9c/e1/3277c38792aeb5cfb18c2f0c5785a221d9ff4e149abbe1184d53d5f72273/pydantic_core-2.46.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3861f1731b90c50a3266316b9044f5c9b405eecb8e299b0a7120596334e4fe9c", size = 2304615, upload-time = "2026-04-20T14:42:12.584Z" }, + { url = "https://files.pythonhosted.org/packages/5e/d5/e3d9717c9eba10855325650afd2a9cba8e607321697f18953af9d562da2f/pydantic_core-2.46.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb528e295ed31570ac3dcc9bfdd6e0150bc11ce6168ac87a8082055cf1a67395", size = 2094380, upload-time = "2026-04-20T14:43:05.522Z" }, + { url = "https://files.pythonhosted.org/packages/a1/20/abac35dedcbfd66c6f0b03e4e3564511771d6c9b7ede10a362d03e110d9b/pydantic_core-2.46.3-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:367508faa4973b992b271ba1494acaab36eb7e8739d1e47be5035fb1ea225396", size = 2135429, upload-time = "2026-04-20T14:41:55.549Z" }, + { url = "https://files.pythonhosted.org/packages/6c/a5/41bfd1df69afad71b5cf0535055bccc73022715ad362edbc124bc1e021d7/pydantic_core-2.46.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ad3c826fe523e4becf4fe39baa44286cff85ef137c729a2c5e269afbfd0905d", size = 2174582, upload-time = "2026-04-20T14:41:45.96Z" }, + { url = "https://files.pythonhosted.org/packages/79/65/38d86ea056b29b2b10734eb23329b7a7672ca604df4f2b6e9c02d4ee22fe/pydantic_core-2.46.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ec638c5d194ef8af27db69f16c954a09797c0dc25015ad6123eb2c73a4d271ca", size = 2187533, upload-time = "2026-04-20T14:40:55.367Z" }, + { url = "https://files.pythonhosted.org/packages/b6/55/a1129141678a2026badc539ad1dee0a71d06f54c2f06a4bd68c030ac781b/pydantic_core-2.46.3-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:28ed528c45446062ee66edb1d33df5d88828ae167de76e773a3c7f64bd14e976", size = 2332985, upload-time = "2026-04-20T14:44:13.05Z" }, + { url = "https://files.pythonhosted.org/packages/d7/60/cb26f4077719f709e54819f4e8e1d43f4091f94e285eb6bd21e1190a7b7c/pydantic_core-2.46.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aed19d0c783886d5bd86d80ae5030006b45e28464218747dcf83dabfdd092c7b", size = 2373670, upload-time = "2026-04-20T14:41:53.421Z" }, + { url = "https://files.pythonhosted.org/packages/6b/7e/c3f21882bdf1d8d086876f81b5e296206c69c6082551d776895de7801fa0/pydantic_core-2.46.3-cp312-cp312-win32.whl", hash = "sha256:06d5d8820cbbdb4147578c1fe7ffcd5b83f34508cb9f9ab76e807be7db6ff0a4", size = 1966722, upload-time = "2026-04-20T14:44:30.588Z" }, + { url = "https://files.pythonhosted.org/packages/57/be/6b5e757b859013ebfbd7adba02f23b428f37c86dcbf78b5bb0b4ffd36e99/pydantic_core-2.46.3-cp312-cp312-win_amd64.whl", hash = "sha256:c3212fda0ee959c1dd04c60b601ec31097aaa893573a3a1abd0a47bcac2968c1", size = 2072970, upload-time = "2026-04-20T14:42:54.248Z" }, + { url = "https://files.pythonhosted.org/packages/bf/f8/a989b21cc75e9a32d24192ef700eea606521221a89faa40c919ce884f2b1/pydantic_core-2.46.3-cp312-cp312-win_arm64.whl", hash = "sha256:f1f8338dd7a7f31761f1f1a3c47503a9a3b34eea3c8b01fa6ee96408affb5e72", size = 2035963, upload-time = "2026-04-20T14:44:20.4Z" }, + { url = "https://files.pythonhosted.org/packages/9b/3c/9b5e8eb9821936d065439c3b0fb1490ffa64163bfe7e1595985a47896073/pydantic_core-2.46.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:12bc98de041458b80c86c56b24df1d23832f3e166cbaff011f25d187f5c62c37", size = 2102109, upload-time = "2026-04-20T14:41:24.219Z" }, + { url = "https://files.pythonhosted.org/packages/91/97/1c41d1f5a19f241d8069f1e249853bcce378cdb76eec8ab636d7bc426280/pydantic_core-2.46.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:85348b8f89d2c3508b65b16c3c33a4da22b8215138d8b996912bb1532868885f", size = 1951820, upload-time = "2026-04-20T14:42:14.236Z" }, + { url = "https://files.pythonhosted.org/packages/30/b4/d03a7ae14571bc2b6b3c7b122441154720619afe9a336fa3a95434df5e2f/pydantic_core-2.46.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1105677a6df914b1fb71a81b96c8cce7726857e1717d86001f29be06a25ee6f8", size = 1977785, upload-time = "2026-04-20T14:42:31.648Z" }, + { url = "https://files.pythonhosted.org/packages/ae/0c/4086f808834b59e3c8f1aa26df8f4b6d998cdcf354a143d18ef41529d1fe/pydantic_core-2.46.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:87082cd65669a33adeba5470769e9704c7cf026cc30afb9cc77fd865578ebaad", size = 2062761, upload-time = "2026-04-20T14:40:37.093Z" }, + { url = "https://files.pythonhosted.org/packages/fa/71/a649be5a5064c2df0db06e0a512c2281134ed2fcc981f52a657936a7527c/pydantic_core-2.46.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:60e5f66e12c4f5212d08522963380eaaeac5ebd795826cfd19b2dfb0c7a52b9c", size = 2232989, upload-time = "2026-04-20T14:42:59.254Z" }, + { url = "https://files.pythonhosted.org/packages/a2/84/7756e75763e810b3a710f4724441d1ecc5883b94aacb07ca71c5fb5cfb69/pydantic_core-2.46.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b6cdf19bf84128d5e7c37e8a73a0c5c10d51103a650ac585d42dd6ae233f2b7f", size = 2303975, upload-time = "2026-04-20T14:41:32.287Z" }, + { url = "https://files.pythonhosted.org/packages/6c/35/68a762e0c1e31f35fa0dac733cbd9f5b118042853698de9509c8e5bf128b/pydantic_core-2.46.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:031bb17f4885a43773c8c763089499f242aee2ea85cf17154168775dccdecf35", size = 2095325, upload-time = "2026-04-20T14:42:47.685Z" }, + { url = "https://files.pythonhosted.org/packages/77/bf/1bf8c9a8e91836c926eae5e3e51dce009bf495a60ca56060689d3df3f340/pydantic_core-2.46.3-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:bcf2a8b2982a6673693eae7348ef3d8cf3979c1d63b54fca7c397a635cc68687", size = 2133368, upload-time = "2026-04-20T14:41:22.766Z" }, + { url = "https://files.pythonhosted.org/packages/e5/50/87d818d6bab915984995157ceb2380f5aac4e563dddbed6b56f0ed057aba/pydantic_core-2.46.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28e8cf2f52d72ced402a137145923a762cbb5081e48b34312f7a0c8f55928ec3", size = 2173908, upload-time = "2026-04-20T14:42:52.044Z" }, + { url = "https://files.pythonhosted.org/packages/91/88/a311fb306d0bd6185db41fa14ae888fb81d0baf648a761ae760d30819d33/pydantic_core-2.46.3-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:17eaface65d9fc5abb940003020309c1bf7a211f5f608d7870297c367e6f9022", size = 2186422, upload-time = "2026-04-20T14:43:29.55Z" }, + { url = "https://files.pythonhosted.org/packages/8f/79/28fd0d81508525ab2054fef7c77a638c8b5b0afcbbaeee493cf7c3fef7e1/pydantic_core-2.46.3-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:93fd339f23408a07e98950a89644f92c54d8729719a40b30c0a30bb9ebc55d23", size = 2332709, upload-time = "2026-04-20T14:42:16.134Z" }, + { url = "https://files.pythonhosted.org/packages/b3/21/795bf5fe5c0f379308b8ef19c50dedab2e7711dbc8d0c2acf08f1c7daa05/pydantic_core-2.46.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:23cbdb3aaa74dfe0837975dbf69b469753bbde8eacace524519ffdb6b6e89eb7", size = 2372428, upload-time = "2026-04-20T14:41:10.974Z" }, + { url = "https://files.pythonhosted.org/packages/45/b3/ed14c659cbe7605e3ef063077680a64680aec81eb1a04763a05190d49b7f/pydantic_core-2.46.3-cp313-cp313-win32.whl", hash = "sha256:610eda2e3838f401105e6326ca304f5da1e15393ae25dacae5c5c63f2c275b13", size = 1965601, upload-time = "2026-04-20T14:41:42.128Z" }, + { url = "https://files.pythonhosted.org/packages/ef/bb/adb70d9a762ddd002d723fbf1bd492244d37da41e3af7b74ad212609027e/pydantic_core-2.46.3-cp313-cp313-win_amd64.whl", hash = "sha256:68cc7866ed863db34351294187f9b729964c371ba33e31c26f478471c52e1ed0", size = 2071517, upload-time = "2026-04-20T14:43:36.096Z" }, + { url = "https://files.pythonhosted.org/packages/52/eb/66faefabebfe68bd7788339c9c9127231e680b11906368c67ce112fdb47f/pydantic_core-2.46.3-cp313-cp313-win_arm64.whl", hash = "sha256:f64b5537ac62b231572879cd08ec05600308636a5d63bcbdb15063a466977bec", size = 2035802, upload-time = "2026-04-20T14:43:38.507Z" }, + { url = "https://files.pythonhosted.org/packages/7f/db/a7bcb4940183fda36022cd18ba8dd12f2dff40740ec7b58ce7457befa416/pydantic_core-2.46.3-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:afa3aa644f74e290cdede48a7b0bee37d1c35e71b05105f6b340d484af536d9b", size = 2097614, upload-time = "2026-04-20T14:44:38.374Z" }, + { url = "https://files.pythonhosted.org/packages/24/35/e4066358a22e3e99519db370494c7528f5a2aa1367370e80e27e20283543/pydantic_core-2.46.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ced3310e51aa425f7f77da8bbbb5212616655bedbe82c70944320bc1dbe5e018", size = 1951896, upload-time = "2026-04-20T14:40:53.996Z" }, + { url = "https://files.pythonhosted.org/packages/87/92/37cf4049d1636996e4b888c05a501f40a43ff218983a551d57f9d5e14f0d/pydantic_core-2.46.3-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e29908922ce9da1a30b4da490bd1d3d82c01dcfdf864d2a74aacee674d0bfa34", size = 1979314, upload-time = "2026-04-20T14:41:49.446Z" }, + { url = "https://files.pythonhosted.org/packages/d8/36/9ff4d676dfbdfb2d591cf43f3d90ded01e15b1404fd101180ed2d62a2fd3/pydantic_core-2.46.3-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0c9ff69140423eea8ed2d5477df3ba037f671f5e897d206d921bc9fdc39613e7", size = 2056133, upload-time = "2026-04-20T14:42:23.574Z" }, + { url = "https://files.pythonhosted.org/packages/bc/f0/405b442a4d7ba855b06eec8b2bf9c617d43b8432d099dfdc7bf999293495/pydantic_core-2.46.3-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b675ab0a0d5b1c8fdb81195dc5bcefea3f3c240871cdd7ff9a2de8aa50772eb2", size = 2228726, upload-time = "2026-04-20T14:44:22.816Z" }, + { url = "https://files.pythonhosted.org/packages/e7/f8/65cd92dd5a0bd89ba277a98ecbfaf6fc36bbd3300973c7a4b826d6ab1391/pydantic_core-2.46.3-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0087084960f209a9a4af50ecd1fb063d9ad3658c07bb81a7a53f452dacbfb2ba", size = 2301214, upload-time = "2026-04-20T14:44:48.792Z" }, + { url = "https://files.pythonhosted.org/packages/fd/86/ef96a4c6e79e7a2d0410826a68fbc0eccc0fd44aa733be199d5fcac3bb87/pydantic_core-2.46.3-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed42e6cc8e1b0e2b9b96e2276bad70ae625d10d6d524aed0c93de974ae029f9f", size = 2099927, upload-time = "2026-04-20T14:41:40.196Z" }, + { url = "https://files.pythonhosted.org/packages/6d/53/269caf30e0096e0a8a8f929d1982a27b3879872cca2d917d17c2f9fdf4fe/pydantic_core-2.46.3-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:f1771ce258afb3e4201e67d154edbbae712a76a6081079fe247c2f53c6322c22", size = 2128789, upload-time = "2026-04-20T14:41:15.868Z" }, + { url = "https://files.pythonhosted.org/packages/00/b0/1a6d9b6a587e118482910c244a1c5acf4d192604174132efd12bf0ac486f/pydantic_core-2.46.3-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a7610b6a5242a6c736d8ad47fd5fff87fcfe8f833b281b1c409c3d6835d9227f", size = 2173815, upload-time = "2026-04-20T14:44:25.152Z" }, + { url = "https://files.pythonhosted.org/packages/87/56/e7e00d4041a7e62b5a40815590114db3b535bf3ca0bf4dca9f16cef25246/pydantic_core-2.46.3-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:ff5e7783bcc5476e1db448bf268f11cb257b1c276d3e89f00b5727be86dd0127", size = 2181608, upload-time = "2026-04-20T14:41:28.933Z" }, + { url = "https://files.pythonhosted.org/packages/e8/22/4bd23c3d41f7c185d60808a1de83c76cf5aeabf792f6c636a55c3b1ec7f9/pydantic_core-2.46.3-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:9d2e32edcc143bc01e95300671915d9ca052d4f745aa0a49c48d4803f8a85f2c", size = 2326968, upload-time = "2026-04-20T14:42:03.962Z" }, + { url = "https://files.pythonhosted.org/packages/24/ac/66cd45129e3915e5ade3b292cb3bc7fd537f58f8f8dbdaba6170f7cabb74/pydantic_core-2.46.3-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:6e42d83d1c6b87fa56b521479cff237e626a292f3b31b6345c15a99121b454c1", size = 2369842, upload-time = "2026-04-20T14:41:35.52Z" }, + { url = "https://files.pythonhosted.org/packages/a2/51/dd4248abb84113615473aa20d5545b7c4cd73c8644003b5259686f93996c/pydantic_core-2.46.3-cp314-cp314-win32.whl", hash = "sha256:07bc6d2a28c3adb4f7c6ae46aa4f2d2929af127f587ed44057af50bf1ce0f505", size = 1959661, upload-time = "2026-04-20T14:41:00.042Z" }, + { url = "https://files.pythonhosted.org/packages/20/eb/59980e5f1ae54a3b86372bd9f0fa373ea2d402e8cdcd3459334430f91e91/pydantic_core-2.46.3-cp314-cp314-win_amd64.whl", hash = "sha256:8940562319bc621da30714617e6a7eaa6b98c84e8c685bcdc02d7ed5e7c7c44e", size = 2071686, upload-time = "2026-04-20T14:43:16.471Z" }, + { url = "https://files.pythonhosted.org/packages/8c/db/1cf77e5247047dfee34bc01fa9bca134854f528c8eb053e144298893d370/pydantic_core-2.46.3-cp314-cp314-win_arm64.whl", hash = "sha256:5dcbbcf4d22210ced8f837c96db941bdb078f419543472aca5d9a0bb7cddc7df", size = 2026907, upload-time = "2026-04-20T14:43:31.732Z" }, + { url = "https://files.pythonhosted.org/packages/57/c0/b3df9f6a543276eadba0a48487b082ca1f201745329d97dbfa287034a230/pydantic_core-2.46.3-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:d0fe3dce1e836e418f912c1ad91c73357d03e556a4d286f441bf34fed2dbeecf", size = 2095047, upload-time = "2026-04-20T14:42:37.982Z" }, + { url = "https://files.pythonhosted.org/packages/66/57/886a938073b97556c168fd99e1a7305bb363cd30a6d2c76086bf0587b32a/pydantic_core-2.46.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:9ce92e58abc722dac1bf835a6798a60b294e48eb0e625ec9fd994b932ac5feee", size = 1934329, upload-time = "2026-04-20T14:43:49.655Z" }, + { url = "https://files.pythonhosted.org/packages/0b/7c/b42eaa5c34b13b07ecb51da21761297a9b8eb43044c864a035999998f328/pydantic_core-2.46.3-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a03e6467f0f5ab796a486146d1b887b2dc5e5f9b3288898c1b1c3ad974e53e4a", size = 1974847, upload-time = "2026-04-20T14:42:10.737Z" }, + { url = "https://files.pythonhosted.org/packages/e6/9b/92b42db6543e7de4f99ae977101a2967b63122d4b6cf7773812da2d7d5b5/pydantic_core-2.46.3-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2798b6ba041b9d70acfb9071a2ea13c8456dd1e6a5555798e41ba7b0790e329c", size = 2041742, upload-time = "2026-04-20T14:40:44.262Z" }, + { url = "https://files.pythonhosted.org/packages/0f/19/46fbe1efabb5aa2834b43b9454e70f9a83ad9c338c1291e48bdc4fecf167/pydantic_core-2.46.3-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9be3e221bdc6d69abf294dcf7aff6af19c31a5cdcc8f0aa3b14be29df4bd03b1", size = 2236235, upload-time = "2026-04-20T14:41:27.307Z" }, + { url = "https://files.pythonhosted.org/packages/77/da/b3f95bc009ad60ec53120f5d16c6faa8cabdbe8a20d83849a1f2b8728148/pydantic_core-2.46.3-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f13936129ce841f2a5ddf6f126fea3c43cd128807b5a59588c37cf10178c2e64", size = 2282633, upload-time = "2026-04-20T14:44:33.271Z" }, + { url = "https://files.pythonhosted.org/packages/cc/6e/401336117722e28f32fb8220df676769d28ebdf08f2f4469646d404c43a3/pydantic_core-2.46.3-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28b5f2ef03416facccb1c6ef744c69793175fd27e44ef15669201601cf423acb", size = 2109679, upload-time = "2026-04-20T14:44:41.065Z" }, + { url = "https://files.pythonhosted.org/packages/fc/53/b289f9bc8756a32fe718c46f55afaeaf8d489ee18d1a1e7be1db73f42cc4/pydantic_core-2.46.3-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:830d1247d77ad23852314f069e9d7ddafeec5f684baf9d7e7065ed46a049c4e6", size = 2108342, upload-time = "2026-04-20T14:42:50.144Z" }, + { url = "https://files.pythonhosted.org/packages/10/5b/8292fc7c1f9111f1b2b7c1b0dcf1179edcd014fc3ea4517499f50b829d71/pydantic_core-2.46.3-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0793c90c1a3c74966e7975eaef3ed30ebdff3260a0f815a62a22adc17e4c01c", size = 2157208, upload-time = "2026-04-20T14:42:08.133Z" }, + { url = "https://files.pythonhosted.org/packages/2b/9e/f80044e9ec07580f057a89fc131f78dda7a58751ddf52bbe05eaf31db50f/pydantic_core-2.46.3-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:d2d0aead851b66f5245ec0c4fb2612ef457f8bbafefdf65a2bf9d6bac6140f47", size = 2167237, upload-time = "2026-04-20T14:42:25.412Z" }, + { url = "https://files.pythonhosted.org/packages/f8/84/6781a1b037f3b96be9227edbd1101f6d3946746056231bf4ac48cdff1a8d/pydantic_core-2.46.3-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:2f40e4246676beb31c5ce77c38a55ca4e465c6b38d11ea1bd935420568e0b1ab", size = 2312540, upload-time = "2026-04-20T14:40:40.313Z" }, + { url = "https://files.pythonhosted.org/packages/3e/db/19c0839feeb728e7df03255581f198dfdf1c2aeb1e174a8420b63c5252e5/pydantic_core-2.46.3-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:cf489cf8986c543939aeee17a09c04d6ffb43bfef8ca16fcbcc5cfdcbed24dba", size = 2369556, upload-time = "2026-04-20T14:41:09.427Z" }, + { url = "https://files.pythonhosted.org/packages/e0/15/3228774cb7cd45f5f721ddf1b2242747f4eb834d0c491f0c02d606f09fed/pydantic_core-2.46.3-cp314-cp314t-win32.whl", hash = "sha256:ffe0883b56cfc05798bf994164d2b2ff03efe2d22022a2bb080f3b626176dd56", size = 1949756, upload-time = "2026-04-20T14:41:25.717Z" }, + { url = "https://files.pythonhosted.org/packages/b8/2a/c79cf53fd91e5a87e30d481809f52f9a60dd221e39de66455cf04deaad37/pydantic_core-2.46.3-cp314-cp314t-win_amd64.whl", hash = "sha256:706d9d0ce9cf4593d07270d8e9f53b161f90c57d315aeec4fb4fd7a8b10240d8", size = 2051305, upload-time = "2026-04-20T14:43:18.627Z" }, + { url = "https://files.pythonhosted.org/packages/0b/db/d8182a7f1d9343a032265aae186eb063fe26ca4c40f256b21e8da4498e89/pydantic_core-2.46.3-cp314-cp314t-win_arm64.whl", hash = "sha256:77706aeb41df6a76568434701e0917da10692da28cb69d5fb6919ce5fdb07374", size = 2026310, upload-time = "2026-04-20T14:41:01.778Z" }, + { url = "https://files.pythonhosted.org/packages/31/75/c1ee7cb5b2277fe1f95837a58fb692eeda7162494fc1ddccb5f23be1d7f6/pydantic_core-2.46.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:fa3eb7c2995aa443687a825bc30395c8521b7c6ec201966e55debfd1128bcceb", size = 2112012, upload-time = "2026-04-20T14:44:35.697Z" }, + { url = "https://files.pythonhosted.org/packages/6b/da/fb883281703dc5f4d68cdc648c503c46c8af5726f428013178d657c75181/pydantic_core-2.46.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3d08782c4045f90724b44c95d35ebec0d67edb8a957a2ac81d5a8e4b8a200495", size = 1953006, upload-time = "2026-04-20T14:43:33.878Z" }, + { url = "https://files.pythonhosted.org/packages/92/47/5d7d7d04204920771086d768ca51306e34b63a31ad80a5f82c9d38dea568/pydantic_core-2.46.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:831eb19aa789a97356979e94c981e5667759301fb708d1c0d5adf1bc0098b873", size = 1980050, upload-time = "2026-04-20T14:41:03.154Z" }, + { url = "https://files.pythonhosted.org/packages/e0/e9/1c52019dd95babcff1bffe40022e8541c0447b8e4a44596a979c7309fa0c/pydantic_core-2.46.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4335e87c7afa436a0dfa899e138d57a72f8aad542e2cf19c36fb428461caabd0", size = 2057165, upload-time = "2026-04-20T14:43:44.507Z" }, + { url = "https://files.pythonhosted.org/packages/6f/0e/e0aac1f35baf80ff8f35d4fa58d85dce248324a764d950460cf5c0569758/pydantic_core-2.46.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99421e7684a60f7f3550a1d159ade5fdff1954baedb6bdd407cba6a307c9f27d", size = 2225133, upload-time = "2026-04-20T14:41:07.334Z" }, + { url = "https://files.pythonhosted.org/packages/d5/df/8eb296b9661574ef26e990856991615c1e1fb1744a10b896bff684a3c99a/pydantic_core-2.46.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd81f6907932ebac3abbe41378dac64b2380db1287e2aa64d8d88f78d170f51a", size = 2282409, upload-time = "2026-04-20T14:43:07.567Z" }, + { url = "https://files.pythonhosted.org/packages/d2/07/888c53b769be71072a1dbd741ec25160579d789ef276fd5bd2045a07b09a/pydantic_core-2.46.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f247596366f4221af52beddd65af1218797771d6989bc891a0b86ccaa019168", size = 2095775, upload-time = "2026-04-20T14:42:21.586Z" }, + { url = "https://files.pythonhosted.org/packages/8a/19/6c32bdb93362b899bf92ac42c824898ab93dd8a23f339cbf5c5098ef61a6/pydantic_core-2.46.3-cp39-cp39-manylinux_2_31_riscv64.whl", hash = "sha256:6dff8cc884679df229ebc6d8eb2321ea6f8e091bc7d4886d4dc2e0e71452843c", size = 2118999, upload-time = "2026-04-20T14:44:43.791Z" }, + { url = "https://files.pythonhosted.org/packages/6b/c6/31d926d003f59a032ff61b62990e378f0fb985aa9d77fd448a6140f7eb5f/pydantic_core-2.46.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:68ef2f623dda6d5a9067ac014e406c020c780b2a358930a7e5c1b73702900720", size = 2162368, upload-time = "2026-04-20T14:41:12.529Z" }, + { url = "https://files.pythonhosted.org/packages/4f/a1/48d669051947845ff54f5b7cb6254ccafb23aa284184de6f273145d0e45b/pydantic_core-2.46.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d56bdb4af1767cc15b0386b3c581fdfe659bb9ee4a4f776e92c1cd9d074000d6", size = 2184786, upload-time = "2026-04-20T14:42:40.235Z" }, + { url = "https://files.pythonhosted.org/packages/08/ff/a722cade3d4bd8ed6433a8e84eddf2f993b5fb4a47cade269289cfb4cc0c/pydantic_core-2.46.3-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:91249bcb7c165c2fb2a2f852dbc5c91636e2e218e75d96dfdd517e4078e173dd", size = 2325626, upload-time = "2026-04-20T14:41:37.73Z" }, + { url = "https://files.pythonhosted.org/packages/ad/8a/238e33805d6f3691bcce8739db7d0376a2388e1b3f2c8db2128f6683fc78/pydantic_core-2.46.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4b068543bdb707f5d935dab765d99227aa2545ef2820935f2e5dd801795c7dbd", size = 2363286, upload-time = "2026-04-20T14:42:29.385Z" }, + { url = "https://files.pythonhosted.org/packages/ad/2e/ab044f4431798a565242d5e8e48d080faa931f45e3d30df62e4f501d9bb0/pydantic_core-2.46.3-cp39-cp39-win32.whl", hash = "sha256:dcda6583921c05a40533f982321532f2d8db29326c7b95c4026941fa5074bd79", size = 1981660, upload-time = "2026-04-20T14:43:54.525Z" }, + { url = "https://files.pythonhosted.org/packages/d0/2c/13855786276f51fe86915c0533f4fc14e1d5421726ba8ad57caa09eb18ec/pydantic_core-2.46.3-cp39-cp39-win_amd64.whl", hash = "sha256:a35cc284c8dd7edae8a31533713b4d2467dfe7c4f1b5587dd4031f28f90d1d13", size = 2078793, upload-time = "2026-04-20T14:42:17.87Z" }, + { url = "https://files.pythonhosted.org/packages/66/7f/03dbad45cd3aa9083fbc93c210ae8b005af67e4136a14186950a747c6874/pydantic_core-2.46.3-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:9715525891ed524a0a1eb6d053c74d4d4ad5017677fb00af0b7c2644a31bae46", size = 2105683, upload-time = "2026-04-20T14:42:19.779Z" }, + { url = "https://files.pythonhosted.org/packages/26/22/4dc186ac8ea6b257e9855031f51b62a9637beac4d68ac06bee02f046f836/pydantic_core-2.46.3-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:9d2f400712a99a013aff420ef1eb9be077f8189a36c1e3ef87660b4e1088a874", size = 1940052, upload-time = "2026-04-20T14:43:59.274Z" }, + { url = "https://files.pythonhosted.org/packages/0d/ca/d376391a5aff1f2e8188960d7873543608130a870961c2b6b5236627c116/pydantic_core-2.46.3-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd2aab0e2e9dc2daf36bd2686c982535d5e7b1d930a1344a7bb6e82baab42a76", size = 1988172, upload-time = "2026-04-20T14:41:17.469Z" }, + { url = "https://files.pythonhosted.org/packages/0e/6b/523b9f85c23788755d6ab949329de692a2e3a584bc6beb67fef5e035aa9d/pydantic_core-2.46.3-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e9d76736da5f362fabfeea6a69b13b7f2be405c6d6966f06b2f6bfff7e64531", size = 2128596, upload-time = "2026-04-20T14:40:41.707Z" }, + { url = "https://files.pythonhosted.org/packages/34/42/f426db557e8ab2791bc7562052299944a118655496fbff99914e564c0a94/pydantic_core-2.46.3-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:b12dd51f1187c2eb489af8e20f880362db98e954b54ab792fa5d92e8bcc6b803", size = 2091877, upload-time = "2026-04-20T14:43:27.091Z" }, + { url = "https://files.pythonhosted.org/packages/5c/4f/86a832a9d14df58e663bfdf4627dc00d3317c2bd583c4fb23390b0f04b8e/pydantic_core-2.46.3-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:f00a0961b125f1a47af7bcc17f00782e12f4cd056f83416006b30111d941dfa3", size = 1932428, upload-time = "2026-04-20T14:40:45.781Z" }, + { url = "https://files.pythonhosted.org/packages/11/1a/fe857968954d93fb78e0d4b6df5c988c74c4aaa67181c60be7cfe327c0ca/pydantic_core-2.46.3-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57697d7c056aca4bbb680200f96563e841a6386ac1129370a0102592f4dddff5", size = 1997550, upload-time = "2026-04-20T14:44:02.425Z" }, + { url = "https://files.pythonhosted.org/packages/17/eb/9d89ad2d9b0ba8cd65393d434471621b98912abb10fbe1df08e480ba57b5/pydantic_core-2.46.3-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd35aa21299def8db7ef4fe5c4ff862941a9a158ca7b63d61e66fe67d30416b4", size = 2137657, upload-time = "2026-04-20T14:42:45.149Z" }, + { url = "https://files.pythonhosted.org/packages/1f/da/99d40830684f81dec901cac521b5b91c095394cc1084b9433393cde1c2df/pydantic_core-2.46.3-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:13afdd885f3d71280cf286b13b310ee0f7ccfefd1dbbb661514a474b726e2f25", size = 2107973, upload-time = "2026-04-20T14:42:06.175Z" }, + { url = "https://files.pythonhosted.org/packages/99/a5/87024121818d75bbb2a98ddbaf638e40e7a18b5e0f5492c9ca4b1b316107/pydantic_core-2.46.3-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:f91c0aff3e3ee0928edd1232c57f643a7a003e6edf1860bc3afcdc749cb513f3", size = 1947191, upload-time = "2026-04-20T14:43:14.319Z" }, + { url = "https://files.pythonhosted.org/packages/60/62/0c1acfe10945b83a6a59d19fbaa92f48825381509e5701b855c08f13db76/pydantic_core-2.46.3-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6529d1d128321a58d30afcc97b49e98836542f68dd41b33c2e972bb9e5290536", size = 2123791, upload-time = "2026-04-20T14:43:22.766Z" }, + { url = "https://files.pythonhosted.org/packages/75/3e/3b2393b4c8f44285561dc30b00cf307a56a2eff7c483a824db3b8221ca51/pydantic_core-2.46.3-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:975c267cff4f7e7272eacbe50f6cc03ca9a3da4c4fbd66fffd89c94c1e311aa1", size = 2153197, upload-time = "2026-04-20T14:44:27.932Z" }, + { url = "https://files.pythonhosted.org/packages/ba/75/5af02fb35505051eee727c061f2881c555ab4f8ddb2d42da715a42c9731b/pydantic_core-2.46.3-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2b8e4f2bbdf71415c544b4b1138b8060db7b6611bc927e8064c769f64bed651c", size = 2181073, upload-time = "2026-04-20T14:43:20.729Z" }, + { url = "https://files.pythonhosted.org/packages/10/92/7e0e1bd9ca3c68305db037560ca2876f89b2647deb2f8b6319005de37505/pydantic_core-2.46.3-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:e61ea8e9fff9606d09178f577ff8ccdd7206ff73d6552bcec18e1033c4254b85", size = 2315886, upload-time = "2026-04-20T14:44:04.826Z" }, + { url = "https://files.pythonhosted.org/packages/b8/d8/101655f27eaf3e44558ead736b2795d12500598beed4683f279396fa186e/pydantic_core-2.46.3-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:b504bda01bafc69b6d3c7a0c7f039dcf60f47fab70e06fe23f57b5c75bdc82b8", size = 2360528, upload-time = "2026-04-20T14:40:47.431Z" }, + { url = "https://files.pythonhosted.org/packages/07/0f/1c34a74c8d07136f0d729ffe5e1fdab04fbdaa7684f61a92f92511a84a15/pydantic_core-2.46.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:b00b76f7142fc60c762ce579bd29c8fa44aaa56592dd3c54fab3928d0d4ca6ff", size = 2184144, upload-time = "2026-04-20T14:42:57Z" }, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] + +[[package]] +name = "typing-inspection" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, +] + +[[package]] +name = "yarl" +version = "1.22.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.10'", +] +dependencies = [ + { name = "idna", marker = "python_full_version < '3.10'" }, + { name = "multidict", marker = "python_full_version < '3.10'" }, + { name = "propcache", marker = "python_full_version < '3.10'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/57/63/0c6ebca57330cd313f6102b16dd57ffaf3ec4c83403dcb45dbd15c6f3ea1/yarl-1.22.0.tar.gz", hash = "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71", size = 187169, upload-time = "2025-10-06T14:12:55.963Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/43/a2204825342f37c337f5edb6637040fa14e365b2fcc2346960201d457579/yarl-1.22.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c7bd6683587567e5a49ee6e336e0612bec8329be1b7d4c8af5687dcdeb67ee1e", size = 140517, upload-time = "2025-10-06T14:08:42.494Z" }, + { url = "https://files.pythonhosted.org/packages/44/6f/674f3e6f02266428c56f704cd2501c22f78e8b2eeb23f153117cc86fb28a/yarl-1.22.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5cdac20da754f3a723cceea5b3448e1a2074866406adeb4ef35b469d089adb8f", size = 93495, upload-time = "2025-10-06T14:08:46.2Z" }, + { url = "https://files.pythonhosted.org/packages/b8/12/5b274d8a0f30c07b91b2f02cba69152600b47830fcfb465c108880fcee9c/yarl-1.22.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07a524d84df0c10f41e3ee918846e1974aba4ec017f990dc735aad487a0bdfdf", size = 94400, upload-time = "2025-10-06T14:08:47.855Z" }, + { url = "https://files.pythonhosted.org/packages/e2/7f/df1b6949b1fa1aa9ff6de6e2631876ad4b73c4437822026e85d8acb56bb1/yarl-1.22.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1b329cb8146d7b736677a2440e422eadd775d1806a81db2d4cded80a48efc1a", size = 347545, upload-time = "2025-10-06T14:08:49.683Z" }, + { url = "https://files.pythonhosted.org/packages/84/09/f92ed93bd6cd77872ab6c3462df45ca45cd058d8f1d0c9b4f54c1704429f/yarl-1.22.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:75976c6945d85dbb9ee6308cd7ff7b1fb9409380c82d6119bd778d8fcfe2931c", size = 319598, upload-time = "2025-10-06T14:08:51.215Z" }, + { url = "https://files.pythonhosted.org/packages/c3/97/ac3f3feae7d522cf7ccec3d340bb0b2b61c56cb9767923df62a135092c6b/yarl-1.22.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:80ddf7a5f8c86cb3eb4bc9028b07bbbf1f08a96c5c0bc1244be5e8fefcb94147", size = 363893, upload-time = "2025-10-06T14:08:53.144Z" }, + { url = "https://files.pythonhosted.org/packages/06/49/f3219097403b9c84a4d079b1d7bda62dd9b86d0d6e4428c02d46ab2c77fc/yarl-1.22.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d332fc2e3c94dad927f2112395772a4e4fedbcf8f80efc21ed7cdfae4d574fdb", size = 371240, upload-time = "2025-10-06T14:08:55.036Z" }, + { url = "https://files.pythonhosted.org/packages/35/9f/06b765d45c0e44e8ecf0fe15c9eacbbde342bb5b7561c46944f107bfb6c3/yarl-1.22.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0cf71bf877efeac18b38d3930594c0948c82b64547c1cf420ba48722fe5509f6", size = 346965, upload-time = "2025-10-06T14:08:56.722Z" }, + { url = "https://files.pythonhosted.org/packages/c5/69/599e7cea8d0fcb1694323b0db0dda317fa3162f7b90166faddecf532166f/yarl-1.22.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:663e1cadaddae26be034a6ab6072449a8426ddb03d500f43daf952b74553bba0", size = 342026, upload-time = "2025-10-06T14:08:58.563Z" }, + { url = "https://files.pythonhosted.org/packages/95/6f/9dfd12c8bc90fea9eab39832ee32ea48f8e53d1256252a77b710c065c89f/yarl-1.22.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:6dcbb0829c671f305be48a7227918cfcd11276c2d637a8033a99a02b67bf9eda", size = 335637, upload-time = "2025-10-06T14:09:00.506Z" }, + { url = "https://files.pythonhosted.org/packages/57/2e/34c5b4eb9b07e16e873db5b182c71e5f06f9b5af388cdaa97736d79dd9a6/yarl-1.22.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f0d97c18dfd9a9af4490631905a3f131a8e4c9e80a39353919e2cfed8f00aedc", size = 359082, upload-time = "2025-10-06T14:09:01.936Z" }, + { url = "https://files.pythonhosted.org/packages/31/71/fa7e10fb772d273aa1f096ecb8ab8594117822f683bab7d2c5a89914c92a/yarl-1.22.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:437840083abe022c978470b942ff832c3940b2ad3734d424b7eaffcd07f76737", size = 357811, upload-time = "2025-10-06T14:09:03.445Z" }, + { url = "https://files.pythonhosted.org/packages/26/da/11374c04e8e1184a6a03cf9c8f5688d3e5cec83ed6f31ad3481b3207f709/yarl-1.22.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a899cbd98dce6f5d8de1aad31cb712ec0a530abc0a86bd6edaa47c1090138467", size = 351223, upload-time = "2025-10-06T14:09:05.401Z" }, + { url = "https://files.pythonhosted.org/packages/82/8f/e2d01f161b0c034a30410e375e191a5d27608c1f8693bab1a08b089ca096/yarl-1.22.0-cp310-cp310-win32.whl", hash = "sha256:595697f68bd1f0c1c159fcb97b661fc9c3f5db46498043555d04805430e79bea", size = 82118, upload-time = "2025-10-06T14:09:11.148Z" }, + { url = "https://files.pythonhosted.org/packages/62/46/94c76196642dbeae634c7a61ba3da88cd77bed875bf6e4a8bed037505aa6/yarl-1.22.0-cp310-cp310-win_amd64.whl", hash = "sha256:cb95a9b1adaa48e41815a55ae740cfda005758104049a640a398120bf02515ca", size = 86852, upload-time = "2025-10-06T14:09:12.958Z" }, + { url = "https://files.pythonhosted.org/packages/af/af/7df4f179d3b1a6dcb9a4bd2ffbc67642746fcafdb62580e66876ce83fff4/yarl-1.22.0-cp310-cp310-win_arm64.whl", hash = "sha256:b85b982afde6df99ecc996990d4ad7ccbdbb70e2a4ba4de0aecde5922ba98a0b", size = 82012, upload-time = "2025-10-06T14:09:14.664Z" }, + { url = "https://files.pythonhosted.org/packages/4d/27/5ab13fc84c76a0250afd3d26d5936349a35be56ce5785447d6c423b26d92/yarl-1.22.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ab72135b1f2db3fed3997d7e7dc1b80573c67138023852b6efb336a5eae6511", size = 141607, upload-time = "2025-10-06T14:09:16.298Z" }, + { url = "https://files.pythonhosted.org/packages/6a/a1/d065d51d02dc02ce81501d476b9ed2229d9a990818332242a882d5d60340/yarl-1.22.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:669930400e375570189492dc8d8341301578e8493aec04aebc20d4717f899dd6", size = 94027, upload-time = "2025-10-06T14:09:17.786Z" }, + { url = "https://files.pythonhosted.org/packages/c1/da/8da9f6a53f67b5106ffe902c6fa0164e10398d4e150d85838b82f424072a/yarl-1.22.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:792a2af6d58177ef7c19cbf0097aba92ca1b9cb3ffdd9c7470e156c8f9b5e028", size = 94963, upload-time = "2025-10-06T14:09:19.662Z" }, + { url = "https://files.pythonhosted.org/packages/68/fe/2c1f674960c376e29cb0bec1249b117d11738db92a6ccc4a530b972648db/yarl-1.22.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ea66b1c11c9150f1372f69afb6b8116f2dd7286f38e14ea71a44eee9ec51b9d", size = 368406, upload-time = "2025-10-06T14:09:21.402Z" }, + { url = "https://files.pythonhosted.org/packages/95/26/812a540e1c3c6418fec60e9bbd38e871eaba9545e94fa5eff8f4a8e28e1e/yarl-1.22.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3e2daa88dc91870215961e96a039ec73e4937da13cf77ce17f9cad0c18df3503", size = 336581, upload-time = "2025-10-06T14:09:22.98Z" }, + { url = "https://files.pythonhosted.org/packages/0b/f5/5777b19e26fdf98563985e481f8be3d8a39f8734147a6ebf459d0dab5a6b/yarl-1.22.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba440ae430c00eee41509353628600212112cd5018d5def7e9b05ea7ac34eb65", size = 388924, upload-time = "2025-10-06T14:09:24.655Z" }, + { url = "https://files.pythonhosted.org/packages/86/08/24bd2477bd59c0bbd994fe1d93b126e0472e4e3df5a96a277b0a55309e89/yarl-1.22.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e6438cc8f23a9c1478633d216b16104a586b9761db62bfacb6425bac0a36679e", size = 392890, upload-time = "2025-10-06T14:09:26.617Z" }, + { url = "https://files.pythonhosted.org/packages/46/00/71b90ed48e895667ecfb1eaab27c1523ee2fa217433ed77a73b13205ca4b/yarl-1.22.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c52a6e78aef5cf47a98ef8e934755abf53953379b7d53e68b15ff4420e6683d", size = 365819, upload-time = "2025-10-06T14:09:28.544Z" }, + { url = "https://files.pythonhosted.org/packages/30/2d/f715501cae832651d3282387c6a9236cd26bd00d0ff1e404b3dc52447884/yarl-1.22.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3b06bcadaac49c70f4c88af4ffcfbe3dc155aab3163e75777818092478bcbbe7", size = 363601, upload-time = "2025-10-06T14:09:30.568Z" }, + { url = "https://files.pythonhosted.org/packages/f8/f9/a678c992d78e394e7126ee0b0e4e71bd2775e4334d00a9278c06a6cce96a/yarl-1.22.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:6944b2dc72c4d7f7052683487e3677456050ff77fcf5e6204e98caf785ad1967", size = 358072, upload-time = "2025-10-06T14:09:32.528Z" }, + { url = "https://files.pythonhosted.org/packages/2c/d1/b49454411a60edb6fefdcad4f8e6dbba7d8019e3a508a1c5836cba6d0781/yarl-1.22.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d5372ca1df0f91a86b047d1277c2aaf1edb32d78bbcefffc81b40ffd18f027ed", size = 385311, upload-time = "2025-10-06T14:09:34.634Z" }, + { url = "https://files.pythonhosted.org/packages/87/e5/40d7a94debb8448c7771a916d1861d6609dddf7958dc381117e7ba36d9e8/yarl-1.22.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:51af598701f5299012b8416486b40fceef8c26fc87dc6d7d1f6fc30609ea0aa6", size = 381094, upload-time = "2025-10-06T14:09:36.268Z" }, + { url = "https://files.pythonhosted.org/packages/35/d8/611cc282502381ad855448643e1ad0538957fc82ae83dfe7762c14069e14/yarl-1.22.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b266bd01fedeffeeac01a79ae181719ff848a5a13ce10075adbefc8f1daee70e", size = 370944, upload-time = "2025-10-06T14:09:37.872Z" }, + { url = "https://files.pythonhosted.org/packages/2d/df/fadd00fb1c90e1a5a8bd731fa3d3de2e165e5a3666a095b04e31b04d9cb6/yarl-1.22.0-cp311-cp311-win32.whl", hash = "sha256:a9b1ba5610a4e20f655258d5a1fdc7ebe3d837bb0e45b581398b99eb98b1f5ca", size = 81804, upload-time = "2025-10-06T14:09:39.359Z" }, + { url = "https://files.pythonhosted.org/packages/b5/f7/149bb6f45f267cb5c074ac40c01c6b3ea6d8a620d34b337f6321928a1b4d/yarl-1.22.0-cp311-cp311-win_amd64.whl", hash = "sha256:078278b9b0b11568937d9509b589ee83ef98ed6d561dfe2020e24a9fd08eaa2b", size = 86858, upload-time = "2025-10-06T14:09:41.068Z" }, + { url = "https://files.pythonhosted.org/packages/2b/13/88b78b93ad3f2f0b78e13bfaaa24d11cbc746e93fe76d8c06bf139615646/yarl-1.22.0-cp311-cp311-win_arm64.whl", hash = "sha256:b6a6f620cfe13ccec221fa312139135166e47ae169f8253f72a0abc0dae94376", size = 81637, upload-time = "2025-10-06T14:09:42.712Z" }, + { url = "https://files.pythonhosted.org/packages/75/ff/46736024fee3429b80a165a732e38e5d5a238721e634ab41b040d49f8738/yarl-1.22.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e340382d1afa5d32b892b3ff062436d592ec3d692aeea3bef3a5cfe11bbf8c6f", size = 142000, upload-time = "2025-10-06T14:09:44.631Z" }, + { url = "https://files.pythonhosted.org/packages/5a/9a/b312ed670df903145598914770eb12de1bac44599549b3360acc96878df8/yarl-1.22.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f1e09112a2c31ffe8d80be1b0988fa6a18c5d5cad92a9ffbb1c04c91bfe52ad2", size = 94338, upload-time = "2025-10-06T14:09:46.372Z" }, + { url = "https://files.pythonhosted.org/packages/ba/f5/0601483296f09c3c65e303d60c070a5c19fcdbc72daa061e96170785bc7d/yarl-1.22.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:939fe60db294c786f6b7c2d2e121576628468f65453d86b0fe36cb52f987bd74", size = 94909, upload-time = "2025-10-06T14:09:48.648Z" }, + { url = "https://files.pythonhosted.org/packages/60/41/9a1fe0b73dbcefce72e46cf149b0e0a67612d60bfc90fb59c2b2efdfbd86/yarl-1.22.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1651bf8e0398574646744c1885a41198eba53dc8a9312b954073f845c90a8df", size = 372940, upload-time = "2025-10-06T14:09:50.089Z" }, + { url = "https://files.pythonhosted.org/packages/17/7a/795cb6dfee561961c30b800f0ed616b923a2ec6258b5def2a00bf8231334/yarl-1.22.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b8a0588521a26bf92a57a1705b77b8b59044cdceccac7151bd8d229e66b8dedb", size = 345825, upload-time = "2025-10-06T14:09:52.142Z" }, + { url = "https://files.pythonhosted.org/packages/d7/93/a58f4d596d2be2ae7bab1a5846c4d270b894958845753b2c606d666744d3/yarl-1.22.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:42188e6a615c1a75bcaa6e150c3fe8f3e8680471a6b10150c5f7e83f47cc34d2", size = 386705, upload-time = "2025-10-06T14:09:54.128Z" }, + { url = "https://files.pythonhosted.org/packages/61/92/682279d0e099d0e14d7fd2e176bd04f48de1484f56546a3e1313cd6c8e7c/yarl-1.22.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f6d2cb59377d99718913ad9a151030d6f83ef420a2b8f521d94609ecc106ee82", size = 396518, upload-time = "2025-10-06T14:09:55.762Z" }, + { url = "https://files.pythonhosted.org/packages/db/0f/0d52c98b8a885aeda831224b78f3be7ec2e1aa4a62091f9f9188c3c65b56/yarl-1.22.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50678a3b71c751d58d7908edc96d332af328839eea883bb554a43f539101277a", size = 377267, upload-time = "2025-10-06T14:09:57.958Z" }, + { url = "https://files.pythonhosted.org/packages/22/42/d2685e35908cbeaa6532c1fc73e89e7f2efb5d8a7df3959ea8e37177c5a3/yarl-1.22.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e8fbaa7cec507aa24ea27a01456e8dd4b6fab829059b69844bd348f2d467124", size = 365797, upload-time = "2025-10-06T14:09:59.527Z" }, + { url = "https://files.pythonhosted.org/packages/a2/83/cf8c7bcc6355631762f7d8bdab920ad09b82efa6b722999dfb05afa6cfac/yarl-1.22.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:433885ab5431bc3d3d4f2f9bd15bfa1614c522b0f1405d62c4f926ccd69d04fa", size = 365535, upload-time = "2025-10-06T14:10:01.139Z" }, + { url = "https://files.pythonhosted.org/packages/25/e1/5302ff9b28f0c59cac913b91fe3f16c59a033887e57ce9ca5d41a3a94737/yarl-1.22.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:b790b39c7e9a4192dc2e201a282109ed2985a1ddbd5ac08dc56d0e121400a8f7", size = 382324, upload-time = "2025-10-06T14:10:02.756Z" }, + { url = "https://files.pythonhosted.org/packages/bf/cd/4617eb60f032f19ae3a688dc990d8f0d89ee0ea378b61cac81ede3e52fae/yarl-1.22.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:31f0b53913220599446872d757257be5898019c85e7971599065bc55065dc99d", size = 383803, upload-time = "2025-10-06T14:10:04.552Z" }, + { url = "https://files.pythonhosted.org/packages/59/65/afc6e62bb506a319ea67b694551dab4a7e6fb7bf604e9bd9f3e11d575fec/yarl-1.22.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a49370e8f711daec68d09b821a34e1167792ee2d24d405cbc2387be4f158b520", size = 374220, upload-time = "2025-10-06T14:10:06.489Z" }, + { url = "https://files.pythonhosted.org/packages/e7/3d/68bf18d50dc674b942daec86a9ba922d3113d8399b0e52b9897530442da2/yarl-1.22.0-cp312-cp312-win32.whl", hash = "sha256:70dfd4f241c04bd9239d53b17f11e6ab672b9f1420364af63e8531198e3f5fe8", size = 81589, upload-time = "2025-10-06T14:10:09.254Z" }, + { url = "https://files.pythonhosted.org/packages/c8/9a/6ad1a9b37c2f72874f93e691b2e7ecb6137fb2b899983125db4204e47575/yarl-1.22.0-cp312-cp312-win_amd64.whl", hash = "sha256:8884d8b332a5e9b88e23f60bb166890009429391864c685e17bd73a9eda9105c", size = 87213, upload-time = "2025-10-06T14:10:11.369Z" }, + { url = "https://files.pythonhosted.org/packages/44/c5/c21b562d1680a77634d748e30c653c3ca918beb35555cff24986fff54598/yarl-1.22.0-cp312-cp312-win_arm64.whl", hash = "sha256:ea70f61a47f3cc93bdf8b2f368ed359ef02a01ca6393916bc8ff877427181e74", size = 81330, upload-time = "2025-10-06T14:10:13.112Z" }, + { url = "https://files.pythonhosted.org/packages/ea/f3/d67de7260456ee105dc1d162d43a019ecad6b91e2f51809d6cddaa56690e/yarl-1.22.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8dee9c25c74997f6a750cd317b8ca63545169c098faee42c84aa5e506c819b53", size = 139980, upload-time = "2025-10-06T14:10:14.601Z" }, + { url = "https://files.pythonhosted.org/packages/01/88/04d98af0b47e0ef42597b9b28863b9060bb515524da0a65d5f4db160b2d5/yarl-1.22.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:01e73b85a5434f89fc4fe27dcda2aff08ddf35e4d47bbbea3bdcd25321af538a", size = 93424, upload-time = "2025-10-06T14:10:16.115Z" }, + { url = "https://files.pythonhosted.org/packages/18/91/3274b215fd8442a03975ce6bee5fe6aa57a8326b29b9d3d56234a1dca244/yarl-1.22.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:22965c2af250d20c873cdbee8ff958fb809940aeb2e74ba5f20aaf6b7ac8c70c", size = 93821, upload-time = "2025-10-06T14:10:17.993Z" }, + { url = "https://files.pythonhosted.org/packages/61/3a/caf4e25036db0f2da4ca22a353dfeb3c9d3c95d2761ebe9b14df8fc16eb0/yarl-1.22.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4f15793aa49793ec8d1c708ab7f9eded1aa72edc5174cae703651555ed1b601", size = 373243, upload-time = "2025-10-06T14:10:19.44Z" }, + { url = "https://files.pythonhosted.org/packages/6e/9e/51a77ac7516e8e7803b06e01f74e78649c24ee1021eca3d6a739cb6ea49c/yarl-1.22.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5542339dcf2747135c5c85f68680353d5cb9ffd741c0f2e8d832d054d41f35a", size = 342361, upload-time = "2025-10-06T14:10:21.124Z" }, + { url = "https://files.pythonhosted.org/packages/d4/f8/33b92454789dde8407f156c00303e9a891f1f51a0330b0fad7c909f87692/yarl-1.22.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5c401e05ad47a75869c3ab3e35137f8468b846770587e70d71e11de797d113df", size = 387036, upload-time = "2025-10-06T14:10:22.902Z" }, + { url = "https://files.pythonhosted.org/packages/d9/9a/c5db84ea024f76838220280f732970aa4ee154015d7f5c1bfb60a267af6f/yarl-1.22.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:243dda95d901c733f5b59214d28b0120893d91777cb8aa043e6ef059d3cddfe2", size = 397671, upload-time = "2025-10-06T14:10:24.523Z" }, + { url = "https://files.pythonhosted.org/packages/11/c9/cd8538dc2e7727095e0c1d867bad1e40c98f37763e6d995c1939f5fdc7b1/yarl-1.22.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bec03d0d388060058f5d291a813f21c011041938a441c593374da6077fe21b1b", size = 377059, upload-time = "2025-10-06T14:10:26.406Z" }, + { url = "https://files.pythonhosted.org/packages/a1/b9/ab437b261702ced75122ed78a876a6dec0a1b0f5e17a4ac7a9a2482d8abe/yarl-1.22.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0748275abb8c1e1e09301ee3cf90c8a99678a4e92e4373705f2a2570d581273", size = 365356, upload-time = "2025-10-06T14:10:28.461Z" }, + { url = "https://files.pythonhosted.org/packages/b2/9d/8e1ae6d1d008a9567877b08f0ce4077a29974c04c062dabdb923ed98e6fe/yarl-1.22.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:47fdb18187e2a4e18fda2c25c05d8251a9e4a521edaed757fef033e7d8498d9a", size = 361331, upload-time = "2025-10-06T14:10:30.541Z" }, + { url = "https://files.pythonhosted.org/packages/ca/5a/09b7be3905962f145b73beb468cdd53db8aa171cf18c80400a54c5b82846/yarl-1.22.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c7044802eec4524fde550afc28edda0dd5784c4c45f0be151a2d3ba017daca7d", size = 382590, upload-time = "2025-10-06T14:10:33.352Z" }, + { url = "https://files.pythonhosted.org/packages/aa/7f/59ec509abf90eda5048b0bc3e2d7b5099dffdb3e6b127019895ab9d5ef44/yarl-1.22.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:139718f35149ff544caba20fce6e8a2f71f1e39b92c700d8438a0b1d2a631a02", size = 385316, upload-time = "2025-10-06T14:10:35.034Z" }, + { url = "https://files.pythonhosted.org/packages/e5/84/891158426bc8036bfdfd862fabd0e0fa25df4176ec793e447f4b85cf1be4/yarl-1.22.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e1b51bebd221006d3d2f95fbe124b22b247136647ae5dcc8c7acafba66e5ee67", size = 374431, upload-time = "2025-10-06T14:10:37.76Z" }, + { url = "https://files.pythonhosted.org/packages/bb/49/03da1580665baa8bef5e8ed34c6df2c2aca0a2f28bf397ed238cc1bbc6f2/yarl-1.22.0-cp313-cp313-win32.whl", hash = "sha256:d3e32536234a95f513bd374e93d717cf6b2231a791758de6c509e3653f234c95", size = 81555, upload-time = "2025-10-06T14:10:39.649Z" }, + { url = "https://files.pythonhosted.org/packages/9a/ee/450914ae11b419eadd067c6183ae08381cfdfcb9798b90b2b713bbebddda/yarl-1.22.0-cp313-cp313-win_amd64.whl", hash = "sha256:47743b82b76d89a1d20b83e60d5c20314cbd5ba2befc9cda8f28300c4a08ed4d", size = 86965, upload-time = "2025-10-06T14:10:41.313Z" }, + { url = "https://files.pythonhosted.org/packages/98/4d/264a01eae03b6cf629ad69bae94e3b0e5344741e929073678e84bf7a3e3b/yarl-1.22.0-cp313-cp313-win_arm64.whl", hash = "sha256:5d0fcda9608875f7d052eff120c7a5da474a6796fe4d83e152e0e4d42f6d1a9b", size = 81205, upload-time = "2025-10-06T14:10:43.167Z" }, + { url = "https://files.pythonhosted.org/packages/88/fc/6908f062a2f77b5f9f6d69cecb1747260831ff206adcbc5b510aff88df91/yarl-1.22.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:719ae08b6972befcba4310e49edb1161a88cdd331e3a694b84466bd938a6ab10", size = 146209, upload-time = "2025-10-06T14:10:44.643Z" }, + { url = "https://files.pythonhosted.org/packages/65/47/76594ae8eab26210b4867be6f49129861ad33da1f1ebdf7051e98492bf62/yarl-1.22.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:47d8a5c446df1c4db9d21b49619ffdba90e77c89ec6e283f453856c74b50b9e3", size = 95966, upload-time = "2025-10-06T14:10:46.554Z" }, + { url = "https://files.pythonhosted.org/packages/ab/ce/05e9828a49271ba6b5b038b15b3934e996980dd78abdfeb52a04cfb9467e/yarl-1.22.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:cfebc0ac8333520d2d0423cbbe43ae43c8838862ddb898f5ca68565e395516e9", size = 97312, upload-time = "2025-10-06T14:10:48.007Z" }, + { url = "https://files.pythonhosted.org/packages/d1/c5/7dffad5e4f2265b29c9d7ec869c369e4223166e4f9206fc2243ee9eea727/yarl-1.22.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4398557cbf484207df000309235979c79c4356518fd5c99158c7d38203c4da4f", size = 361967, upload-time = "2025-10-06T14:10:49.997Z" }, + { url = "https://files.pythonhosted.org/packages/50/b2/375b933c93a54bff7fc041e1a6ad2c0f6f733ffb0c6e642ce56ee3b39970/yarl-1.22.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2ca6fd72a8cd803be290d42f2dec5cdcd5299eeb93c2d929bf060ad9efaf5de0", size = 323949, upload-time = "2025-10-06T14:10:52.004Z" }, + { url = "https://files.pythonhosted.org/packages/66/50/bfc2a29a1d78644c5a7220ce2f304f38248dc94124a326794e677634b6cf/yarl-1.22.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ca1f59c4e1ab6e72f0a23c13fca5430f889634166be85dbf1013683e49e3278e", size = 361818, upload-time = "2025-10-06T14:10:54.078Z" }, + { url = "https://files.pythonhosted.org/packages/46/96/f3941a46af7d5d0f0498f86d71275696800ddcdd20426298e572b19b91ff/yarl-1.22.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c5010a52015e7c70f86eb967db0f37f3c8bd503a695a49f8d45700144667708", size = 372626, upload-time = "2025-10-06T14:10:55.767Z" }, + { url = "https://files.pythonhosted.org/packages/c1/42/8b27c83bb875cd89448e42cd627e0fb971fa1675c9ec546393d18826cb50/yarl-1.22.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d7672ecf7557476642c88497c2f8d8542f8e36596e928e9bcba0e42e1e7d71f", size = 341129, upload-time = "2025-10-06T14:10:57.985Z" }, + { url = "https://files.pythonhosted.org/packages/49/36/99ca3122201b382a3cf7cc937b95235b0ac944f7e9f2d5331d50821ed352/yarl-1.22.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3b7c88eeef021579d600e50363e0b6ee4f7f6f728cd3486b9d0f3ee7b946398d", size = 346776, upload-time = "2025-10-06T14:10:59.633Z" }, + { url = "https://files.pythonhosted.org/packages/85/b4/47328bf996acd01a4c16ef9dcd2f59c969f495073616586f78cd5f2efb99/yarl-1.22.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f4afb5c34f2c6fecdcc182dfcfc6af6cccf1aa923eed4d6a12e9d96904e1a0d8", size = 334879, upload-time = "2025-10-06T14:11:01.454Z" }, + { url = "https://files.pythonhosted.org/packages/c2/ad/b77d7b3f14a4283bffb8e92c6026496f6de49751c2f97d4352242bba3990/yarl-1.22.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:59c189e3e99a59cf8d83cbb31d4db02d66cda5a1a4374e8a012b51255341abf5", size = 350996, upload-time = "2025-10-06T14:11:03.452Z" }, + { url = "https://files.pythonhosted.org/packages/81/c8/06e1d69295792ba54d556f06686cbd6a7ce39c22307100e3fb4a2c0b0a1d/yarl-1.22.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:5a3bf7f62a289fa90f1990422dc8dff5a458469ea71d1624585ec3a4c8d6960f", size = 356047, upload-time = "2025-10-06T14:11:05.115Z" }, + { url = "https://files.pythonhosted.org/packages/4b/b8/4c0e9e9f597074b208d18cef227d83aac36184bfbc6eab204ea55783dbc5/yarl-1.22.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:de6b9a04c606978fdfe72666fa216ffcf2d1a9f6a381058d4378f8d7b1e5de62", size = 342947, upload-time = "2025-10-06T14:11:08.137Z" }, + { url = "https://files.pythonhosted.org/packages/e0/e5/11f140a58bf4c6ad7aca69a892bff0ee638c31bea4206748fc0df4ebcb3a/yarl-1.22.0-cp313-cp313t-win32.whl", hash = "sha256:1834bb90991cc2999f10f97f5f01317f99b143284766d197e43cd5b45eb18d03", size = 86943, upload-time = "2025-10-06T14:11:10.284Z" }, + { url = "https://files.pythonhosted.org/packages/31/74/8b74bae38ed7fe6793d0c15a0c8207bbb819cf287788459e5ed230996cdd/yarl-1.22.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ff86011bd159a9d2dfc89c34cfd8aff12875980e3bd6a39ff097887520e60249", size = 93715, upload-time = "2025-10-06T14:11:11.739Z" }, + { url = "https://files.pythonhosted.org/packages/69/66/991858aa4b5892d57aef7ee1ba6b4d01ec3b7eb3060795d34090a3ca3278/yarl-1.22.0-cp313-cp313t-win_arm64.whl", hash = "sha256:7861058d0582b847bc4e3a4a4c46828a410bca738673f35a29ba3ca5db0b473b", size = 83857, upload-time = "2025-10-06T14:11:13.586Z" }, + { url = "https://files.pythonhosted.org/packages/46/b3/e20ef504049f1a1c54a814b4b9bed96d1ac0e0610c3b4da178f87209db05/yarl-1.22.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:34b36c2c57124530884d89d50ed2c1478697ad7473efd59cfd479945c95650e4", size = 140520, upload-time = "2025-10-06T14:11:15.465Z" }, + { url = "https://files.pythonhosted.org/packages/e4/04/3532d990fdbab02e5ede063676b5c4260e7f3abea2151099c2aa745acc4c/yarl-1.22.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:0dd9a702591ca2e543631c2a017e4a547e38a5c0f29eece37d9097e04a7ac683", size = 93504, upload-time = "2025-10-06T14:11:17.106Z" }, + { url = "https://files.pythonhosted.org/packages/11/63/ff458113c5c2dac9a9719ac68ee7c947cb621432bcf28c9972b1c0e83938/yarl-1.22.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:594fcab1032e2d2cc3321bb2e51271e7cd2b516c7d9aee780ece81b07ff8244b", size = 94282, upload-time = "2025-10-06T14:11:19.064Z" }, + { url = "https://files.pythonhosted.org/packages/a7/bc/315a56aca762d44a6aaaf7ad253f04d996cb6b27bad34410f82d76ea8038/yarl-1.22.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f3d7a87a78d46a2e3d5b72587ac14b4c16952dd0887dbb051451eceac774411e", size = 372080, upload-time = "2025-10-06T14:11:20.996Z" }, + { url = "https://files.pythonhosted.org/packages/3f/3f/08e9b826ec2e099ea6e7c69a61272f4f6da62cb5b1b63590bb80ca2e4a40/yarl-1.22.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:852863707010316c973162e703bddabec35e8757e67fcb8ad58829de1ebc8590", size = 338696, upload-time = "2025-10-06T14:11:22.847Z" }, + { url = "https://files.pythonhosted.org/packages/e3/9f/90360108e3b32bd76789088e99538febfea24a102380ae73827f62073543/yarl-1.22.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:131a085a53bfe839a477c0845acf21efc77457ba2bcf5899618136d64f3303a2", size = 387121, upload-time = "2025-10-06T14:11:24.889Z" }, + { url = "https://files.pythonhosted.org/packages/98/92/ab8d4657bd5b46a38094cfaea498f18bb70ce6b63508fd7e909bd1f93066/yarl-1.22.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:078a8aefd263f4d4f923a9677b942b445a2be970ca24548a8102689a3a8ab8da", size = 394080, upload-time = "2025-10-06T14:11:27.307Z" }, + { url = "https://files.pythonhosted.org/packages/f5/e7/d8c5a7752fef68205296201f8ec2bf718f5c805a7a7e9880576c67600658/yarl-1.22.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bca03b91c323036913993ff5c738d0842fc9c60c4648e5c8d98331526df89784", size = 372661, upload-time = "2025-10-06T14:11:29.387Z" }, + { url = "https://files.pythonhosted.org/packages/b6/2e/f4d26183c8db0bb82d491b072f3127fb8c381a6206a3a56332714b79b751/yarl-1.22.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:68986a61557d37bb90d3051a45b91fa3d5c516d177dfc6dd6f2f436a07ff2b6b", size = 364645, upload-time = "2025-10-06T14:11:31.423Z" }, + { url = "https://files.pythonhosted.org/packages/80/7c/428e5812e6b87cd00ee8e898328a62c95825bf37c7fa87f0b6bb2ad31304/yarl-1.22.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:4792b262d585ff0dff6bcb787f8492e40698443ec982a3568c2096433660c694", size = 355361, upload-time = "2025-10-06T14:11:33.055Z" }, + { url = "https://files.pythonhosted.org/packages/ec/2a/249405fd26776f8b13c067378ef4d7dd49c9098d1b6457cdd152a99e96a9/yarl-1.22.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ebd4549b108d732dba1d4ace67614b9545b21ece30937a63a65dd34efa19732d", size = 381451, upload-time = "2025-10-06T14:11:35.136Z" }, + { url = "https://files.pythonhosted.org/packages/67/a8/fb6b1adbe98cf1e2dd9fad71003d3a63a1bc22459c6e15f5714eb9323b93/yarl-1.22.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f87ac53513d22240c7d59203f25cc3beac1e574c6cd681bbfd321987b69f95fd", size = 383814, upload-time = "2025-10-06T14:11:37.094Z" }, + { url = "https://files.pythonhosted.org/packages/d9/f9/3aa2c0e480fb73e872ae2814c43bc1e734740bb0d54e8cb2a95925f98131/yarl-1.22.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:22b029f2881599e2f1b06f8f1db2ee63bd309e2293ba2d566e008ba12778b8da", size = 370799, upload-time = "2025-10-06T14:11:38.83Z" }, + { url = "https://files.pythonhosted.org/packages/50/3c/af9dba3b8b5eeb302f36f16f92791f3ea62e3f47763406abf6d5a4a3333b/yarl-1.22.0-cp314-cp314-win32.whl", hash = "sha256:6a635ea45ba4ea8238463b4f7d0e721bad669f80878b7bfd1f89266e2ae63da2", size = 82990, upload-time = "2025-10-06T14:11:40.624Z" }, + { url = "https://files.pythonhosted.org/packages/ac/30/ac3a0c5bdc1d6efd1b41fa24d4897a4329b3b1e98de9449679dd327af4f0/yarl-1.22.0-cp314-cp314-win_amd64.whl", hash = "sha256:0d6e6885777af0f110b0e5d7e5dda8b704efed3894da26220b7f3d887b839a79", size = 88292, upload-time = "2025-10-06T14:11:42.578Z" }, + { url = "https://files.pythonhosted.org/packages/df/0a/227ab4ff5b998a1b7410abc7b46c9b7a26b0ca9e86c34ba4b8d8bc7c63d5/yarl-1.22.0-cp314-cp314-win_arm64.whl", hash = "sha256:8218f4e98d3c10d683584cb40f0424f4b9fd6e95610232dd75e13743b070ee33", size = 82888, upload-time = "2025-10-06T14:11:44.863Z" }, + { url = "https://files.pythonhosted.org/packages/06/5e/a15eb13db90abd87dfbefb9760c0f3f257ac42a5cac7e75dbc23bed97a9f/yarl-1.22.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:45c2842ff0e0d1b35a6bf1cd6c690939dacb617a70827f715232b2e0494d55d1", size = 146223, upload-time = "2025-10-06T14:11:46.796Z" }, + { url = "https://files.pythonhosted.org/packages/18/82/9665c61910d4d84f41a5bf6837597c89e665fa88aa4941080704645932a9/yarl-1.22.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d947071e6ebcf2e2bee8fce76e10faca8f7a14808ca36a910263acaacef08eca", size = 95981, upload-time = "2025-10-06T14:11:48.845Z" }, + { url = "https://files.pythonhosted.org/packages/5d/9a/2f65743589809af4d0a6d3aa749343c4b5f4c380cc24a8e94a3c6625a808/yarl-1.22.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:334b8721303e61b00019474cc103bdac3d7b1f65e91f0bfedeec2d56dfe74b53", size = 97303, upload-time = "2025-10-06T14:11:50.897Z" }, + { url = "https://files.pythonhosted.org/packages/b0/ab/5b13d3e157505c43c3b43b5a776cbf7b24a02bc4cccc40314771197e3508/yarl-1.22.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e7ce67c34138a058fd092f67d07a72b8e31ff0c9236e751957465a24b28910c", size = 361820, upload-time = "2025-10-06T14:11:52.549Z" }, + { url = "https://files.pythonhosted.org/packages/fb/76/242a5ef4677615cf95330cfc1b4610e78184400699bdda0acb897ef5e49a/yarl-1.22.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d77e1b2c6d04711478cb1c4ab90db07f1609ccf06a287d5607fcd90dc9863acf", size = 323203, upload-time = "2025-10-06T14:11:54.225Z" }, + { url = "https://files.pythonhosted.org/packages/8c/96/475509110d3f0153b43d06164cf4195c64d16999e0c7e2d8a099adcd6907/yarl-1.22.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4647674b6150d2cae088fc07de2738a84b8bcedebef29802cf0b0a82ab6face", size = 363173, upload-time = "2025-10-06T14:11:56.069Z" }, + { url = "https://files.pythonhosted.org/packages/c9/66/59db471aecfbd559a1fd48aedd954435558cd98c7d0da8b03cc6c140a32c/yarl-1.22.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efb07073be061c8f79d03d04139a80ba33cbd390ca8f0297aae9cce6411e4c6b", size = 373562, upload-time = "2025-10-06T14:11:58.783Z" }, + { url = "https://files.pythonhosted.org/packages/03/1f/c5d94abc91557384719da10ff166b916107c1b45e4d0423a88457071dd88/yarl-1.22.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e51ac5435758ba97ad69617e13233da53908beccc6cfcd6c34bbed8dcbede486", size = 339828, upload-time = "2025-10-06T14:12:00.686Z" }, + { url = "https://files.pythonhosted.org/packages/5f/97/aa6a143d3afba17b6465733681c70cf175af89f76ec8d9286e08437a7454/yarl-1.22.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:33e32a0dd0c8205efa8e83d04fc9f19313772b78522d1bdc7d9aed706bfd6138", size = 347551, upload-time = "2025-10-06T14:12:02.628Z" }, + { url = "https://files.pythonhosted.org/packages/43/3c/45a2b6d80195959239a7b2a8810506d4eea5487dce61c2a3393e7fc3c52e/yarl-1.22.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:bf4a21e58b9cde0e401e683ebd00f6ed30a06d14e93f7c8fd059f8b6e8f87b6a", size = 334512, upload-time = "2025-10-06T14:12:04.871Z" }, + { url = "https://files.pythonhosted.org/packages/86/a0/c2ab48d74599c7c84cb104ebd799c5813de252bea0f360ffc29d270c2caa/yarl-1.22.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:e4b582bab49ac33c8deb97e058cd67c2c50dac0dd134874106d9c774fd272529", size = 352400, upload-time = "2025-10-06T14:12:06.624Z" }, + { url = "https://files.pythonhosted.org/packages/32/75/f8919b2eafc929567d3d8411f72bdb1a2109c01caaab4ebfa5f8ffadc15b/yarl-1.22.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0b5bcc1a9c4839e7e30b7b30dd47fe5e7e44fb7054ec29b5bb8d526aa1041093", size = 357140, upload-time = "2025-10-06T14:12:08.362Z" }, + { url = "https://files.pythonhosted.org/packages/cf/72/6a85bba382f22cf78add705d8c3731748397d986e197e53ecc7835e76de7/yarl-1.22.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c0232bce2170103ec23c454e54a57008a9a72b5d1c3105dc2496750da8cfa47c", size = 341473, upload-time = "2025-10-06T14:12:10.994Z" }, + { url = "https://files.pythonhosted.org/packages/35/18/55e6011f7c044dc80b98893060773cefcfdbf60dfefb8cb2f58b9bacbd83/yarl-1.22.0-cp314-cp314t-win32.whl", hash = "sha256:8009b3173bcd637be650922ac455946197d858b3630b6d8787aa9e5c4564533e", size = 89056, upload-time = "2025-10-06T14:12:13.317Z" }, + { url = "https://files.pythonhosted.org/packages/f9/86/0f0dccb6e59a9e7f122c5afd43568b1d31b8ab7dda5f1b01fb5c7025c9a9/yarl-1.22.0-cp314-cp314t-win_amd64.whl", hash = "sha256:9fb17ea16e972c63d25d4a97f016d235c78dd2344820eb35bc034bc32012ee27", size = 96292, upload-time = "2025-10-06T14:12:15.398Z" }, + { url = "https://files.pythonhosted.org/packages/48/b7/503c98092fb3b344a179579f55814b613c1fbb1c23b3ec14a7b008a66a6e/yarl-1.22.0-cp314-cp314t-win_arm64.whl", hash = "sha256:9f6d73c1436b934e3f01df1e1b21ff765cd1d28c77dfb9ace207f746d4610ee1", size = 85171, upload-time = "2025-10-06T14:12:16.935Z" }, + { url = "https://files.pythonhosted.org/packages/94/fd/6480106702a79bcceda5fd9c63cb19a04a6506bd5ce7fd8d9b63742f0021/yarl-1.22.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3aa27acb6de7a23785d81557577491f6c38a5209a254d1191519d07d8fe51748", size = 141301, upload-time = "2025-10-06T14:12:19.01Z" }, + { url = "https://files.pythonhosted.org/packages/42/e1/6d95d21b17a93e793e4ec420a925fe1f6a9342338ca7a563ed21129c0990/yarl-1.22.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:af74f05666a5e531289cb1cc9c883d1de2088b8e5b4de48004e5ca8a830ac859", size = 93864, upload-time = "2025-10-06T14:12:21.05Z" }, + { url = "https://files.pythonhosted.org/packages/32/58/b8055273c203968e89808413ea4c984988b6649baabf10f4522e67c22d2f/yarl-1.22.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:62441e55958977b8167b2709c164c91a6363e25da322d87ae6dd9c6019ceecf9", size = 94706, upload-time = "2025-10-06T14:12:23.287Z" }, + { url = "https://files.pythonhosted.org/packages/18/91/d7bfbc28a88c2895ecd0da6a874def0c147de78afc52c773c28e1aa233a3/yarl-1.22.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b580e71cac3f8113d3135888770903eaf2f507e9421e5697d6ee6d8cd1c7f054", size = 347100, upload-time = "2025-10-06T14:12:28.527Z" }, + { url = "https://files.pythonhosted.org/packages/bd/e8/37a1e7b99721c0564b1fc7b0a4d1f595ef6fb8060d82ca61775b644185f7/yarl-1.22.0-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e81fda2fb4a07eda1a2252b216aa0df23ebcd4d584894e9612e80999a78fd95b", size = 318902, upload-time = "2025-10-06T14:12:30.528Z" }, + { url = "https://files.pythonhosted.org/packages/1c/ef/34724449d7ef2db4f22df644f2dac0b8a275d20f585e526937b3ae47b02d/yarl-1.22.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:99b6fc1d55782461b78221e95fc357b47ad98b041e8e20f47c1411d0aacddc60", size = 363302, upload-time = "2025-10-06T14:12:32.295Z" }, + { url = "https://files.pythonhosted.org/packages/8a/04/88a39a5dad39889f192cce8d66cc4c58dbeca983e83f9b6bf23822a7ed91/yarl-1.22.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:088e4e08f033db4be2ccd1f34cf29fe994772fb54cfe004bbf54db320af56890", size = 370816, upload-time = "2025-10-06T14:12:34.01Z" }, + { url = "https://files.pythonhosted.org/packages/6b/1f/5e895e547129413f56c76be2c3ce4b96c797d2d0ff3e16a817d9269b12e6/yarl-1.22.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e4e1f6f0b4da23e61188676e3ed027ef0baa833a2e633c29ff8530800edccba", size = 346465, upload-time = "2025-10-06T14:12:35.977Z" }, + { url = "https://files.pythonhosted.org/packages/11/13/a750e9fd6f9cc9ed3a52a70fe58ffe505322f0efe0d48e1fd9ffe53281f5/yarl-1.22.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:84fc3ec96fce86ce5aa305eb4aa9358279d1aa644b71fab7b8ed33fe3ba1a7ca", size = 341506, upload-time = "2025-10-06T14:12:37.788Z" }, + { url = "https://files.pythonhosted.org/packages/3c/67/bb6024de76e7186611ebe626aec5b71a2d2ecf9453e795f2dbd80614784c/yarl-1.22.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:5dbeefd6ca588b33576a01b0ad58aa934bc1b41ef89dee505bf2932b22ddffba", size = 335030, upload-time = "2025-10-06T14:12:39.775Z" }, + { url = "https://files.pythonhosted.org/packages/a2/be/50b38447fd94a7992996a62b8b463d0579323fcfc08c61bdba949eef8a5d/yarl-1.22.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:14291620375b1060613f4aab9ebf21850058b6b1b438f386cc814813d901c60b", size = 358560, upload-time = "2025-10-06T14:12:41.547Z" }, + { url = "https://files.pythonhosted.org/packages/e2/89/c020b6f547578c4e3dbb6335bf918f26e2f34ad0d1e515d72fd33ac0c635/yarl-1.22.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:a4fcfc8eb2c34148c118dfa02e6427ca278bfd0f3df7c5f99e33d2c0e81eae3e", size = 357290, upload-time = "2025-10-06T14:12:43.861Z" }, + { url = "https://files.pythonhosted.org/packages/8c/52/c49a619ee35a402fa3a7019a4fa8d26878fec0d1243f6968bbf516789578/yarl-1.22.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:029866bde8d7b0878b9c160e72305bbf0a7342bcd20b9999381704ae03308dc8", size = 350700, upload-time = "2025-10-06T14:12:46.868Z" }, + { url = "https://files.pythonhosted.org/packages/ab/c9/f5042d87777bf6968435f04a2bbb15466b2f142e6e47fa4f34d1a3f32f0c/yarl-1.22.0-cp39-cp39-win32.whl", hash = "sha256:4dcc74149ccc8bba31ce1944acee24813e93cfdee2acda3c172df844948ddf7b", size = 82323, upload-time = "2025-10-06T14:12:48.633Z" }, + { url = "https://files.pythonhosted.org/packages/fd/58/d00f7cad9eba20c4eefac2682f34661d1d1b3a942fc0092eb60e78cfb733/yarl-1.22.0-cp39-cp39-win_amd64.whl", hash = "sha256:10619d9fdee46d20edc49d3479e2f8269d0779f1b031e6f7c2aa1c76be04b7ed", size = 87145, upload-time = "2025-10-06T14:12:50.241Z" }, + { url = "https://files.pythonhosted.org/packages/c2/a3/70904f365080780d38b919edd42d224b8c4ce224a86950d2eaa2a24366ad/yarl-1.22.0-cp39-cp39-win_arm64.whl", hash = "sha256:dd7afd3f8b0bfb4e0d9fc3c31bfe8a4ec7debe124cfd90619305def3c8ca8cd2", size = 82173, upload-time = "2025-10-06T14:12:51.869Z" }, + { url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814, upload-time = "2025-10-06T14:12:53.872Z" }, +] + +[[package]] +name = "yarl" +version = "1.23.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", +] +dependencies = [ + { name = "idna", marker = "python_full_version >= '3.10'" }, + { name = "multidict", marker = "python_full_version >= '3.10'" }, + { name = "propcache", marker = "python_full_version >= '3.10'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/23/6e/beb1beec874a72f23815c1434518bfc4ed2175065173fb138c3705f658d4/yarl-1.23.0.tar.gz", hash = "sha256:53b1ea6ca88ebd4420379c330aea57e258408dd0df9af0992e5de2078dc9f5d5", size = 194676, upload-time = "2026-03-01T22:07:53.373Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8b/0d/9cc638702f6fc3c7a3685bcc8cf2a9ed7d6206e932a49f5242658047ef51/yarl-1.23.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cff6d44cb13d39db2663a22b22305d10855efa0fa8015ddeacc40bc59b9d8107", size = 123764, upload-time = "2026-03-01T22:04:09.7Z" }, + { url = "https://files.pythonhosted.org/packages/7a/35/5a553687c5793df5429cd1db45909d4f3af7eee90014888c208d086a44f0/yarl-1.23.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e4c53f8347cd4200f0d70a48ad059cabaf24f5adc6ba08622a23423bc7efa10d", size = 86282, upload-time = "2026-03-01T22:04:11.892Z" }, + { url = "https://files.pythonhosted.org/packages/68/2e/c5a2234238f8ce37a8312b52801ee74117f576b1539eec8404a480434acc/yarl-1.23.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2a6940a074fb3c48356ed0158a3ca5699c955ee4185b4d7d619be3c327143e05", size = 86053, upload-time = "2026-03-01T22:04:13.292Z" }, + { url = "https://files.pythonhosted.org/packages/74/3f/bbd8ff36fb038622797ffbaf7db314918bb4d76f1cc8a4f9ca7a55fe5195/yarl-1.23.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ed5f69ce7be7902e5c70ea19eb72d20abf7d725ab5d49777d696e32d4fc1811d", size = 99395, upload-time = "2026-03-01T22:04:15.133Z" }, + { url = "https://files.pythonhosted.org/packages/77/04/9516bc4e269d2a3ec9c6779fcdeac51ce5b3a9b0156f06ac7152e5bba864/yarl-1.23.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:389871e65468400d6283c0308e791a640b5ab5c83bcee02a2f51295f95e09748", size = 92143, upload-time = "2026-03-01T22:04:16.829Z" }, + { url = "https://files.pythonhosted.org/packages/c7/63/88802d1f6b1cb1fc67d67a58cd0cf8a1790de4ce7946e434240f1d60ab4a/yarl-1.23.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:dda608c88cf709b1d406bdfcd84d8d63cff7c9e577a403c6108ce8ce9dcc8764", size = 107643, upload-time = "2026-03-01T22:04:18.519Z" }, + { url = "https://files.pythonhosted.org/packages/8e/db/4f9b838f4d8bdd6f0f385aed8bbf21c71ed11a0b9983305c302cbd557815/yarl-1.23.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8c4fe09e0780c6c3bf2b7d4af02ee2394439d11a523bbcf095cf4747c2932007", size = 108700, upload-time = "2026-03-01T22:04:20.373Z" }, + { url = "https://files.pythonhosted.org/packages/50/12/95a1d33f04a79c402664070d43b8b9f72dc18914e135b345b611b0b1f8cc/yarl-1.23.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:31c9921eb8bd12633b41ad27686bbb0b1a2a9b8452bfdf221e34f311e9942ed4", size = 102769, upload-time = "2026-03-01T22:04:23.055Z" }, + { url = "https://files.pythonhosted.org/packages/86/65/91a0285f51321369fd1a8308aa19207520c5f0587772cfc2e03fc2467e90/yarl-1.23.0-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5f10fd85e4b75967468af655228fbfd212bdf66db1c0d135065ce288982eda26", size = 101114, upload-time = "2026-03-01T22:04:25.031Z" }, + { url = "https://files.pythonhosted.org/packages/58/80/c7c8244fc3e5bc483dc71a09560f43b619fab29301a0f0a8f936e42865c7/yarl-1.23.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dbf507e9ef5688bada447a24d68b4b58dd389ba93b7afc065a2ba892bea54769", size = 98883, upload-time = "2026-03-01T22:04:27.281Z" }, + { url = "https://files.pythonhosted.org/packages/86/e7/71ca9cc9ca79c0b7d491216177d1aed559d632947b8ffb0ee60f7d8b23e3/yarl-1.23.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:85e9beda1f591bc73e77ea1c51965c68e98dafd0fec72cdd745f77d727466716", size = 94172, upload-time = "2026-03-01T22:04:28.554Z" }, + { url = "https://files.pythonhosted.org/packages/6a/3f/6c6c8a0fe29c26fb2db2e8d32195bb84ec1bfb8f1d32e7f73b787fcf349b/yarl-1.23.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:0e1fdaa14ef51366d7757b45bde294e95f6c8c049194e793eedb8387c86d5993", size = 107010, upload-time = "2026-03-01T22:04:30.385Z" }, + { url = "https://files.pythonhosted.org/packages/56/38/12730c05e5ad40a76374d440ed8b0899729a96c250516d91c620a6e38fc2/yarl-1.23.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:75e3026ab649bf48f9a10c0134512638725b521340293f202a69b567518d94e0", size = 100285, upload-time = "2026-03-01T22:04:31.752Z" }, + { url = "https://files.pythonhosted.org/packages/34/92/6a7be9239f2347234e027284e7a5f74b1140cc86575e7b469d13fba1ebfe/yarl-1.23.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:80e6d33a3d42a7549b409f199857b4fb54e2103fc44fb87605b6663b7a7ff750", size = 108230, upload-time = "2026-03-01T22:04:33.844Z" }, + { url = "https://files.pythonhosted.org/packages/5e/81/4aebccfa9376bd98b9d8bfad20621a57d3e8cfc5b8631c1fa5f62cdd03f4/yarl-1.23.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5ec2f42d41ccbd5df0270d7df31618a8ee267bfa50997f5d720ddba86c4a83a6", size = 103008, upload-time = "2026-03-01T22:04:35.856Z" }, + { url = "https://files.pythonhosted.org/packages/38/0f/0b4e3edcec794a86b853b0c6396c0a888d72dfce19b2d88c02ac289fb6c1/yarl-1.23.0-cp310-cp310-win32.whl", hash = "sha256:debe9c4f41c32990771be5c22b56f810659f9ddf3d63f67abfdcaa2c6c9c5c1d", size = 83073, upload-time = "2026-03-01T22:04:38.268Z" }, + { url = "https://files.pythonhosted.org/packages/a0/71/ad95c33da18897e4c636528bbc24a1dd23fe16797de8bc4ec667b8db0ba4/yarl-1.23.0-cp310-cp310-win_amd64.whl", hash = "sha256:ab5f043cb8a2d71c981c09c510da013bc79fd661f5c60139f00dd3c3cc4f2ffb", size = 87328, upload-time = "2026-03-01T22:04:39.558Z" }, + { url = "https://files.pythonhosted.org/packages/e2/14/dfa369523c79bccf9c9c746b0a63eb31f65db9418ac01275f7950962e504/yarl-1.23.0-cp310-cp310-win_arm64.whl", hash = "sha256:263cd4f47159c09b8b685890af949195b51d1aa82ba451c5847ca9bc6413c220", size = 82463, upload-time = "2026-03-01T22:04:41.454Z" }, + { url = "https://files.pythonhosted.org/packages/a2/aa/60da938b8f0997ba3a911263c40d82b6f645a67902a490b46f3355e10fae/yarl-1.23.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b35d13d549077713e4414f927cdc388d62e543987c572baee613bf82f11a4b99", size = 123641, upload-time = "2026-03-01T22:04:42.841Z" }, + { url = "https://files.pythonhosted.org/packages/24/84/e237607faf4e099dbb8a4f511cfd5efcb5f75918baad200ff7380635631b/yarl-1.23.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cbb0fef01f0c6b38cb0f39b1f78fc90b807e0e3c86a7ff3ce74ad77ce5c7880c", size = 86248, upload-time = "2026-03-01T22:04:44.757Z" }, + { url = "https://files.pythonhosted.org/packages/b2/0d/71ceabc14c146ba8ee3804ca7b3d42b1664c8440439de5214d366fec7d3a/yarl-1.23.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dc52310451fc7c629e13c4e061cbe2dd01684d91f2f8ee2821b083c58bd72432", size = 85988, upload-time = "2026-03-01T22:04:46.365Z" }, + { url = "https://files.pythonhosted.org/packages/8c/6c/4a90d59c572e46b270ca132aca66954f1175abd691f74c1ef4c6711828e2/yarl-1.23.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b2c6b50c7b0464165472b56b42d4c76a7b864597007d9c085e8b63e185cf4a7a", size = 100566, upload-time = "2026-03-01T22:04:47.639Z" }, + { url = "https://files.pythonhosted.org/packages/49/fb/c438fb5108047e629f6282a371e6e91cf3f97ee087c4fb748a1f32ceef55/yarl-1.23.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:aafe5dcfda86c8af00386d7781d4c2181b5011b7be3f2add5e99899ea925df05", size = 92079, upload-time = "2026-03-01T22:04:48.925Z" }, + { url = "https://files.pythonhosted.org/packages/d9/13/d269aa1aed3e4f50a5a103f96327210cc5fa5dd2d50882778f13c7a14606/yarl-1.23.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9ee33b875f0b390564c1fb7bc528abf18c8ee6073b201c6ae8524aca778e2d83", size = 108741, upload-time = "2026-03-01T22:04:50.838Z" }, + { url = "https://files.pythonhosted.org/packages/85/fb/115b16f22c37ea4437d323e472945bea97301c8ec6089868fa560abab590/yarl-1.23.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4c41e021bc6d7affb3364dc1e1e5fa9582b470f283748784bd6ea0558f87f42c", size = 108099, upload-time = "2026-03-01T22:04:52.499Z" }, + { url = "https://files.pythonhosted.org/packages/9a/64/c53487d9f4968045b8afa51aed7ca44f58b2589e772f32745f3744476c82/yarl-1.23.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:99c8a9ed30f4164bc4c14b37a90208836cbf50d4ce2a57c71d0f52c7fb4f7598", size = 102678, upload-time = "2026-03-01T22:04:55.176Z" }, + { url = "https://files.pythonhosted.org/packages/85/59/cd98e556fbb2bf8fab29c1a722f67ad45c5f3447cac798ab85620d1e70af/yarl-1.23.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f2af5c81a1f124609d5f33507082fc3f739959d4719b56877ab1ee7e7b3d602b", size = 100803, upload-time = "2026-03-01T22:04:56.588Z" }, + { url = "https://files.pythonhosted.org/packages/9e/c0/b39770b56d4a9f0bb5f77e2f1763cd2d75cc2f6c0131e3b4c360348fcd65/yarl-1.23.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6b41389c19b07c760c7e427a3462e8ab83c4bb087d127f0e854c706ce1b9215c", size = 100163, upload-time = "2026-03-01T22:04:58.492Z" }, + { url = "https://files.pythonhosted.org/packages/e7/64/6980f99ab00e1f0ff67cb84766c93d595b067eed07439cfccfc8fb28c1a6/yarl-1.23.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:1dc702e42d0684f42d6519c8d581e49c96cefaaab16691f03566d30658ee8788", size = 93859, upload-time = "2026-03-01T22:05:00.268Z" }, + { url = "https://files.pythonhosted.org/packages/38/69/912e6c5e146793e5d4b5fe39ff5b00f4d22463dfd5a162bec565ac757673/yarl-1.23.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:0e40111274f340d32ebcc0a5668d54d2b552a6cca84c9475859d364b380e3222", size = 108202, upload-time = "2026-03-01T22:05:02.273Z" }, + { url = "https://files.pythonhosted.org/packages/59/97/35ca6767524687ad64e5f5c31ad54bc76d585585a9fcb40f649e7e82ffed/yarl-1.23.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:4764a6a7588561a9aef92f65bda2c4fb58fe7c675c0883862e6df97559de0bfb", size = 99866, upload-time = "2026-03-01T22:05:03.597Z" }, + { url = "https://files.pythonhosted.org/packages/d3/1c/1a3387ee6d73589f6f2a220ae06f2984f6c20b40c734989b0a44f5987308/yarl-1.23.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:03214408cfa590df47728b84c679ae4ef00be2428e11630277be0727eba2d7cc", size = 107852, upload-time = "2026-03-01T22:05:04.986Z" }, + { url = "https://files.pythonhosted.org/packages/a4/b8/35c0750fcd5a3f781058bfd954515dd4b1eab45e218cbb85cf11132215f1/yarl-1.23.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:170e26584b060879e29fac213e4228ef063f39128723807a312e5c7fec28eff2", size = 102919, upload-time = "2026-03-01T22:05:06.397Z" }, + { url = "https://files.pythonhosted.org/packages/e5/1c/9a1979aec4a81896d597bcb2177827f2dbee3f5b7cc48b2d0dadb644b41d/yarl-1.23.0-cp311-cp311-win32.whl", hash = "sha256:51430653db848d258336cfa0244427b17d12db63d42603a55f0d4546f50f25b5", size = 82602, upload-time = "2026-03-01T22:05:08.444Z" }, + { url = "https://files.pythonhosted.org/packages/93/22/b85eca6fa2ad9491af48c973e4c8cf6b103a73dbb271fe3346949449fca0/yarl-1.23.0-cp311-cp311-win_amd64.whl", hash = "sha256:bf49a3ae946a87083ef3a34c8f677ae4243f5b824bfc4c69672e72b3d6719d46", size = 87461, upload-time = "2026-03-01T22:05:10.145Z" }, + { url = "https://files.pythonhosted.org/packages/93/95/07e3553fe6f113e6864a20bdc53a78113cda3b9ced8784ee52a52c9f80d8/yarl-1.23.0-cp311-cp311-win_arm64.whl", hash = "sha256:b39cb32a6582750b6cc77bfb3c49c0f8760dc18dc96ec9fb55fbb0f04e08b928", size = 82336, upload-time = "2026-03-01T22:05:11.554Z" }, + { url = "https://files.pythonhosted.org/packages/88/8a/94615bc31022f711add374097ad4144d569e95ff3c38d39215d07ac153a0/yarl-1.23.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1932b6b8bba8d0160a9d1078aae5838a66039e8832d41d2992daa9a3a08f7860", size = 124737, upload-time = "2026-03-01T22:05:12.897Z" }, + { url = "https://files.pythonhosted.org/packages/e3/6f/c6554045d59d64052698add01226bc867b52fe4a12373415d7991fdca95d/yarl-1.23.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:411225bae281f114067578891bc75534cfb3d92a3b4dfef7a6ca78ba354e6069", size = 87029, upload-time = "2026-03-01T22:05:14.376Z" }, + { url = "https://files.pythonhosted.org/packages/19/2a/725ecc166d53438bc88f76822ed4b1e3b10756e790bafd7b523fe97c322d/yarl-1.23.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:13a563739ae600a631c36ce096615fe307f131344588b0bc0daec108cdb47b25", size = 86310, upload-time = "2026-03-01T22:05:15.71Z" }, + { url = "https://files.pythonhosted.org/packages/99/30/58260ed98e6ff7f90ba84442c1ddd758c9170d70327394a6227b310cd60f/yarl-1.23.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9cbf44c5cb4a7633d078788e1b56387e3d3cf2b8139a3be38040b22d6c3221c8", size = 97587, upload-time = "2026-03-01T22:05:17.384Z" }, + { url = "https://files.pythonhosted.org/packages/76/0a/8b08aac08b50682e65759f7f8dde98ae8168f72487e7357a5d684c581ef9/yarl-1.23.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:53ad387048f6f09a8969631e4de3f1bf70c50e93545d64af4f751b2498755072", size = 92528, upload-time = "2026-03-01T22:05:18.804Z" }, + { url = "https://files.pythonhosted.org/packages/52/07/0b7179101fe5f8385ec6c6bb5d0cb9f76bd9fb4a769591ab6fb5cdbfc69a/yarl-1.23.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4a59ba56f340334766f3a4442e0efd0af895fae9e2b204741ef885c446b3a1a8", size = 105339, upload-time = "2026-03-01T22:05:20.235Z" }, + { url = "https://files.pythonhosted.org/packages/d3/8a/36d82869ab5ec829ca8574dfcb92b51286fcfb1e9c7a73659616362dc880/yarl-1.23.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:803a3c3ce4acc62eaf01eaca1208dcf0783025ef27572c3336502b9c232005e7", size = 105061, upload-time = "2026-03-01T22:05:22.268Z" }, + { url = "https://files.pythonhosted.org/packages/66/3e/868e5c3364b6cee19ff3e1a122194fa4ce51def02c61023970442162859e/yarl-1.23.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a3d2bff8f37f8d0f96c7ec554d16945050d54462d6e95414babaa18bfafc7f51", size = 100132, upload-time = "2026-03-01T22:05:23.638Z" }, + { url = "https://files.pythonhosted.org/packages/cf/26/9c89acf82f08a52cb52d6d39454f8d18af15f9d386a23795389d1d423823/yarl-1.23.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c75eb09e8d55bceb4367e83496ff8ef2bc7ea6960efb38e978e8073ea59ecb67", size = 99289, upload-time = "2026-03-01T22:05:25.749Z" }, + { url = "https://files.pythonhosted.org/packages/6f/54/5b0db00d2cb056922356104468019c0a132e89c8d3ab67d8ede9f4483d2a/yarl-1.23.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877b0738624280e34c55680d6054a307aa94f7d52fa0e3034a9cc6e790871da7", size = 96950, upload-time = "2026-03-01T22:05:27.318Z" }, + { url = "https://files.pythonhosted.org/packages/f6/40/10fa93811fd439341fad7e0718a86aca0de9548023bbb403668d6555acab/yarl-1.23.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b5405bb8f0e783a988172993cfc627e4d9d00432d6bbac65a923041edacf997d", size = 93960, upload-time = "2026-03-01T22:05:28.738Z" }, + { url = "https://files.pythonhosted.org/packages/bc/d2/8ae2e6cd77d0805f4526e30ec43b6f9a3dfc542d401ac4990d178e4bf0cf/yarl-1.23.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1c3a3598a832590c5a3ce56ab5576361b5688c12cb1d39429cf5dba30b510760", size = 104703, upload-time = "2026-03-01T22:05:30.438Z" }, + { url = "https://files.pythonhosted.org/packages/2f/0c/b3ceacf82c3fe21183ce35fa2acf5320af003d52bc1fcf5915077681142e/yarl-1.23.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:8419ebd326430d1cbb7efb5292330a2cf39114e82df5cc3d83c9a0d5ebeaf2f2", size = 98325, upload-time = "2026-03-01T22:05:31.835Z" }, + { url = "https://files.pythonhosted.org/packages/9d/e0/12900edd28bdab91a69bd2554b85ad7b151f64e8b521fe16f9ad2f56477a/yarl-1.23.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:be61f6fff406ca40e3b1d84716fde398fc08bc63dd96d15f3a14230a0973ed86", size = 105067, upload-time = "2026-03-01T22:05:33.358Z" }, + { url = "https://files.pythonhosted.org/packages/15/61/74bb1182cf79c9bbe4eb6b1f14a57a22d7a0be5e9cedf8e2d5c2086474c3/yarl-1.23.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ceb13c5c858d01321b5d9bb65e4cf37a92169ea470b70fec6f236b2c9dd7e34", size = 100285, upload-time = "2026-03-01T22:05:35.4Z" }, + { url = "https://files.pythonhosted.org/packages/69/7f/cd5ef733f2550de6241bd8bd8c3febc78158b9d75f197d9c7baa113436af/yarl-1.23.0-cp312-cp312-win32.whl", hash = "sha256:fffc45637bcd6538de8b85f51e3df3223e4ad89bccbfca0481c08c7fc8b7ed7d", size = 82359, upload-time = "2026-03-01T22:05:36.811Z" }, + { url = "https://files.pythonhosted.org/packages/f5/be/25216a49daeeb7af2bec0db22d5e7df08ed1d7c9f65d78b14f3b74fd72fc/yarl-1.23.0-cp312-cp312-win_amd64.whl", hash = "sha256:f69f57305656a4852f2a7203efc661d8c042e6cc67f7acd97d8667fb448a426e", size = 87674, upload-time = "2026-03-01T22:05:38.171Z" }, + { url = "https://files.pythonhosted.org/packages/d2/35/aeab955d6c425b227d5b7247eafb24f2653fedc32f95373a001af5dfeb9e/yarl-1.23.0-cp312-cp312-win_arm64.whl", hash = "sha256:6e87a6e8735b44816e7db0b2fbc9686932df473c826b0d9743148432e10bb9b9", size = 81879, upload-time = "2026-03-01T22:05:40.006Z" }, + { url = "https://files.pythonhosted.org/packages/9a/4b/a0a6e5d0ee8a2f3a373ddef8a4097d74ac901ac363eea1440464ccbe0898/yarl-1.23.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:16c6994ac35c3e74fb0ae93323bf8b9c2a9088d55946109489667c510a7d010e", size = 123796, upload-time = "2026-03-01T22:05:41.412Z" }, + { url = "https://files.pythonhosted.org/packages/67/b6/8925d68af039b835ae876db5838e82e76ec87b9782ecc97e192b809c4831/yarl-1.23.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4a42e651629dafb64fd5b0286a3580613702b5809ad3f24934ea87595804f2c5", size = 86547, upload-time = "2026-03-01T22:05:42.841Z" }, + { url = "https://files.pythonhosted.org/packages/ae/50/06d511cc4b8e0360d3c94af051a768e84b755c5eb031b12adaaab6dec6e5/yarl-1.23.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7c6b9461a2a8b47c65eef63bb1c76a4f1c119618ffa99ea79bc5bb1e46c5821b", size = 85854, upload-time = "2026-03-01T22:05:44.85Z" }, + { url = "https://files.pythonhosted.org/packages/c4/f4/4e30b250927ffdab4db70da08b9b8d2194d7c7b400167b8fbeca1e4701ca/yarl-1.23.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2569b67d616eab450d262ca7cb9f9e19d2f718c70a8b88712859359d0ab17035", size = 98351, upload-time = "2026-03-01T22:05:46.836Z" }, + { url = "https://files.pythonhosted.org/packages/86/fc/4118c5671ea948208bdb1492d8b76bdf1453d3e73df051f939f563e7dcc5/yarl-1.23.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e9d9a4d06d3481eab79803beb4d9bd6f6a8e781ec078ac70d7ef2dcc29d1bea5", size = 92711, upload-time = "2026-03-01T22:05:48.316Z" }, + { url = "https://files.pythonhosted.org/packages/56/11/1ed91d42bd9e73c13dc9e7eb0dd92298d75e7ac4dd7f046ad0c472e231cd/yarl-1.23.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f514f6474e04179d3d33175ed3f3e31434d3130d42ec153540d5b157deefd735", size = 106014, upload-time = "2026-03-01T22:05:50.028Z" }, + { url = "https://files.pythonhosted.org/packages/ce/c9/74e44e056a23fbc33aca71779ef450ca648a5bc472bdad7a82339918f818/yarl-1.23.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fda207c815b253e34f7e1909840fd14299567b1c0eb4908f8c2ce01a41265401", size = 105557, upload-time = "2026-03-01T22:05:51.416Z" }, + { url = "https://files.pythonhosted.org/packages/66/fe/b1e10b08d287f518994f1e2ff9b6d26f0adeecd8dd7d533b01bab29a3eda/yarl-1.23.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34b6cf500e61c90f305094911f9acc9c86da1a05a7a3f5be9f68817043f486e4", size = 101559, upload-time = "2026-03-01T22:05:52.872Z" }, + { url = "https://files.pythonhosted.org/packages/72/59/c5b8d94b14e3d3c2a9c20cb100119fd534ab5a14b93673ab4cc4a4141ea5/yarl-1.23.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d7504f2b476d21653e4d143f44a175f7f751cd41233525312696c76aa3dbb23f", size = 100502, upload-time = "2026-03-01T22:05:54.954Z" }, + { url = "https://files.pythonhosted.org/packages/77/4f/96976cb54cbfc5c9fd73ed4c51804f92f209481d1fb190981c0f8a07a1d7/yarl-1.23.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:578110dd426f0d209d1509244e6d4a3f1a3e9077655d98c5f22583d63252a08a", size = 98027, upload-time = "2026-03-01T22:05:56.409Z" }, + { url = "https://files.pythonhosted.org/packages/63/6e/904c4f476471afdbad6b7e5b70362fb5810e35cd7466529a97322b6f5556/yarl-1.23.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:609d3614d78d74ebe35f54953c5bbd2ac647a7ddb9c30a5d877580f5e86b22f2", size = 95369, upload-time = "2026-03-01T22:05:58.141Z" }, + { url = "https://files.pythonhosted.org/packages/9d/40/acfcdb3b5f9d68ef499e39e04d25e141fe90661f9d54114556cf83be8353/yarl-1.23.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4966242ec68afc74c122f8459abd597afd7d8a60dc93d695c1334c5fd25f762f", size = 105565, upload-time = "2026-03-01T22:06:00.286Z" }, + { url = "https://files.pythonhosted.org/packages/5e/c6/31e28f3a6ba2869c43d124f37ea5260cac9c9281df803c354b31f4dd1f3c/yarl-1.23.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:e0fd068364a6759bc794459f0a735ab151d11304346332489c7972bacbe9e72b", size = 99813, upload-time = "2026-03-01T22:06:01.712Z" }, + { url = "https://files.pythonhosted.org/packages/08/1f/6f65f59e72d54aa467119b63fc0b0b1762eff0232db1f4720cd89e2f4a17/yarl-1.23.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:39004f0ad156da43e86aa71f44e033de68a44e5a31fc53507b36dd253970054a", size = 105632, upload-time = "2026-03-01T22:06:03.188Z" }, + { url = "https://files.pythonhosted.org/packages/a3/c4/18b178a69935f9e7a338127d5b77d868fdc0f0e49becd286d51b3a18c61d/yarl-1.23.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e5723c01a56c5028c807c701aa66722916d2747ad737a046853f6c46f4875543", size = 101895, upload-time = "2026-03-01T22:06:04.651Z" }, + { url = "https://files.pythonhosted.org/packages/8f/54/f5b870b5505663911dba950a8e4776a0dbd51c9c54c0ae88e823e4b874a0/yarl-1.23.0-cp313-cp313-win32.whl", hash = "sha256:1b6b572edd95b4fa8df75de10b04bc81acc87c1c7d16bcdd2035b09d30acc957", size = 82356, upload-time = "2026-03-01T22:06:06.04Z" }, + { url = "https://files.pythonhosted.org/packages/7a/84/266e8da36879c6edcd37b02b547e2d9ecdfea776be49598e75696e3316e1/yarl-1.23.0-cp313-cp313-win_amd64.whl", hash = "sha256:baaf55442359053c7d62f6f8413a62adba3205119bcb6f49594894d8be47e5e3", size = 87515, upload-time = "2026-03-01T22:06:08.107Z" }, + { url = "https://files.pythonhosted.org/packages/00/fd/7e1c66efad35e1649114fa13f17485f62881ad58edeeb7f49f8c5e748bf9/yarl-1.23.0-cp313-cp313-win_arm64.whl", hash = "sha256:fb4948814a2a98e3912505f09c9e7493b1506226afb1f881825368d6fb776ee3", size = 81785, upload-time = "2026-03-01T22:06:10.181Z" }, + { url = "https://files.pythonhosted.org/packages/9c/fc/119dd07004f17ea43bb91e3ece6587759edd7519d6b086d16bfbd3319982/yarl-1.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:aecfed0b41aa72b7881712c65cf764e39ce2ec352324f5e0837c7048d9e6daaa", size = 130719, upload-time = "2026-03-01T22:06:11.708Z" }, + { url = "https://files.pythonhosted.org/packages/e6/0d/9f2348502fbb3af409e8f47730282cd6bc80dec6630c1e06374d882d6eb2/yarl-1.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a41bcf68efd19073376eb8cf948b8d9be0af26256403e512bb18f3966f1f9120", size = 89690, upload-time = "2026-03-01T22:06:13.429Z" }, + { url = "https://files.pythonhosted.org/packages/50/93/e88f3c80971b42cfc83f50a51b9d165a1dbf154b97005f2994a79f212a07/yarl-1.23.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:cde9a2ecd91668bcb7f077c4966d8ceddb60af01b52e6e3e2680e4cf00ad1a59", size = 89851, upload-time = "2026-03-01T22:06:15.53Z" }, + { url = "https://files.pythonhosted.org/packages/1c/07/61c9dd8ba8f86473263b4036f70fb594c09e99c0d9737a799dfd8bc85651/yarl-1.23.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5023346c4ee7992febc0068e7593de5fa2bf611848c08404b35ebbb76b1b0512", size = 95874, upload-time = "2026-03-01T22:06:17.553Z" }, + { url = "https://files.pythonhosted.org/packages/9e/e9/f9ff8ceefba599eac6abddcfb0b3bee9b9e636e96dbf54342a8577252379/yarl-1.23.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d1009abedb49ae95b136a8904a3f71b342f849ffeced2d3747bf29caeda218c4", size = 88710, upload-time = "2026-03-01T22:06:19.004Z" }, + { url = "https://files.pythonhosted.org/packages/eb/78/0231bfcc5d4c8eec220bc2f9ef82cb4566192ea867a7c5b4148f44f6cbcd/yarl-1.23.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a8d00f29b42f534cc8aa3931cfe773b13b23e561e10d2b26f27a8d309b0e82a1", size = 101033, upload-time = "2026-03-01T22:06:21.203Z" }, + { url = "https://files.pythonhosted.org/packages/cd/9b/30ea5239a61786f18fd25797151a17fbb3be176977187a48d541b5447dd4/yarl-1.23.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:95451e6ce06c3e104556d73b559f5da6c34a069b6b62946d3ad66afcd51642ea", size = 100817, upload-time = "2026-03-01T22:06:22.738Z" }, + { url = "https://files.pythonhosted.org/packages/62/e2/a4980481071791bc83bce2b7a1a1f7adcabfa366007518b4b845e92eeee3/yarl-1.23.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:531ef597132086b6cf96faa7c6c1dcd0361dd5f1694e5cc30375907b9b7d3ea9", size = 97482, upload-time = "2026-03-01T22:06:24.21Z" }, + { url = "https://files.pythonhosted.org/packages/e5/1e/304a00cf5f6100414c4b5a01fc7ff9ee724b62158a08df2f8170dfc72a2d/yarl-1.23.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:88f9fb0116fbfcefcab70f85cf4b74a2b6ce5d199c41345296f49d974ddb4123", size = 95949, upload-time = "2026-03-01T22:06:25.697Z" }, + { url = "https://files.pythonhosted.org/packages/68/03/093f4055ed4cae649ac53bca3d180bd37102e9e11d048588e9ab0c0108d0/yarl-1.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e7b0460976dc75cb87ad9cc1f9899a4b97751e7d4e77ab840fc9b6d377b8fd24", size = 95839, upload-time = "2026-03-01T22:06:27.309Z" }, + { url = "https://files.pythonhosted.org/packages/b9/28/4c75ebb108f322aa8f917ae10a8ffa4f07cae10a8a627b64e578617df6a0/yarl-1.23.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:115136c4a426f9da976187d238e84139ff6b51a20839aa6e3720cd1026d768de", size = 90696, upload-time = "2026-03-01T22:06:29.048Z" }, + { url = "https://files.pythonhosted.org/packages/23/9c/42c2e2dd91c1a570402f51bdf066bfdb1241c2240ba001967bad778e77b7/yarl-1.23.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:ead11956716a940c1abc816b7df3fa2b84d06eaed8832ca32f5c5e058c65506b", size = 100865, upload-time = "2026-03-01T22:06:30.525Z" }, + { url = "https://files.pythonhosted.org/packages/74/05/1bcd60a8a0a914d462c305137246b6f9d167628d73568505fce3f1cb2e65/yarl-1.23.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:fe8f8f5e70e6dbdfca9882cd9deaac058729bcf323cf7a58660901e55c9c94f6", size = 96234, upload-time = "2026-03-01T22:06:32.692Z" }, + { url = "https://files.pythonhosted.org/packages/90/b2/f52381aac396d6778ce516b7bc149c79e65bfc068b5de2857ab69eeea3b7/yarl-1.23.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:a0e317df055958a0c1e79e5d2aa5a5eaa4a6d05a20d4b0c9c3f48918139c9fc6", size = 100295, upload-time = "2026-03-01T22:06:34.268Z" }, + { url = "https://files.pythonhosted.org/packages/e5/e8/638bae5bbf1113a659b2435d8895474598afe38b4a837103764f603aba56/yarl-1.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f0fd84de0c957b2d280143522c4f91a73aada1923caee763e24a2b3fda9f8a5", size = 97784, upload-time = "2026-03-01T22:06:35.864Z" }, + { url = "https://files.pythonhosted.org/packages/80/25/a3892b46182c586c202629fc2159aa13975d3741d52ebd7347fd501d48d5/yarl-1.23.0-cp313-cp313t-win32.whl", hash = "sha256:93a784271881035ab4406a172edb0faecb6e7d00f4b53dc2f55919d6c9688595", size = 88313, upload-time = "2026-03-01T22:06:37.39Z" }, + { url = "https://files.pythonhosted.org/packages/43/68/8c5b36aa5178900b37387937bc2c2fe0e9505537f713495472dcf6f6fccc/yarl-1.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:dd00607bffbf30250fe108065f07453ec124dbf223420f57f5e749b04295e090", size = 94932, upload-time = "2026-03-01T22:06:39.579Z" }, + { url = "https://files.pythonhosted.org/packages/c6/cc/d79ba8292f51f81f4dc533a8ccfb9fc6992cabf0998ed3245de7589dc07c/yarl-1.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:ac09d42f48f80c9ee1635b2fcaa819496a44502737660d3c0f2ade7526d29144", size = 84786, upload-time = "2026-03-01T22:06:41.988Z" }, + { url = "https://files.pythonhosted.org/packages/90/98/b85a038d65d1b92c3903ab89444f48d3cee490a883477b716d7a24b1a78c/yarl-1.23.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:21d1b7305a71a15b4794b5ff22e8eef96ff4a6d7f9657155e5aa419444b28912", size = 124455, upload-time = "2026-03-01T22:06:43.615Z" }, + { url = "https://files.pythonhosted.org/packages/39/54/bc2b45559f86543d163b6e294417a107bb87557609007c007ad889afec18/yarl-1.23.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:85610b4f27f69984932a7abbe52703688de3724d9f72bceb1cca667deff27474", size = 86752, upload-time = "2026-03-01T22:06:45.425Z" }, + { url = "https://files.pythonhosted.org/packages/24/f9/e8242b68362bffe6fb536c8db5076861466fc780f0f1b479fc4ffbebb128/yarl-1.23.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:23f371bd662cf44a7630d4d113101eafc0cfa7518a2760d20760b26021454719", size = 86291, upload-time = "2026-03-01T22:06:46.974Z" }, + { url = "https://files.pythonhosted.org/packages/ea/d8/d1cb2378c81dd729e98c716582b1ccb08357e8488e4c24714658cc6630e8/yarl-1.23.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4a80f77dc1acaaa61f0934176fccca7096d9b1ff08c8ba9cddf5ae034a24319", size = 99026, upload-time = "2026-03-01T22:06:48.459Z" }, + { url = "https://files.pythonhosted.org/packages/0a/ff/7196790538f31debe3341283b5b0707e7feb947620fc5e8236ef28d44f72/yarl-1.23.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:bd654fad46d8d9e823afbb4f87c79160b5a374ed1ff5bde24e542e6ba8f41434", size = 92355, upload-time = "2026-03-01T22:06:50.306Z" }, + { url = "https://files.pythonhosted.org/packages/c1/56/25d58c3eddde825890a5fe6aa1866228377354a3c39262235234ab5f616b/yarl-1.23.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:682bae25f0a0dd23a056739f23a134db9f52a63e2afd6bfb37ddc76292bbd723", size = 106417, upload-time = "2026-03-01T22:06:52.1Z" }, + { url = "https://files.pythonhosted.org/packages/51/8a/882c0e7bc8277eb895b31bce0138f51a1ba551fc2e1ec6753ffc1e7c1377/yarl-1.23.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a82836cab5f197a0514235aaf7ffccdc886ccdaa2324bc0aafdd4ae898103039", size = 106422, upload-time = "2026-03-01T22:06:54.424Z" }, + { url = "https://files.pythonhosted.org/packages/42/2b/fef67d616931055bf3d6764885990a3ac647d68734a2d6a9e1d13de437a2/yarl-1.23.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c57676bdedc94cd3bc37724cf6f8cd2779f02f6aba48de45feca073e714fe52", size = 101915, upload-time = "2026-03-01T22:06:55.895Z" }, + { url = "https://files.pythonhosted.org/packages/18/6a/530e16aebce27c5937920f3431c628a29a4b6b430fab3fd1c117b26ff3f6/yarl-1.23.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c7f8dc16c498ff06497c015642333219871effba93e4a2e8604a06264aca5c5c", size = 100690, upload-time = "2026-03-01T22:06:58.21Z" }, + { url = "https://files.pythonhosted.org/packages/88/08/93749219179a45e27b036e03260fda05190b911de8e18225c294ac95bbc9/yarl-1.23.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:5ee586fb17ff8f90c91cf73c6108a434b02d69925f44f5f8e0d7f2f260607eae", size = 98750, upload-time = "2026-03-01T22:06:59.794Z" }, + { url = "https://files.pythonhosted.org/packages/d9/cf/ea424a004969f5d81a362110a6ac1496d79efdc6d50c2c4b2e3ea0fc2519/yarl-1.23.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:17235362f580149742739cc3828b80e24029d08cbb9c4bda0242c7b5bc610a8e", size = 94685, upload-time = "2026-03-01T22:07:01.375Z" }, + { url = "https://files.pythonhosted.org/packages/e2/b7/14341481fe568e2b0408bcf1484c652accafe06a0ade9387b5d3fd9df446/yarl-1.23.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:0793e2bd0cf14234983bbb371591e6bea9e876ddf6896cdcc93450996b0b5c85", size = 106009, upload-time = "2026-03-01T22:07:03.151Z" }, + { url = "https://files.pythonhosted.org/packages/0a/e6/5c744a9b54f4e8007ad35bce96fbc9218338e84812d36f3390cea616881a/yarl-1.23.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:3650dc2480f94f7116c364096bc84b1d602f44224ef7d5c7208425915c0475dd", size = 100033, upload-time = "2026-03-01T22:07:04.701Z" }, + { url = "https://files.pythonhosted.org/packages/0c/23/e3bfc188d0b400f025bc49d99793d02c9abe15752138dcc27e4eaf0c4a9e/yarl-1.23.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f40e782d49630ad384db66d4d8b73ff4f1b8955dc12e26b09a3e3af064b3b9d6", size = 106483, upload-time = "2026-03-01T22:07:06.231Z" }, + { url = "https://files.pythonhosted.org/packages/72/42/f0505f949a90b3f8b7a363d6cbdf398f6e6c58946d85c6d3a3bc70595b26/yarl-1.23.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:94f8575fbdf81749008d980c17796097e645574a3b8c28ee313931068dad14fe", size = 102175, upload-time = "2026-03-01T22:07:08.4Z" }, + { url = "https://files.pythonhosted.org/packages/aa/65/b39290f1d892a9dd671d1c722014ca062a9c35d60885d57e5375db0404b5/yarl-1.23.0-cp314-cp314-win32.whl", hash = "sha256:c8aa34a5c864db1087d911a0b902d60d203ea3607d91f615acd3f3108ac32169", size = 83871, upload-time = "2026-03-01T22:07:09.968Z" }, + { url = "https://files.pythonhosted.org/packages/a9/5b/9b92f54c784c26e2a422e55a8d2607ab15b7ea3349e28359282f84f01d43/yarl-1.23.0-cp314-cp314-win_amd64.whl", hash = "sha256:63e92247f383c85ab00dd0091e8c3fa331a96e865459f5ee80353c70a4a42d70", size = 89093, upload-time = "2026-03-01T22:07:11.501Z" }, + { url = "https://files.pythonhosted.org/packages/e0/7d/8a84dc9381fd4412d5e7ff04926f9865f6372b4c2fd91e10092e65d29eb8/yarl-1.23.0-cp314-cp314-win_arm64.whl", hash = "sha256:70efd20be968c76ece7baa8dafe04c5be06abc57f754d6f36f3741f7aa7a208e", size = 83384, upload-time = "2026-03-01T22:07:13.069Z" }, + { url = "https://files.pythonhosted.org/packages/dd/8d/d2fad34b1c08aa161b74394183daa7d800141aaaee207317e82c790b418d/yarl-1.23.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:9a18d6f9359e45722c064c97464ec883eb0e0366d33eda61cb19a244bf222679", size = 131019, upload-time = "2026-03-01T22:07:14.903Z" }, + { url = "https://files.pythonhosted.org/packages/19/ff/33009a39d3ccf4b94d7d7880dfe17fb5816c5a4fe0096d9b56abceea9ac7/yarl-1.23.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:2803ed8b21ca47a43da80a6fd1ed3019d30061f7061daa35ac54f63933409412", size = 89894, upload-time = "2026-03-01T22:07:17.372Z" }, + { url = "https://files.pythonhosted.org/packages/0c/f1/dab7ac5e7306fb79c0190766a3c00b4cb8d09a1f390ded68c85a5934faf5/yarl-1.23.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:394906945aa8b19fc14a61cf69743a868bb8c465efe85eee687109cc540b98f4", size = 89979, upload-time = "2026-03-01T22:07:19.361Z" }, + { url = "https://files.pythonhosted.org/packages/aa/b1/08e95f3caee1fad6e65017b9f26c1d79877b502622d60e517de01e72f95d/yarl-1.23.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:71d006bee8397a4a89f469b8deb22469fe7508132d3c17fa6ed871e79832691c", size = 95943, upload-time = "2026-03-01T22:07:21.266Z" }, + { url = "https://files.pythonhosted.org/packages/c0/cc/6409f9018864a6aa186c61175b977131f373f1988e198e031236916e87e4/yarl-1.23.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:62694e275c93d54f7ccedcfef57d42761b2aad5234b6be1f3e3026cae4001cd4", size = 88786, upload-time = "2026-03-01T22:07:23.129Z" }, + { url = "https://files.pythonhosted.org/packages/76/40/cc22d1d7714b717fde2006fad2ced5efe5580606cb059ae42117542122f3/yarl-1.23.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a31de1613658308efdb21ada98cbc86a97c181aa050ba22a808120bb5be3ab94", size = 101307, upload-time = "2026-03-01T22:07:24.689Z" }, + { url = "https://files.pythonhosted.org/packages/8f/0d/476c38e85ddb4c6ec6b20b815bdd779aa386a013f3d8b85516feee55c8dc/yarl-1.23.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fb1e8b8d66c278b21d13b0a7ca22c41dd757a7c209c6b12c313e445c31dd3b28", size = 100904, upload-time = "2026-03-01T22:07:26.287Z" }, + { url = "https://files.pythonhosted.org/packages/72/32/0abe4a76d59adf2081dcb0397168553ece4616ada1c54d1c49d8936c74f8/yarl-1.23.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50f9d8d531dfb767c565f348f33dd5139a6c43f5cbdf3f67da40d54241df93f6", size = 97728, upload-time = "2026-03-01T22:07:27.906Z" }, + { url = "https://files.pythonhosted.org/packages/b7/35/7b30f4810fba112f60f5a43237545867504e15b1c7647a785fbaf588fac2/yarl-1.23.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:575aa4405a656e61a540f4a80eaa5260f2a38fff7bfdc4b5f611840d76e9e277", size = 95964, upload-time = "2026-03-01T22:07:30.198Z" }, + { url = "https://files.pythonhosted.org/packages/2d/86/ed7a73ab85ef00e8bb70b0cb5421d8a2a625b81a333941a469a6f4022828/yarl-1.23.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:041b1a4cefacf65840b4e295c6985f334ba83c30607441ae3cf206a0eed1a2e4", size = 95882, upload-time = "2026-03-01T22:07:32.132Z" }, + { url = "https://files.pythonhosted.org/packages/19/90/d56967f61a29d8498efb7afb651e0b2b422a1e9b47b0ab5f4e40a19b699b/yarl-1.23.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:d38c1e8231722c4ce40d7593f28d92b5fc72f3e9774fe73d7e800ec32299f63a", size = 90797, upload-time = "2026-03-01T22:07:34.404Z" }, + { url = "https://files.pythonhosted.org/packages/72/00/8b8f76909259f56647adb1011d7ed8b321bcf97e464515c65016a47ecdf0/yarl-1.23.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:d53834e23c015ee83a99377db6e5e37d8484f333edb03bd15b4bc312cc7254fb", size = 101023, upload-time = "2026-03-01T22:07:35.953Z" }, + { url = "https://files.pythonhosted.org/packages/ac/e2/cab11b126fb7d440281b7df8e9ddbe4851e70a4dde47a202b6642586b8d9/yarl-1.23.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:2e27c8841126e017dd2a054a95771569e6070b9ee1b133366d8b31beb5018a41", size = 96227, upload-time = "2026-03-01T22:07:37.594Z" }, + { url = "https://files.pythonhosted.org/packages/c2/9b/2c893e16bfc50e6b2edf76c1a9eb6cb0c744346197e74c65e99ad8d634d0/yarl-1.23.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:76855800ac56f878847a09ce6dba727c93ca2d89c9e9d63002d26b916810b0a2", size = 100302, upload-time = "2026-03-01T22:07:39.334Z" }, + { url = "https://files.pythonhosted.org/packages/28/ec/5498c4e3a6d5f1003beb23405671c2eb9cdbf3067d1c80f15eeafe301010/yarl-1.23.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e09fd068c2e169a7070d83d3bde728a4d48de0549f975290be3c108c02e499b4", size = 98202, upload-time = "2026-03-01T22:07:41.717Z" }, + { url = "https://files.pythonhosted.org/packages/fe/c3/cd737e2d45e70717907f83e146f6949f20cc23cd4bf7b2688727763aa458/yarl-1.23.0-cp314-cp314t-win32.whl", hash = "sha256:73309162a6a571d4cbd3b6a1dcc703c7311843ae0d1578df6f09be4e98df38d4", size = 90558, upload-time = "2026-03-01T22:07:43.433Z" }, + { url = "https://files.pythonhosted.org/packages/e1/19/3774d162f6732d1cfb0b47b4140a942a35ca82bb19b6db1f80e9e7bdc8f8/yarl-1.23.0-cp314-cp314t-win_amd64.whl", hash = "sha256:4503053d296bc6e4cbd1fad61cf3b6e33b939886c4f249ba7c78b602214fabe2", size = 97610, upload-time = "2026-03-01T22:07:45.773Z" }, + { url = "https://files.pythonhosted.org/packages/51/47/3fa2286c3cb162c71cdb34c4224d5745a1ceceb391b2bd9b19b668a8d724/yarl-1.23.0-cp314-cp314t-win_arm64.whl", hash = "sha256:44bb7bef4ea409384e3f8bc36c063d77ea1b8d4a5b2706956c0d6695f07dcc25", size = 86041, upload-time = "2026-03-01T22:07:49.026Z" }, + { url = "https://files.pythonhosted.org/packages/69/68/c8739671f5699c7dc470580a4f821ef37c32c4cb0b047ce223a7f115757f/yarl-1.23.0-py3-none-any.whl", hash = "sha256:a2df6afe50dea8ae15fa34c9f824a3ee958d785fd5d089063d960bae1daa0a3f", size = 48288, upload-time = "2026-03-01T22:07:51.388Z" }, +] From 57311bf3e79c90f9e51a647efab1853364c1bfd3 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 30 Apr 2026 07:47:44 +0000 Subject: [PATCH 17/45] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 11365b78b41..0aa2e078043 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 2195 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a6c352830d1270d0abb5bb983058ea21815e1bb7d2e163965335dcb0e706f057.yml -openapi_spec_hash: ffe469d5b0b3f29c20ccb91c0a2862e7 +openapi_spec_hash: 93aa588f2a0a180eefe9654f56cd065b config_hash: a83bae9f0be0219cfe77d38d5af60d4a From 5cc95f1ee99c9ba0e4cf48ca14a4fdb34892c8a2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 30 Apr 2026 14:43:49 +0000 Subject: [PATCH 18/45] chore(api): update composite API spec --- .stats.yml | 2 +- src/cloudflare/resources/fraud/fraud.py | 20 ++++++ src/cloudflare/types/fraud/fraud_settings.py | 70 +++++++++++++++++- .../types/fraud/fraud_update_params.py | 71 ++++++++++++++++++- tests/api_resources/test_fraud.py | 20 ++++++ 5 files changed, 180 insertions(+), 3 deletions(-) diff --git a/.stats.yml b/.stats.yml index 0aa2e078043..73f917f5813 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 2195 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a6c352830d1270d0abb5bb983058ea21815e1bb7d2e163965335dcb0e706f057.yml -openapi_spec_hash: 93aa588f2a0a180eefe9654f56cd065b +openapi_spec_hash: a7e122c59429c7ec48c11144e6842390 config_hash: a83bae9f0be0219cfe77d38d5af60d4a diff --git a/src/cloudflare/resources/fraud/fraud.py b/src/cloudflare/resources/fraud/fraud.py index bdb431f9bc3..81e5efe5796 100644 --- a/src/cloudflare/resources/fraud/fraud.py +++ b/src/cloudflare/resources/fraud/fraud.py @@ -49,6 +49,7 @@ def update( self, *, zone_id: str, + authentication_settings: fraud_update_params.AuthenticationSettings | Omit = omit, user_profiles: Literal["enabled", "disabled"] | Omit = omit, username_expressions: SequenceNotStr[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -69,6 +70,14 @@ def update( Args: zone_id: Identifier. + authentication_settings: Configuration for classifying login authentication outcomes based on the origin + response. Requires `user_profiles` to be enabled. + + - Success and failure criteria are independently updatable — sending only + `success_criteria` leaves failure codes untouched, and vice versa. + - Omit `authentication_settings` entirely to leave both unchanged. + - Status codes must not overlap between success and failure criteria. + user_profiles: Whether Fraud User Profiles is enabled for the zone. username_expressions: List of expressions to detect usernames in write HTTP requests. @@ -93,6 +102,7 @@ def update( path_template("/zones/{zone_id}/fraud_detection/settings", zone_id=zone_id), body=maybe_transform( { + "authentication_settings": authentication_settings, "user_profiles": user_profiles, "username_expressions": username_expressions, }, @@ -172,6 +182,7 @@ async def update( self, *, zone_id: str, + authentication_settings: fraud_update_params.AuthenticationSettings | Omit = omit, user_profiles: Literal["enabled", "disabled"] | Omit = omit, username_expressions: SequenceNotStr[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -192,6 +203,14 @@ async def update( Args: zone_id: Identifier. + authentication_settings: Configuration for classifying login authentication outcomes based on the origin + response. Requires `user_profiles` to be enabled. + + - Success and failure criteria are independently updatable — sending only + `success_criteria` leaves failure codes untouched, and vice versa. + - Omit `authentication_settings` entirely to leave both unchanged. + - Status codes must not overlap between success and failure criteria. + user_profiles: Whether Fraud User Profiles is enabled for the zone. username_expressions: List of expressions to detect usernames in write HTTP requests. @@ -216,6 +235,7 @@ async def update( path_template("/zones/{zone_id}/fraud_detection/settings", zone_id=zone_id), body=await async_maybe_transform( { + "authentication_settings": authentication_settings, "user_profiles": user_profiles, "username_expressions": username_expressions, }, diff --git a/src/cloudflare/types/fraud/fraud_settings.py b/src/cloudflare/types/fraud/fraud_settings.py index cfd9506fe5c..7392a2b2313 100644 --- a/src/cloudflare/types/fraud/fraud_settings.py +++ b/src/cloudflare/types/fraud/fraud_settings.py @@ -5,10 +5,78 @@ from ..._models import BaseModel -__all__ = ["FraudSettings"] +__all__ = [ + "FraudSettings", + "AuthenticationSettings", + "AuthenticationSettingsFailureCriteria", + "AuthenticationSettingsSuccessCriteria", +] + + +class AuthenticationSettingsFailureCriteria(BaseModel): + """Criterion for identifying failed login responses.""" + + kind: Literal["status_code"] + """The type of criterion. Currently only `status_code` is supported.""" + + status_codes: Optional[List[int]] = None + """HTTP status codes to match against the origin response. + + - Maximum of 10 codes per criterion. + - Each code must be a valid HTTP status code (100-599). + - Codes are deduplicated and sorted on save. + - Omit to leave unchanged on update. + - Provide an empty array `[]` to clear codes on update. + """ + + +class AuthenticationSettingsSuccessCriteria(BaseModel): + """Criterion for identifying successful login responses.""" + + kind: Literal["status_code"] + """The type of criterion. Currently only `status_code` is supported.""" + + status_codes: Optional[List[int]] = None + """HTTP status codes to match against the origin response. + + - Maximum of 10 codes per criterion. + - Each code must be a valid HTTP status code (100-599). + - Codes are deduplicated and sorted on save. + - Omit to leave unchanged on update. + - Provide an empty array `[]` to clear codes on update. + """ + + +class AuthenticationSettings(BaseModel): + """ + Configuration for classifying login authentication outcomes based on the origin response. + Requires `user_profiles` to be enabled. + + - Success and failure criteria are independently updatable — sending only `success_criteria` + leaves failure codes untouched, and vice versa. + - Omit `authentication_settings` entirely to leave both unchanged. + - Status codes must not overlap between success and failure criteria. + """ + + failure_criteria: Optional[AuthenticationSettingsFailureCriteria] = None + """Criterion for identifying failed login responses.""" + + success_criteria: Optional[AuthenticationSettingsSuccessCriteria] = None + """Criterion for identifying successful login responses.""" class FraudSettings(BaseModel): + authentication_settings: Optional[AuthenticationSettings] = None + """ + Configuration for classifying login authentication outcomes based on the origin + response. Requires `user_profiles` to be enabled. + + - Success and failure criteria are independently updatable — sending only + `success_criteria` leaves failure codes untouched, and vice versa. + - Omit `authentication_settings` entirely to leave both unchanged. + - Status codes must not overlap between success and failure criteria. + """ + user_profiles: Optional[Literal["enabled", "disabled"]] = None """Whether Fraud User Profiles is enabled for the zone.""" diff --git a/src/cloudflare/types/fraud/fraud_update_params.py b/src/cloudflare/types/fraud/fraud_update_params.py index 78d59357e8c..4bb2a52b7d1 100644 --- a/src/cloudflare/types/fraud/fraud_update_params.py +++ b/src/cloudflare/types/fraud/fraud_update_params.py @@ -2,17 +2,34 @@ from __future__ import annotations +from typing import Iterable from typing_extensions import Literal, Required, TypedDict from ..._types import SequenceNotStr -__all__ = ["FraudUpdateParams"] +__all__ = [ + "FraudUpdateParams", + "AuthenticationSettings", + "AuthenticationSettingsFailureCriteria", + "AuthenticationSettingsSuccessCriteria", +] class FraudUpdateParams(TypedDict, total=False): zone_id: Required[str] """Identifier.""" + authentication_settings: AuthenticationSettings + """ + Configuration for classifying login authentication outcomes based on the origin + response. Requires `user_profiles` to be enabled. + + - Success and failure criteria are independently updatable — sending only + `success_criteria` leaves failure codes untouched, and vice versa. + - Omit `authentication_settings` entirely to leave both unchanged. + - Status codes must not overlap between success and failure criteria. + """ + user_profiles: Literal["enabled", "disabled"] """Whether Fraud User Profiles is enabled for the zone.""" @@ -25,3 +42,55 @@ class FraudUpdateParams(TypedDict, total=False): - Invalid expressions will result in a 10400 Bad Request with details in the `messages` array. """ + + +class AuthenticationSettingsFailureCriteria(TypedDict, total=False): + """Criterion for identifying failed login responses.""" + + kind: Required[Literal["status_code"]] + """The type of criterion. Currently only `status_code` is supported.""" + + status_codes: Iterable[int] + """HTTP status codes to match against the origin response. + + - Maximum of 10 codes per criterion. + - Each code must be a valid HTTP status code (100-599). + - Codes are deduplicated and sorted on save. + - Omit to leave unchanged on update. + - Provide an empty array `[]` to clear codes on update. + """ + + +class AuthenticationSettingsSuccessCriteria(TypedDict, total=False): + """Criterion for identifying successful login responses.""" + + kind: Required[Literal["status_code"]] + """The type of criterion. Currently only `status_code` is supported.""" + + status_codes: Iterable[int] + """HTTP status codes to match against the origin response. + + - Maximum of 10 codes per criterion. + - Each code must be a valid HTTP status code (100-599). + - Codes are deduplicated and sorted on save. + - Omit to leave unchanged on update. + - Provide an empty array `[]` to clear codes on update. + """ + + +class AuthenticationSettings(TypedDict, total=False): + """ + Configuration for classifying login authentication outcomes based on the origin response. + Requires `user_profiles` to be enabled. + + - Success and failure criteria are independently updatable — sending only `success_criteria` + leaves failure codes untouched, and vice versa. + - Omit `authentication_settings` entirely to leave both unchanged. + - Status codes must not overlap between success and failure criteria. + """ + + failure_criteria: AuthenticationSettingsFailureCriteria + """Criterion for identifying failed login responses.""" + + success_criteria: AuthenticationSettingsSuccessCriteria + """Criterion for identifying successful login responses.""" diff --git a/tests/api_resources/test_fraud.py b/tests/api_resources/test_fraud.py index 91984bef14c..7eb87e66fa4 100644 --- a/tests/api_resources/test_fraud.py +++ b/tests/api_resources/test_fraud.py @@ -28,6 +28,16 @@ def test_method_update(self, client: Cloudflare) -> None: def test_method_update_with_all_params(self, client: Cloudflare) -> None: fraud = client.fraud.update( zone_id="023e105f4ecef8ad9ca31a8372d0c353", + authentication_settings={ + "failure_criteria": { + "kind": "status_code", + "status_codes": [200, 201], + }, + "success_criteria": { + "kind": "status_code", + "status_codes": [200, 201], + }, + }, user_profiles="disabled", username_expressions=["string"], ) @@ -119,6 +129,16 @@ async def test_method_update(self, async_client: AsyncCloudflare) -> None: async def test_method_update_with_all_params(self, async_client: AsyncCloudflare) -> None: fraud = await async_client.fraud.update( zone_id="023e105f4ecef8ad9ca31a8372d0c353", + authentication_settings={ + "failure_criteria": { + "kind": "status_code", + "status_codes": [200, 201], + }, + "success_criteria": { + "kind": "status_code", + "status_codes": [200, 201], + }, + }, user_profiles="disabled", username_expressions=["string"], ) From 3ef3fff4e19a7029df92cb227c3e9040fd3e2dbc Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 30 Apr 2026 15:23:34 +0000 Subject: [PATCH 19/45] chore(api): update composite API spec --- .stats.yml | 2 +- .../types/aisearch/instance_create_params.py | 11 ---------- .../aisearch/instance_create_response.py | 11 ---------- .../aisearch/instance_delete_response.py | 11 ---------- .../types/aisearch/instance_list_response.py | 11 ---------- .../types/aisearch/instance_read_response.py | 11 ---------- .../types/aisearch/instance_update_params.py | 11 ---------- .../aisearch/instance_update_response.py | 11 ---------- .../namespaces/instance_create_params.py | 11 ---------- .../namespaces/instance_create_response.py | 11 ---------- .../namespaces/instance_delete_response.py | 11 ---------- .../namespaces/instance_list_response.py | 11 ---------- .../namespaces/instance_read_response.py | 11 ---------- .../namespaces/instance_update_params.py | 11 ---------- .../namespaces/instance_update_response.py | 11 ---------- .../aisearch/namespaces/test_instances.py | 20 ------------------- .../api_resources/aisearch/test_instances.py | 20 ------------------- 17 files changed, 1 insertion(+), 195 deletions(-) diff --git a/.stats.yml b/.stats.yml index 73f917f5813..3fa2675d2e7 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 2195 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a6c352830d1270d0abb5bb983058ea21815e1bb7d2e163965335dcb0e706f057.yml -openapi_spec_hash: a7e122c59429c7ec48c11144e6842390 +openapi_spec_hash: 11e5636b14b208096bae746c985af8aa config_hash: a83bae9f0be0219cfe77d38d5af60d4a diff --git a/src/cloudflare/types/aisearch/instance_create_params.py b/src/cloudflare/types/aisearch/instance_create_params.py index 74f3cef2703..23246fed684 100644 --- a/src/cloudflare/types/aisearch/instance_create_params.py +++ b/src/cloudflare/types/aisearch/instance_create_params.py @@ -15,7 +15,6 @@ "IndexMethod", "IndexingOptions", "Metadata", - "MetadataSearchForAgents", "PublicEndpointParams", "PublicEndpointParamsChatCompletionsEndpoint", "PublicEndpointParamsMcp", @@ -214,19 +213,9 @@ class IndexingOptions(TypedDict, total=False): """ -class MetadataSearchForAgents(TypedDict, total=False): - hostname: Required[str] - - zone_id: Required[str] - - zone_name: Required[str] - - class Metadata(TypedDict, total=False): created_from_aisearch_wizard: bool - search_for_agents: MetadataSearchForAgents - worker_domain: str diff --git a/src/cloudflare/types/aisearch/instance_create_response.py b/src/cloudflare/types/aisearch/instance_create_response.py index a1d955a3e36..9640f00c300 100644 --- a/src/cloudflare/types/aisearch/instance_create_response.py +++ b/src/cloudflare/types/aisearch/instance_create_response.py @@ -15,7 +15,6 @@ "IndexMethod", "IndexingOptions", "Metadata", - "MetadataSearchForAgents", "PublicEndpointParams", "PublicEndpointParamsChatCompletionsEndpoint", "PublicEndpointParamsMcp", @@ -62,19 +61,9 @@ class IndexingOptions(BaseModel): """ -class MetadataSearchForAgents(BaseModel): - hostname: str - - zone_id: str - - zone_name: str - - class Metadata(BaseModel): created_from_aisearch_wizard: Optional[bool] = None - search_for_agents: Optional[MetadataSearchForAgents] = None - worker_domain: Optional[str] = None diff --git a/src/cloudflare/types/aisearch/instance_delete_response.py b/src/cloudflare/types/aisearch/instance_delete_response.py index 2d8af06cb64..d58c218ba08 100644 --- a/src/cloudflare/types/aisearch/instance_delete_response.py +++ b/src/cloudflare/types/aisearch/instance_delete_response.py @@ -15,7 +15,6 @@ "IndexMethod", "IndexingOptions", "Metadata", - "MetadataSearchForAgents", "PublicEndpointParams", "PublicEndpointParamsChatCompletionsEndpoint", "PublicEndpointParamsMcp", @@ -62,19 +61,9 @@ class IndexingOptions(BaseModel): """ -class MetadataSearchForAgents(BaseModel): - hostname: str - - zone_id: str - - zone_name: str - - class Metadata(BaseModel): created_from_aisearch_wizard: Optional[bool] = None - search_for_agents: Optional[MetadataSearchForAgents] = None - worker_domain: Optional[str] = None diff --git a/src/cloudflare/types/aisearch/instance_list_response.py b/src/cloudflare/types/aisearch/instance_list_response.py index a18131f83ca..23678ce553e 100644 --- a/src/cloudflare/types/aisearch/instance_list_response.py +++ b/src/cloudflare/types/aisearch/instance_list_response.py @@ -15,7 +15,6 @@ "IndexMethod", "IndexingOptions", "Metadata", - "MetadataSearchForAgents", "PublicEndpointParams", "PublicEndpointParamsChatCompletionsEndpoint", "PublicEndpointParamsMcp", @@ -62,19 +61,9 @@ class IndexingOptions(BaseModel): """ -class MetadataSearchForAgents(BaseModel): - hostname: str - - zone_id: str - - zone_name: str - - class Metadata(BaseModel): created_from_aisearch_wizard: Optional[bool] = None - search_for_agents: Optional[MetadataSearchForAgents] = None - worker_domain: Optional[str] = None diff --git a/src/cloudflare/types/aisearch/instance_read_response.py b/src/cloudflare/types/aisearch/instance_read_response.py index f573f989aaa..45eaeae759e 100644 --- a/src/cloudflare/types/aisearch/instance_read_response.py +++ b/src/cloudflare/types/aisearch/instance_read_response.py @@ -15,7 +15,6 @@ "IndexMethod", "IndexingOptions", "Metadata", - "MetadataSearchForAgents", "PublicEndpointParams", "PublicEndpointParamsChatCompletionsEndpoint", "PublicEndpointParamsMcp", @@ -62,19 +61,9 @@ class IndexingOptions(BaseModel): """ -class MetadataSearchForAgents(BaseModel): - hostname: str - - zone_id: str - - zone_name: str - - class Metadata(BaseModel): created_from_aisearch_wizard: Optional[bool] = None - search_for_agents: Optional[MetadataSearchForAgents] = None - worker_domain: Optional[str] = None diff --git a/src/cloudflare/types/aisearch/instance_update_params.py b/src/cloudflare/types/aisearch/instance_update_params.py index efdbcbdf308..549194bf577 100644 --- a/src/cloudflare/types/aisearch/instance_update_params.py +++ b/src/cloudflare/types/aisearch/instance_update_params.py @@ -15,7 +15,6 @@ "IndexMethod", "IndexingOptions", "Metadata", - "MetadataSearchForAgents", "PublicEndpointParams", "PublicEndpointParamsChatCompletionsEndpoint", "PublicEndpointParamsMcp", @@ -249,19 +248,9 @@ class IndexingOptions(TypedDict, total=False): """ -class MetadataSearchForAgents(TypedDict, total=False): - hostname: Required[str] - - zone_id: Required[str] - - zone_name: Required[str] - - class Metadata(TypedDict, total=False): created_from_aisearch_wizard: bool - search_for_agents: MetadataSearchForAgents - worker_domain: str diff --git a/src/cloudflare/types/aisearch/instance_update_response.py b/src/cloudflare/types/aisearch/instance_update_response.py index ccbbe7cea67..5abc922e677 100644 --- a/src/cloudflare/types/aisearch/instance_update_response.py +++ b/src/cloudflare/types/aisearch/instance_update_response.py @@ -15,7 +15,6 @@ "IndexMethod", "IndexingOptions", "Metadata", - "MetadataSearchForAgents", "PublicEndpointParams", "PublicEndpointParamsChatCompletionsEndpoint", "PublicEndpointParamsMcp", @@ -62,19 +61,9 @@ class IndexingOptions(BaseModel): """ -class MetadataSearchForAgents(BaseModel): - hostname: str - - zone_id: str - - zone_name: str - - class Metadata(BaseModel): created_from_aisearch_wizard: Optional[bool] = None - search_for_agents: Optional[MetadataSearchForAgents] = None - worker_domain: Optional[str] = None diff --git a/src/cloudflare/types/aisearch/namespaces/instance_create_params.py b/src/cloudflare/types/aisearch/namespaces/instance_create_params.py index bf78a987478..d8f8a70a6cc 100644 --- a/src/cloudflare/types/aisearch/namespaces/instance_create_params.py +++ b/src/cloudflare/types/aisearch/namespaces/instance_create_params.py @@ -15,7 +15,6 @@ "IndexMethod", "IndexingOptions", "Metadata", - "MetadataSearchForAgents", "PublicEndpointParams", "PublicEndpointParamsChatCompletionsEndpoint", "PublicEndpointParamsMcp", @@ -214,19 +213,9 @@ class IndexingOptions(TypedDict, total=False): """ -class MetadataSearchForAgents(TypedDict, total=False): - hostname: Required[str] - - zone_id: Required[str] - - zone_name: Required[str] - - class Metadata(TypedDict, total=False): created_from_aisearch_wizard: bool - search_for_agents: MetadataSearchForAgents - worker_domain: str diff --git a/src/cloudflare/types/aisearch/namespaces/instance_create_response.py b/src/cloudflare/types/aisearch/namespaces/instance_create_response.py index e32256f511e..0dee72d00d8 100644 --- a/src/cloudflare/types/aisearch/namespaces/instance_create_response.py +++ b/src/cloudflare/types/aisearch/namespaces/instance_create_response.py @@ -15,7 +15,6 @@ "IndexMethod", "IndexingOptions", "Metadata", - "MetadataSearchForAgents", "PublicEndpointParams", "PublicEndpointParamsChatCompletionsEndpoint", "PublicEndpointParamsMcp", @@ -62,19 +61,9 @@ class IndexingOptions(BaseModel): """ -class MetadataSearchForAgents(BaseModel): - hostname: str - - zone_id: str - - zone_name: str - - class Metadata(BaseModel): created_from_aisearch_wizard: Optional[bool] = None - search_for_agents: Optional[MetadataSearchForAgents] = None - worker_domain: Optional[str] = None diff --git a/src/cloudflare/types/aisearch/namespaces/instance_delete_response.py b/src/cloudflare/types/aisearch/namespaces/instance_delete_response.py index 9854b1bf225..e870f6fc530 100644 --- a/src/cloudflare/types/aisearch/namespaces/instance_delete_response.py +++ b/src/cloudflare/types/aisearch/namespaces/instance_delete_response.py @@ -15,7 +15,6 @@ "IndexMethod", "IndexingOptions", "Metadata", - "MetadataSearchForAgents", "PublicEndpointParams", "PublicEndpointParamsChatCompletionsEndpoint", "PublicEndpointParamsMcp", @@ -62,19 +61,9 @@ class IndexingOptions(BaseModel): """ -class MetadataSearchForAgents(BaseModel): - hostname: str - - zone_id: str - - zone_name: str - - class Metadata(BaseModel): created_from_aisearch_wizard: Optional[bool] = None - search_for_agents: Optional[MetadataSearchForAgents] = None - worker_domain: Optional[str] = None diff --git a/src/cloudflare/types/aisearch/namespaces/instance_list_response.py b/src/cloudflare/types/aisearch/namespaces/instance_list_response.py index 0b285ba0e3e..fa59d4b6eaa 100644 --- a/src/cloudflare/types/aisearch/namespaces/instance_list_response.py +++ b/src/cloudflare/types/aisearch/namespaces/instance_list_response.py @@ -15,7 +15,6 @@ "IndexMethod", "IndexingOptions", "Metadata", - "MetadataSearchForAgents", "PublicEndpointParams", "PublicEndpointParamsChatCompletionsEndpoint", "PublicEndpointParamsMcp", @@ -62,19 +61,9 @@ class IndexingOptions(BaseModel): """ -class MetadataSearchForAgents(BaseModel): - hostname: str - - zone_id: str - - zone_name: str - - class Metadata(BaseModel): created_from_aisearch_wizard: Optional[bool] = None - search_for_agents: Optional[MetadataSearchForAgents] = None - worker_domain: Optional[str] = None diff --git a/src/cloudflare/types/aisearch/namespaces/instance_read_response.py b/src/cloudflare/types/aisearch/namespaces/instance_read_response.py index 0905449fb17..bf2763a2eeb 100644 --- a/src/cloudflare/types/aisearch/namespaces/instance_read_response.py +++ b/src/cloudflare/types/aisearch/namespaces/instance_read_response.py @@ -15,7 +15,6 @@ "IndexMethod", "IndexingOptions", "Metadata", - "MetadataSearchForAgents", "PublicEndpointParams", "PublicEndpointParamsChatCompletionsEndpoint", "PublicEndpointParamsMcp", @@ -62,19 +61,9 @@ class IndexingOptions(BaseModel): """ -class MetadataSearchForAgents(BaseModel): - hostname: str - - zone_id: str - - zone_name: str - - class Metadata(BaseModel): created_from_aisearch_wizard: Optional[bool] = None - search_for_agents: Optional[MetadataSearchForAgents] = None - worker_domain: Optional[str] = None diff --git a/src/cloudflare/types/aisearch/namespaces/instance_update_params.py b/src/cloudflare/types/aisearch/namespaces/instance_update_params.py index cfd6dd5675c..0834d5ab51c 100644 --- a/src/cloudflare/types/aisearch/namespaces/instance_update_params.py +++ b/src/cloudflare/types/aisearch/namespaces/instance_update_params.py @@ -15,7 +15,6 @@ "IndexMethod", "IndexingOptions", "Metadata", - "MetadataSearchForAgents", "PublicEndpointParams", "PublicEndpointParamsChatCompletionsEndpoint", "PublicEndpointParamsMcp", @@ -251,19 +250,9 @@ class IndexingOptions(TypedDict, total=False): """ -class MetadataSearchForAgents(TypedDict, total=False): - hostname: Required[str] - - zone_id: Required[str] - - zone_name: Required[str] - - class Metadata(TypedDict, total=False): created_from_aisearch_wizard: bool - search_for_agents: MetadataSearchForAgents - worker_domain: str diff --git a/src/cloudflare/types/aisearch/namespaces/instance_update_response.py b/src/cloudflare/types/aisearch/namespaces/instance_update_response.py index 0f4e80924d1..6410208a0d7 100644 --- a/src/cloudflare/types/aisearch/namespaces/instance_update_response.py +++ b/src/cloudflare/types/aisearch/namespaces/instance_update_response.py @@ -15,7 +15,6 @@ "IndexMethod", "IndexingOptions", "Metadata", - "MetadataSearchForAgents", "PublicEndpointParams", "PublicEndpointParamsChatCompletionsEndpoint", "PublicEndpointParamsMcp", @@ -62,19 +61,9 @@ class IndexingOptions(BaseModel): """ -class MetadataSearchForAgents(BaseModel): - hostname: str - - zone_id: str - - zone_name: str - - class Metadata(BaseModel): created_from_aisearch_wizard: Optional[bool] = None - search_for_agents: Optional[MetadataSearchForAgents] = None - worker_domain: Optional[str] = None diff --git a/tests/api_resources/aisearch/namespaces/test_instances.py b/tests/api_resources/aisearch/namespaces/test_instances.py index b9ef034cc9e..ceaff00d4be 100644 --- a/tests/api_resources/aisearch/namespaces/test_instances.py +++ b/tests/api_resources/aisearch/namespaces/test_instances.py @@ -66,11 +66,6 @@ def test_method_create_with_all_params(self, client: Cloudflare) -> None: max_num_results=1, metadata={ "created_from_aisearch_wizard": True, - "search_for_agents": { - "hostname": "hostname", - "zone_id": "zone_id", - "zone_name": "zone_name", - }, "worker_domain": "worker_domain", }, public_endpoint_params={ @@ -227,11 +222,6 @@ def test_method_update_with_all_params(self, client: Cloudflare) -> None: max_num_results=1, metadata={ "created_from_aisearch_wizard": True, - "search_for_agents": { - "hostname": "hostname", - "zone_id": "zone_id", - "zone_name": "zone_name", - }, "worker_domain": "worker_domain", }, paused=True, @@ -901,11 +891,6 @@ async def test_method_create_with_all_params(self, async_client: AsyncCloudflare max_num_results=1, metadata={ "created_from_aisearch_wizard": True, - "search_for_agents": { - "hostname": "hostname", - "zone_id": "zone_id", - "zone_name": "zone_name", - }, "worker_domain": "worker_domain", }, public_endpoint_params={ @@ -1062,11 +1047,6 @@ async def test_method_update_with_all_params(self, async_client: AsyncCloudflare max_num_results=1, metadata={ "created_from_aisearch_wizard": True, - "search_for_agents": { - "hostname": "hostname", - "zone_id": "zone_id", - "zone_name": "zone_name", - }, "worker_domain": "worker_domain", }, paused=True, diff --git a/tests/api_resources/aisearch/test_instances.py b/tests/api_resources/aisearch/test_instances.py index b80c7cb3ba2..033ed5e4825 100644 --- a/tests/api_resources/aisearch/test_instances.py +++ b/tests/api_resources/aisearch/test_instances.py @@ -64,11 +64,6 @@ def test_method_create_with_all_params(self, client: Cloudflare) -> None: max_num_results=1, metadata={ "created_from_aisearch_wizard": True, - "search_for_agents": { - "hostname": "hostname", - "zone_id": "zone_id", - "zone_name": "zone_name", - }, "worker_domain": "worker_domain", }, public_endpoint_params={ @@ -213,11 +208,6 @@ def test_method_update_with_all_params(self, client: Cloudflare) -> None: max_num_results=1, metadata={ "created_from_aisearch_wizard": True, - "search_for_agents": { - "hostname": "hostname", - "zone_id": "zone_id", - "zone_name": "zone_name", - }, "worker_domain": "worker_domain", }, paused=True, @@ -795,11 +785,6 @@ async def test_method_create_with_all_params(self, async_client: AsyncCloudflare max_num_results=1, metadata={ "created_from_aisearch_wizard": True, - "search_for_agents": { - "hostname": "hostname", - "zone_id": "zone_id", - "zone_name": "zone_name", - }, "worker_domain": "worker_domain", }, public_endpoint_params={ @@ -944,11 +929,6 @@ async def test_method_update_with_all_params(self, async_client: AsyncCloudflare max_num_results=1, metadata={ "created_from_aisearch_wizard": True, - "search_for_agents": { - "hostname": "hostname", - "zone_id": "zone_id", - "zone_name": "zone_name", - }, "worker_domain": "worker_domain", }, paused=True, From 40a47dc7afe163615766bc2d23495279b18e45bb Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 30 Apr 2026 15:59:58 +0000 Subject: [PATCH 20/45] feat: chore: skip fraud.update test (HTTP 422 from prism) * chore: skip fraud.update test (HTTP 422 from prism) Failure observed in CI run 25171503153 on cloudflare-typescript PR #2746. --- .stats.yml | 2 +- tests/api_resources/test_fraud.py | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 3fa2675d2e7..8dbc91005b1 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 2195 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a6c352830d1270d0abb5bb983058ea21815e1bb7d2e163965335dcb0e706f057.yml openapi_spec_hash: 11e5636b14b208096bae746c985af8aa -config_hash: a83bae9f0be0219cfe77d38d5af60d4a +config_hash: f1741f028aef186dc5f2be578a9b5b25 diff --git a/tests/api_resources/test_fraud.py b/tests/api_resources/test_fraud.py index 7eb87e66fa4..bd27a068ef6 100644 --- a/tests/api_resources/test_fraud.py +++ b/tests/api_resources/test_fraud.py @@ -17,6 +17,7 @@ class TestFraud: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize def test_method_update(self, client: Cloudflare) -> None: fraud = client.fraud.update( @@ -24,6 +25,7 @@ def test_method_update(self, client: Cloudflare) -> None: ) assert_matches_type(Optional[FraudSettings], fraud, path=["response"]) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize def test_method_update_with_all_params(self, client: Cloudflare) -> None: fraud = client.fraud.update( @@ -43,6 +45,7 @@ def test_method_update_with_all_params(self, client: Cloudflare) -> None: ) assert_matches_type(Optional[FraudSettings], fraud, path=["response"]) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize def test_raw_response_update(self, client: Cloudflare) -> None: response = client.fraud.with_raw_response.update( @@ -54,6 +57,7 @@ def test_raw_response_update(self, client: Cloudflare) -> None: fraud = response.parse() assert_matches_type(Optional[FraudSettings], fraud, path=["response"]) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize def test_streaming_response_update(self, client: Cloudflare) -> None: with client.fraud.with_streaming_response.update( @@ -67,6 +71,7 @@ def test_streaming_response_update(self, client: Cloudflare) -> None: assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize def test_path_params_update(self, client: Cloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `zone_id` but received ''"): @@ -118,6 +123,7 @@ class TestAsyncFraud: "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] ) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize async def test_method_update(self, async_client: AsyncCloudflare) -> None: fraud = await async_client.fraud.update( @@ -125,6 +131,7 @@ async def test_method_update(self, async_client: AsyncCloudflare) -> None: ) assert_matches_type(Optional[FraudSettings], fraud, path=["response"]) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize async def test_method_update_with_all_params(self, async_client: AsyncCloudflare) -> None: fraud = await async_client.fraud.update( @@ -144,6 +151,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncCloudflare ) assert_matches_type(Optional[FraudSettings], fraud, path=["response"]) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize async def test_raw_response_update(self, async_client: AsyncCloudflare) -> None: response = await async_client.fraud.with_raw_response.update( @@ -155,6 +163,7 @@ async def test_raw_response_update(self, async_client: AsyncCloudflare) -> None: fraud = await response.parse() assert_matches_type(Optional[FraudSettings], fraud, path=["response"]) + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize async def test_streaming_response_update(self, async_client: AsyncCloudflare) -> None: async with async_client.fraud.with_streaming_response.update( @@ -168,6 +177,7 @@ async def test_streaming_response_update(self, async_client: AsyncCloudflare) -> assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="HTTP 422 error from prism") @parametrize async def test_path_params_update(self, async_client: AsyncCloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `zone_id` but received ''"): From df2b7b8935e2edd7b1ba3caa3c94c658574b1a7a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 30 Apr 2026 16:06:09 +0000 Subject: [PATCH 21/45] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 8dbc91005b1..78f19a472fd 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 2195 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a6c352830d1270d0abb5bb983058ea21815e1bb7d2e163965335dcb0e706f057.yml -openapi_spec_hash: 11e5636b14b208096bae746c985af8aa +openapi_spec_hash: aa452e4dfaec546a7e50ef8665bd39f4 config_hash: f1741f028aef186dc5f2be578a9b5b25 From c4fe313dc94632ec05ba2d599d83b1cbec4e8792 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 30 Apr 2026 17:06:30 +0000 Subject: [PATCH 22/45] feat: feat(python): switch package manager from rye to uv * feat(python): switch package manager from rye to uv --- .devcontainer/Dockerfile | 3 +- .devcontainer/devcontainer.json | 4 +- .github/workflows/ci.yml | 55 +- .github/workflows/detect-breaking-changes.yml | 16 +- .github/workflows/publish-pypi.yml | 11 +- .stats.yml | 2 +- Brewfile | 2 +- CONTRIBUTING.md | 22 +- bin/publish-pypi | 5 +- noxfile.py | 9 - pyproject.toml | 52 +- requirements-dev.lock | 162 ++-- requirements.lock | 76 -- scripts/bootstrap | 11 +- scripts/format | 10 +- scripts/lint | 16 +- scripts/test | 31 +- uv.lock | 913 +++++++++++++++++- 18 files changed, 1064 insertions(+), 336 deletions(-) delete mode 100644 noxfile.py delete mode 100644 requirements.lock diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index ff261bad783..62c2d13f507 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -3,7 +3,6 @@ FROM mcr.microsoft.com/vscode/devcontainers/python:0-${VARIANT} USER vscode -RUN curl -sSf https://rye.astral.sh/get | RYE_VERSION="0.44.0" RYE_INSTALL_OPTION="--yes" bash -ENV PATH=/home/vscode/.rye/shims:$PATH +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ RUN echo "[[ -d .venv ]] && source .venv/bin/activate || export PATH=\$PATH" >> /home/vscode/.bashrc diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index c17fdc169fc..e01283d8ced 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -7,7 +7,7 @@ "context": ".." }, - "postStartCommand": "rye sync --all-features", + "postStartCommand": "uv sync --all-extras", "customizations": { "vscode": { @@ -20,7 +20,7 @@ "python.defaultInterpreterPath": ".venv/bin/python", "python.typeChecking": "basic", "terminal.integrated.env.linux": { - "PATH": "/home/vscode/.rye/shims:${env:PATH}" + "PATH": "${env:PATH}" } } } diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 830150bcdce..0794fd8d552 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,16 +28,13 @@ jobs: steps: - uses: actions/checkout@v6 - - name: Install Rye - run: | - curl -sSf https://rye.astral.sh/get | bash - echo "$HOME/.rye/shims" >> $GITHUB_PATH - env: - RYE_VERSION: '0.44.0' - RYE_INSTALL_OPTION: '--yes' + - name: Install uv + uses: astral-sh/setup-uv@v5 + with: + version: '0.10.2' - name: Install dependencies - run: rye sync --all-features + run: uv sync --all-extras - name: Run lints run: ./scripts/lint @@ -53,19 +50,16 @@ jobs: steps: - uses: actions/checkout@v6 - - name: Install Rye - run: | - curl -sSf https://rye.astral.sh/get | bash - echo "$HOME/.rye/shims" >> $GITHUB_PATH - env: - RYE_VERSION: '0.44.0' - RYE_INSTALL_OPTION: '--yes' + - name: Install uv + uses: astral-sh/setup-uv@v5 + with: + version: '0.10.2' - name: Install dependencies - run: rye sync --all-features + run: uv sync --all-extras - name: Run build - run: rye build + run: uv build - name: Get GitHub OIDC Token if: |- @@ -94,13 +88,10 @@ jobs: steps: - uses: actions/checkout@v6 - - name: Install Rye - run: | - curl -sSf https://rye.astral.sh/get | bash - echo "$HOME/.rye/shims" >> $GITHUB_PATH - env: - RYE_VERSION: '0.44.0' - RYE_INSTALL_OPTION: '--yes' + - name: Install uv + uses: astral-sh/setup-uv@v5 + with: + version: '0.10.2' - name: Bootstrap run: ./scripts/bootstrap @@ -117,16 +108,12 @@ jobs: steps: - uses: actions/checkout@v6 - - name: Install Rye - run: | - curl -sSf https://rye.astral.sh/get | bash - echo "$HOME/.rye/shims" >> $GITHUB_PATH - env: - RYE_VERSION: '0.44.0' - RYE_INSTALL_OPTION: '--yes' + - name: Install uv + uses: astral-sh/setup-uv@v5 + with: + version: '0.10.2' - name: Install dependencies - run: | - rye sync --all-features + run: uv sync --all-extras - env: CLOUDFLARE_ACCOUNT_ID: f037e56e89293a057740de681ac9abbe @@ -134,4 +121,4 @@ jobs: CLOUDFLARE_ZONE_ID: 0da42c8d2132a9ddaf714f9e7c920711 CLOUDFLARE_API_KEY: ${{ secrets.CLOUDFLARE_API_KEY }} run: | - rye run python ./examples/dns/record.py + uv run python ./examples/dns/record.py diff --git a/.github/workflows/detect-breaking-changes.yml b/.github/workflows/detect-breaking-changes.yml index b1ee63a0dd7..3a4894a9f32 100644 --- a/.github/workflows/detect-breaking-changes.yml +++ b/.github/workflows/detect-breaking-changes.yml @@ -22,19 +22,15 @@ jobs: # Ensure we can check out the pull request base in the script below. fetch-depth: ${{ env.FETCH_DEPTH }} - - name: Install Rye - run: | - curl -sSf https://rye.astral.sh/get | bash - echo "$HOME/.rye/shims" >> $GITHUB_PATH - env: - RYE_VERSION: '0.44.0' - RYE_INSTALL_OPTION: '--yes' + - name: Install uv + uses: astral-sh/setup-uv@v5 + with: + version: '0.10.2' - name: Install dependencies - run: | - rye sync --all-features + run: uv sync --all-extras - name: Detect removed symbols run: | - rye run python scripts/detect-breaking-changes.py "${{ github.event.pull_request.base.sha }}" + uv run python scripts/detect-breaking-changes.py "${{ github.event.pull_request.base.sha }}" - name: Detect breaking changes run: | diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml index b711a25bda7..5d3e356c4f2 100644 --- a/.github/workflows/publish-pypi.yml +++ b/.github/workflows/publish-pypi.yml @@ -16,13 +16,10 @@ jobs: steps: - uses: actions/checkout@v6 - - name: Install Rye - run: | - curl -sSf https://rye.astral.sh/get | bash - echo "$HOME/.rye/shims" >> $GITHUB_PATH - env: - RYE_VERSION: '0.44.0' - RYE_INSTALL_OPTION: '--yes' + - name: Install uv + uses: astral-sh/setup-uv@v5 + with: + version: '0.9.13' - name: Publish to PyPI run: | diff --git a/.stats.yml b/.stats.yml index 78f19a472fd..dfb0c0da36e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 2195 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a6c352830d1270d0abb5bb983058ea21815e1bb7d2e163965335dcb0e706f057.yml openapi_spec_hash: aa452e4dfaec546a7e50ef8665bd39f4 -config_hash: f1741f028aef186dc5f2be578a9b5b25 +config_hash: d3379006654eb5479a62d9576648acc5 diff --git a/Brewfile b/Brewfile index 492ca37bb07..c43041ceff9 100644 --- a/Brewfile +++ b/Brewfile @@ -1,2 +1,2 @@ -brew "rye" +brew "uv" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 320cdedd0ff..0392e10e0aa 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,32 +1,32 @@ ## Setting up the environment -### With Rye +### With `uv` -We use [Rye](https://rye.astral.sh/) to manage dependencies because it will automatically provision a Python environment with the expected Python version. To set it up, run: +We use [uv](https://docs.astral.sh/uv/) to manage dependencies because it will automatically provision a Python environment with the expected Python version. To set it up, run: ```sh $ ./scripts/bootstrap ``` -Or [install Rye manually](https://rye.astral.sh/guide/installation/) and run: +Or [install uv manually](https://docs.astral.sh/uv/getting-started/installation/) and run: ```sh -$ rye sync --all-features +$ uv sync --all-extras ``` -You can then run scripts using `rye run python script.py` or by activating the virtual environment: +You can then run scripts using `uv run python script.py` or by manually activating the virtual environment: ```sh -# Activate the virtual environment - https://docs.python.org/3/library/venv.html#how-venvs-work +# manually activate - https://docs.python.org/3/library/venv.html#how-venvs-work $ source .venv/bin/activate -# now you can omit the `rye run` prefix +# now you can omit the `uv run` prefix $ python script.py ``` -### Without Rye +### Without `uv` -Alternatively if you don't want to install `Rye`, you can stick with the standard `pip` setup by ensuring you have the Python version specified in `.python-version`, create a virtual environment however you desire and then install dependencies using this command: +Alternatively if you don't want to install `uv`, you can stick with the standard `pip` setup by ensuring you have the Python version specified in `.python-version`, create a virtual environment however you desire and then install dependencies using this command: ```sh $ pip install -r requirements-dev.lock @@ -45,7 +45,7 @@ All files in the `examples/` directory are not modified by the generator and can ```py # add an example to examples/.py -#!/usr/bin/env -S rye run python +#!/usr/bin/env -S uv run python … ``` @@ -72,7 +72,7 @@ Building this package will create two files in the `dist/` directory, a `.tar.gz To create a distributable version of the library, all you have to do is run this command: ```sh -$ rye build +$ uv build # or $ python -m build ``` diff --git a/bin/publish-pypi b/bin/publish-pypi index 826054e9248..e72ca2fa409 100644 --- a/bin/publish-pypi +++ b/bin/publish-pypi @@ -1,6 +1,7 @@ #!/usr/bin/env bash set -eux +rm -rf dist mkdir -p dist -rye build --clean -rye publish --yes --token=$PYPI_TOKEN +uv build +uv publish --token=$PYPI_TOKEN diff --git a/noxfile.py b/noxfile.py deleted file mode 100644 index 53bca7ff2aa..00000000000 --- a/noxfile.py +++ /dev/null @@ -1,9 +0,0 @@ -import nox - - -@nox.session(reuse_venv=True, name="test-pydantic-v1") -def test_pydantic_v1(session: nox.Session) -> None: - session.install("-r", "requirements-dev.lock") - session.install("pydantic<2") - - session.run("pytest", "--showlocals", "--ignore=tests/functional", *session.posargs) diff --git a/pyproject.toml b/pyproject.toml index e3ea96e58e4..a79b693633d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,10 +43,19 @@ Repository = "https://github.com/cloudflare/cloudflare-python" [project.optional-dependencies] aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.9"] -[tool.rye] +[tool.uv] managed = true -# version pins are in requirements-dev.lock -dev-dependencies = [ +required-version = ">=0.9" +conflicts = [ + [ + { group = "pydantic-v1" }, + { group = "pydantic-v2" }, + ], +] + +[dependency-groups] +# version pins are in uv.lock +dev = [ "pyright==1.1.399", "mypy==1.17", "respx", @@ -54,42 +63,19 @@ dev-dependencies = [ "pytest-asyncio", "ruff", "time-machine", - "nox", "dirty-equals>=0.6.0", "importlib-metadata>=6.7.0", "rich>=13.7.1", "pytest-xdist>=3.6.1", "griffe>=1", ] - -[tool.rye.scripts] -format = { chain = [ - "format:ruff", - "format:docs", - "fix:ruff", - # run formatting again to fix any inconsistencies when imports are stripped - "format:ruff", -]} -"format:docs" = "bash -c 'python scripts/utils/ruffen-docs.py README.md $(find . -type f -name api.md)'" -"format:ruff" = "ruff format" - -"lint" = { chain = [ - "check:ruff", - "typecheck", - "check:importable", -]} -"check:ruff" = "ruff check ." -"fix:ruff" = "ruff check --fix ." - -"check:importable" = "python -c 'import cloudflare'" - -typecheck = { chain = [ - "typecheck:pyright", - "typecheck:mypy" -]} -"typecheck:pyright" = "pyright" -"typecheck:verify-types" = "pyright --verifytypes cloudflare --ignoreexternal" -"typecheck:mypy" = "mypy ." +pydantic-v1 = [ + "pydantic>=1.9.0,<2", +] +pydantic-v2 = [ + "pydantic~=2.0 ; python_full_version < '3.14'", + "pydantic~=2.12 ; python_full_version >= '3.14'", +] [build-system] requires = ["hatchling==1.26.3", "hatch-fancy-pypi-readme"] diff --git a/requirements-dev.lock b/requirements-dev.lock index be86ad20d91..444b5b6e445 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -1,152 +1,114 @@ -# generated by rye -# use `rye lock` or `rye sync` to update this lockfile -# -# last locked with the following flags: -# pre: false -# features: [] -# all-features: true -# with-sources: false -# generate-hashes: false -# universal: false - --e file:. -aiohappyeyeballs==2.6.1 - # via aiohttp -aiohttp==3.13.3 - # via cloudflare - # via httpx-aiohttp -aiosignal==1.4.0 - # via aiohttp +# This file was autogenerated by uv via the following command: +# uv export -o requirements-dev.lock --no-hashes +-e . annotated-types==0.7.0 # via pydantic anyio==4.12.1 - # via cloudflare - # via httpx -argcomplete==3.6.3 - # via nox -async-timeout==5.0.1 - # via aiohttp -attrs==25.4.0 - # via aiohttp - # via nox -backports-asyncio-runner==1.2.0 + # via + # cloudflare + # httpx +backports-asyncio-runner==1.2.0 ; python_full_version < '3.11' # via pytest-asyncio certifi==2026.1.4 - # via httpcore - # via httpx + # via + # httpcore + # httpx colorama==0.4.6 - # via griffe -colorlog==6.10.1 - # via nox -dependency-groups==1.3.1 - # via nox + # via + # griffe + # pytest dirty-equals==0.11 -distlib==0.4.0 - # via virtualenv distro==1.9.0 # via cloudflare -exceptiongroup==1.3.1 - # via anyio - # via pytest +exceptiongroup==1.3.1 ; python_full_version < '3.11' + # via + # anyio + # pytest execnet==2.1.2 # via pytest-xdist -filelock==3.19.1 - # via virtualenv -frozenlist==1.8.0 - # via aiohttp - # via aiosignal -griffe==1.14.0 +griffe==1.14.0 ; python_full_version < '3.10' +griffe==1.15.0 ; python_full_version >= '3.10' h11==0.16.0 # via httpcore httpcore==1.0.9 # via httpx httpx==0.28.1 - # via cloudflare - # via httpx-aiohttp - # via respx -httpx-aiohttp==0.1.12 - # via cloudflare -humanize==4.13.0 - # via nox + # via + # cloudflare + # respx idna==3.11 - # via anyio - # via httpx - # via yarl + # via + # anyio + # httpx importlib-metadata==8.7.1 -iniconfig==2.1.0 +iniconfig==2.1.0 ; python_full_version < '3.10' # via pytest -markdown-it-py==3.0.0 +iniconfig==2.3.0 ; python_full_version >= '3.10' + # via pytest +markdown-it-py==3.0.0 ; python_full_version < '3.10' + # via rich +markdown-it-py==4.0.0 ; python_full_version >= '3.10' # via rich mdurl==0.1.2 # via markdown-it-py -multidict==6.7.0 - # via aiohttp - # via yarl mypy==1.17.0 mypy-extensions==1.1.0 # via mypy nodeenv==1.10.0 # via pyright -nox==2025.11.12 packaging==25.0 - # via dependency-groups - # via nox # via pytest pathspec==1.0.3 # via mypy -platformdirs==4.4.0 - # via virtualenv pluggy==1.6.0 # via pytest -propcache==0.4.1 - # via aiohttp - # via yarl pydantic==2.12.5 # via cloudflare pydantic-core==2.41.5 # via pydantic pygments==2.19.2 - # via pytest - # via rich + # via + # pytest + # rich pyright==1.1.399 -pytest==8.4.2 - # via pytest-asyncio - # via pytest-xdist -pytest-asyncio==1.2.0 +pytest==8.4.2 ; python_full_version < '3.10' + # via + # pytest-asyncio + # pytest-xdist +pytest==9.0.2 ; python_full_version >= '3.10' + # via + # pytest-asyncio + # pytest-xdist +pytest-asyncio==1.2.0 ; python_full_version < '3.10' +pytest-asyncio==1.3.0 ; python_full_version >= '3.10' pytest-xdist==3.8.0 -python-dateutil==2.9.0.post0 +python-dateutil==2.9.0.post0 ; python_full_version < '3.10' # via time-machine respx==0.22.0 rich==14.2.0 ruff==0.14.13 -six==1.17.0 +six==1.17.0 ; python_full_version < '3.10' # via python-dateutil sniffio==1.3.1 # via cloudflare -time-machine==2.19.0 -tomli==2.4.0 - # via dependency-groups - # via mypy - # via nox - # via pytest +time-machine==2.19.0 ; python_full_version < '3.10' +time-machine==3.2.0 ; python_full_version >= '3.10' +tomli==2.4.0 ; python_full_version < '3.11' + # via + # mypy + # pytest typing-extensions==4.15.0 - # via aiosignal - # via anyio - # via cloudflare - # via exceptiongroup - # via multidict - # via mypy - # via pydantic - # via pydantic-core - # via pyright - # via pytest-asyncio - # via typing-inspection - # via virtualenv + # via + # anyio + # cloudflare + # exceptiongroup + # mypy + # pydantic + # pydantic-core + # pyright + # pytest-asyncio + # typing-inspection typing-inspection==0.4.2 # via pydantic -virtualenv==20.36.1 - # via nox -yarl==1.22.0 - # via aiohttp zipp==3.23.0 # via importlib-metadata diff --git a/requirements.lock b/requirements.lock deleted file mode 100644 index 67880761fcb..00000000000 --- a/requirements.lock +++ /dev/null @@ -1,76 +0,0 @@ -# generated by rye -# use `rye lock` or `rye sync` to update this lockfile -# -# last locked with the following flags: -# pre: false -# features: [] -# all-features: true -# with-sources: false -# generate-hashes: false -# universal: false - --e file:. -aiohappyeyeballs==2.6.1 - # via aiohttp -aiohttp==3.13.3 - # via cloudflare - # via httpx-aiohttp -aiosignal==1.4.0 - # via aiohttp -annotated-types==0.7.0 - # via pydantic -anyio==4.12.1 - # via cloudflare - # via httpx -async-timeout==5.0.1 - # via aiohttp -attrs==25.4.0 - # via aiohttp -certifi==2026.1.4 - # via httpcore - # via httpx -distro==1.9.0 - # via cloudflare -exceptiongroup==1.3.1 - # via anyio -frozenlist==1.8.0 - # via aiohttp - # via aiosignal -h11==0.16.0 - # via httpcore -httpcore==1.0.9 - # via httpx -httpx==0.28.1 - # via cloudflare - # via httpx-aiohttp -httpx-aiohttp==0.1.12 - # via cloudflare -idna==3.11 - # via anyio - # via httpx - # via yarl -multidict==6.7.0 - # via aiohttp - # via yarl -propcache==0.4.1 - # via aiohttp - # via yarl -pydantic==2.12.5 - # via cloudflare -pydantic-core==2.41.5 - # via pydantic -sniffio==1.3.1 - # via cloudflare -typing-extensions==4.15.0 - # via aiosignal - # via anyio - # via cloudflare - # via exceptiongroup - # via multidict - # via pydantic - # via pydantic-core - # via typing-inspection -typing-inspection==0.4.2 - # via pydantic -yarl==1.22.0 - # via aiohttp diff --git a/scripts/bootstrap b/scripts/bootstrap index b430fee36d6..4638ec6943c 100755 --- a/scripts/bootstrap +++ b/scripts/bootstrap @@ -19,9 +19,12 @@ if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "$SKIP_BREW" != "1" ] } fi -echo "==> Installing Python dependencies…" +echo "==> Installing Python…" +uv python install -# experimental uv support makes installations significantly faster -rye config --set-bool behavior.use-uv=true +echo "==> Installing Python dependencies…" +uv sync --all-extras -rye sync --all-features +echo "==> Exporting Python dependencies…" +# note: `--no-hashes` is required because of https://github.com/pypa/pip/issues/4995 +uv export -o requirements-dev.lock --no-hashes diff --git a/scripts/format b/scripts/format index 667ec2d7af0..c8e1f69d252 100755 --- a/scripts/format +++ b/scripts/format @@ -4,5 +4,11 @@ set -e cd "$(dirname "$0")/.." -echo "==> Running formatters" -rye run format +echo "==> Running ruff" +uv run ruff format +uv run ruff check --fix . +# run formatting again to fix any inconsistencies when imports are stripped +uv run ruff format + +echo "==> Formatting docs" +uv run python scripts/utils/ruffen-docs.py README.md $(find . -type f -name api.md) diff --git a/scripts/lint b/scripts/lint index 3c726986511..1949ec0b8ef 100755 --- a/scripts/lint +++ b/scripts/lint @@ -5,12 +5,18 @@ set -e cd "$(dirname "$0")/.." if [ "$1" = "--fix" ]; then - echo "==> Running lints with --fix" - rye run fix:ruff + echo "==> Running ruff with --fix" + uv run ruff check . --fix else - echo "==> Running lints" - rye run lint + echo "==> Running ruff" + uv run ruff check . fi +echo "==> Running pyright" +uv run pyright + +echo "==> Running mypy" +uv run mypy . + echo "==> Making sure it imports" -rye run python -c 'import cloudflare' +uv run python -c 'import cloudflare' diff --git a/scripts/test b/scripts/test index dbeda2d2176..b56970b78e8 100755 --- a/scripts/test +++ b/scripts/test @@ -54,8 +54,31 @@ fi export DEFER_PYDANTIC_BUILD=false -echo "==> Running tests" -rye run pytest "$@" +# Note that we need to specify the patch version here so that uv +# won't use unstable (alpha, beta, rc) releases for the tests +PY_VERSION_MIN=">=3.9.0" +PY_VERSION_MAX=">=3.14.0" -echo "==> Running Pydantic v1 tests" -rye run nox -s test-pydantic-v1 -- "$@" +function run_tests() { + echo "==> Running tests with Pydantic v2" + uv run --isolated --all-extras pytest "$@" + + # Skip Pydantic v1 tests on latest Python (not supported) + if [[ "$UV_PYTHON" != "$PY_VERSION_MAX" ]]; then + echo "==> Running tests with Pydantic v1" + uv run --isolated --all-extras --group=pydantic-v1 pytest "$@" + fi +} + +# If UV_PYTHON is already set in the environment, just run the command once +if [[ -n "$UV_PYTHON" ]]; then + run_tests "$@" +else + # If UV_PYTHON is not set, run the command for min and max versions + + echo "==> Running tests for Python $PY_VERSION_MIN" + UV_PYTHON="$PY_VERSION_MIN" run_tests "$@" + + echo "==> Running tests for Python $PY_VERSION_MAX" + UV_PYTHON="$PY_VERSION_MAX" run_tests "$@" +fi diff --git a/uv.lock b/uv.lock index 7bd68eabf41..d9973e37a7d 100644 --- a/uv.lock +++ b/uv.lock @@ -2,9 +2,18 @@ version = 1 revision = 3 requires-python = ">=3.9" resolution-markers = [ - "python_full_version >= '3.10'", - "python_full_version < '3.10'", + "python_full_version >= '3.14' and extra != 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2'", + "python_full_version >= '3.10' and python_full_version < '3.14' and extra != 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2'", + "python_full_version < '3.10' and extra != 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2'", + "python_full_version >= '3.10' and extra == 'group-10-cloudflare-pydantic-v1' and extra != 'group-10-cloudflare-pydantic-v2'", + "python_full_version < '3.10' and extra == 'group-10-cloudflare-pydantic-v1' and extra != 'group-10-cloudflare-pydantic-v2'", + "python_full_version >= '3.10' and extra != 'group-10-cloudflare-pydantic-v1' and extra != 'group-10-cloudflare-pydantic-v2'", + "python_full_version < '3.10' and extra != 'group-10-cloudflare-pydantic-v1' and extra != 'group-10-cloudflare-pydantic-v2'", ] +conflicts = [[ + { package = "cloudflare", group = "pydantic-v1" }, + { package = "cloudflare", group = "pydantic-v2" }, +]] [[package]] name = "aiohappyeyeballs" @@ -22,13 +31,13 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohappyeyeballs" }, { name = "aiosignal" }, - { name = "async-timeout", marker = "python_full_version < '3.11'" }, + { name = "async-timeout", marker = "python_full_version < '3.11' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, { name = "attrs" }, { name = "frozenlist" }, { name = "multidict" }, { name = "propcache" }, - { name = "yarl", version = "1.22.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "yarl", version = "1.23.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "yarl", version = "1.22.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "yarl", version = "1.23.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/77/9a/152096d4808df8e4268befa55fba462f440f14beab85e8ad9bf990516918/aiohttp-3.13.5.tar.gz", hash = "sha256:9d98cc980ecc96be6eb4c1994ce35d28d8b1f5e5208a23b421187d1209dbb7d1", size = 7858271, upload-time = "2026-03-31T22:01:03.343Z" } wheels = [ @@ -159,7 +168,7 @@ version = "1.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "frozenlist" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, + { name = "typing-extensions", marker = "python_full_version < '3.13' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" } wheels = [ @@ -183,9 +192,9 @@ resolution-markers = [ "python_full_version < '3.10'", ] dependencies = [ - { name = "exceptiongroup", marker = "python_full_version < '3.10'" }, - { name = "idna", marker = "python_full_version < '3.10'" }, - { name = "typing-extensions", marker = "python_full_version < '3.10'" }, + { name = "exceptiongroup", marker = "python_full_version < '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "idna", marker = "python_full_version < '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "typing-extensions", marker = "python_full_version < '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/96/f0/5eb65b2bb0d09ac6776f2eb54adee6abe8228ea05b20a5ad0e4945de8aac/anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703", size = 228685, upload-time = "2026-01-06T11:45:21.246Z" } wheels = [ @@ -197,12 +206,15 @@ name = "anyio" version = "4.13.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.10'", + "python_full_version >= '3.14' and extra != 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2'", + "python_full_version >= '3.10' and python_full_version < '3.14' and extra != 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2'", + "python_full_version >= '3.10' and extra == 'group-10-cloudflare-pydantic-v1' and extra != 'group-10-cloudflare-pydantic-v2'", + "python_full_version >= '3.10' and extra != 'group-10-cloudflare-pydantic-v1' and extra != 'group-10-cloudflare-pydantic-v2'", ] dependencies = [ - { name = "exceptiongroup", marker = "python_full_version == '3.10.*'" }, - { name = "idna", marker = "python_full_version >= '3.10'" }, - { name = "typing-extensions", marker = "python_full_version >= '3.10' and python_full_version < '3.13'" }, + { name = "exceptiongroup", marker = "python_full_version == '3.10.*' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "idna", marker = "python_full_version >= '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "typing-extensions", marker = "(python_full_version >= '3.10' and python_full_version < '3.13') or (python_full_version < '3.10' and extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2') or (python_full_version >= '3.13' and extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/19/14/2c5dd9f512b66549ae92767a9c7b330ae88e1932ca57876909410251fe13/anyio-4.13.0.tar.gz", hash = "sha256:334b70e641fd2221c1505b3890c69882fe4a2df910cba14d97019b90b24439dc", size = 231622, upload-time = "2026-03-24T12:59:09.671Z" } wheels = [ @@ -227,6 +239,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", size = 67548, upload-time = "2026-03-19T14:22:23.645Z" }, ] +[[package]] +name = "backports-asyncio-runner" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8e/ff/70dca7d7cb1cbc0edb2c6cc0c38b65cba36cccc491eca64cabd5fe7f8670/backports_asyncio_runner-1.2.0.tar.gz", hash = "sha256:a5aa7b2b7d8f8bfcaa2b57313f70792df84e32a2a746f585213373f900b42162", size = 69893, upload-time = "2025-07-02T02:27:15.685Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl", hash = "sha256:0da0a936a8aeb554eccb426dc55af3ba63bcdc69fa1a600b5bb305413a4477b5", size = 12313, upload-time = "2025-07-02T02:27:14.263Z" }, +] + [[package]] name = "certifi" version = "2026.4.22" @@ -241,11 +262,12 @@ name = "cloudflare" version = "5.0.0b2" source = { editable = "." } dependencies = [ - { name = "anyio", version = "4.12.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "anyio", version = "4.13.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "anyio", version = "4.12.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "anyio", version = "4.13.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, { name = "distro" }, { name = "httpx" }, - { name = "pydantic" }, + { name = "pydantic", version = "1.10.26", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'group-10-cloudflare-pydantic-v1'" }, + { name = "pydantic", version = "2.13.3", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'group-10-cloudflare-pydantic-v2' or extra != 'group-10-cloudflare-pydantic-v1'" }, { name = "sniffio" }, { name = "typing-extensions" }, ] @@ -256,6 +278,33 @@ aiohttp = [ { name = "httpx-aiohttp" }, ] +[package.dev-dependencies] +dev = [ + { name = "dirty-equals" }, + { name = "griffe", version = "1.14.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "griffe", version = "2.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "importlib-metadata", version = "8.7.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "importlib-metadata", version = "9.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "mypy" }, + { name = "pyright" }, + { name = "pytest", version = "8.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "pytest", version = "9.0.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "pytest-asyncio", version = "1.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "pytest-asyncio", version = "1.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "pytest-xdist" }, + { name = "respx" }, + { name = "rich" }, + { name = "ruff" }, + { name = "time-machine", version = "2.19.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "time-machine", version = "3.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, +] +pydantic-v1 = [ + { name = "pydantic", version = "1.10.26", source = { registry = "https://pypi.org/simple" } }, +] +pydantic-v2 = [ + { name = "pydantic", version = "2.13.3", source = { registry = "https://pypi.org/simple" } }, +] + [package.metadata] requires-dist = [ { name = "aiohttp", marker = "extra == 'aiohttp'" }, @@ -269,6 +318,45 @@ requires-dist = [ ] provides-extras = ["aiohttp"] +[package.metadata.requires-dev] +dev = [ + { name = "dirty-equals", specifier = ">=0.6.0" }, + { name = "griffe", specifier = ">=1" }, + { name = "importlib-metadata", specifier = ">=6.7.0" }, + { name = "mypy", specifier = "==1.17" }, + { name = "pyright", specifier = "==1.1.399" }, + { name = "pytest" }, + { name = "pytest-asyncio" }, + { name = "pytest-xdist", specifier = ">=3.6.1" }, + { name = "respx" }, + { name = "rich", specifier = ">=13.7.1" }, + { name = "ruff" }, + { name = "time-machine" }, +] +pydantic-v1 = [{ name = "pydantic", specifier = ">=1.9.0,<2" }] +pydantic-v2 = [ + { name = "pydantic", marker = "python_full_version < '3.14'", specifier = "~=2.0" }, + { name = "pydantic", marker = "python_full_version >= '3.14'", specifier = "~=2.12" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "dirty-equals" +version = "0.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/30/1d/c5913ac9d6615515a00f4bdc71356d302437cb74ff2e9aaccd3c14493b78/dirty_equals-0.11.tar.gz", hash = "sha256:f4ac74ee88f2d11e2fa0f65eb30ee4f07105c5f86f4dc92b09eb1138775027c3", size = 128067, upload-time = "2025-11-17T01:51:24.451Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bb/8d/dbff05239043271dbeace563a7686212a3dd517864a35623fe4d4a64ca19/dirty_equals-0.11-py3-none-any.whl", hash = "sha256:b1d7093273fc2f9be12f443a8ead954ef6daaf6746fd42ef3a5616433ee85286", size = 28051, upload-time = "2025-11-17T01:51:22.849Z" }, +] + [[package]] name = "distro" version = "1.9.0" @@ -283,13 +371,22 @@ name = "exceptiongroup" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, + { name = "typing-extensions", marker = "python_full_version < '3.13' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, ] +[[package]] +name = "execnet" +version = "2.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bf/89/780e11f9588d9e7128a3f87788354c7946a9cbb1401ad38a48c4db9a4f07/execnet-2.1.2.tar.gz", hash = "sha256:63d83bfdd9a23e35b9c6a3261412324f964c2ec8dcd8d3c6916ee9373e0befcd", size = 166622, upload-time = "2025-11-12T09:56:37.75Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl", hash = "sha256:67fba928dd5a544b783f6056f449e5e3931a5c378b128bc18501f7ea79e296ec", size = 40708, upload-time = "2025-11-12T09:56:36.333Z" }, +] + [[package]] name = "frozenlist" version = "1.8.0" @@ -427,6 +524,62 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409, upload-time = "2025-10-06T05:38:16.721Z" }, ] +[[package]] +name = "griffe" +version = "1.14.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.10'", +] +dependencies = [ + { name = "colorama", marker = "python_full_version < '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ec/d7/6c09dd7ce4c7837e4cdb11dce980cb45ae3cd87677298dc3b781b6bce7d3/griffe-1.14.0.tar.gz", hash = "sha256:9d2a15c1eca966d68e00517de5d69dd1bc5c9f2335ef6c1775362ba5b8651a13", size = 424684, upload-time = "2025-09-05T15:02:29.167Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/b1/9ff6578d789a89812ff21e4e0f80ffae20a65d5dd84e7a17873fe3b365be/griffe-1.14.0-py3-none-any.whl", hash = "sha256:0e9d52832cccf0f7188cfe585ba962d2674b241c01916d780925df34873bceb0", size = 144439, upload-time = "2025-09-05T15:02:27.511Z" }, +] + +[[package]] +name = "griffe" +version = "2.0.2" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.14' and extra != 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2'", + "python_full_version >= '3.10' and python_full_version < '3.14' and extra != 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2'", + "python_full_version >= '3.10' and extra == 'group-10-cloudflare-pydantic-v1' and extra != 'group-10-cloudflare-pydantic-v2'", + "python_full_version >= '3.10' and extra != 'group-10-cloudflare-pydantic-v1' and extra != 'group-10-cloudflare-pydantic-v2'", +] +dependencies = [ + { name = "griffecli", marker = "python_full_version >= '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "griffelib", marker = "python_full_version >= '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4a/49/eb6d2935e27883af92c930ed40cc4c69bcd32c402be43b8ca4ab20510f67/griffe-2.0.2.tar.gz", hash = "sha256:c5d56326d159f274492e9bf93a9895cec101155d944caa66d0fc4e0c13751b92", size = 293757, upload-time = "2026-03-27T11:34:52.205Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/c0/2bb018eecf9a83c68db9cd9fffd9dab25f102ad30ed869451046e46d1187/griffe-2.0.2-py3-none-any.whl", hash = "sha256:2b31816460aee1996af26050a1fc6927a2e5936486856707f55508e4c9b5960b", size = 5141, upload-time = "2026-03-27T11:34:47.721Z" }, +] + +[[package]] +name = "griffecli" +version = "2.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "python_full_version >= '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "griffelib", marker = "python_full_version >= '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/79/e0/6a7d661d71bb043656a109b91d84a42b5342752542074ec83b16a6eb97f0/griffecli-2.0.2.tar.gz", hash = "sha256:40a1ad4181fc39685d025e119ae2c5b669acdc1f19b705fb9bf971f4e6f6dffb", size = 56281, upload-time = "2026-03-27T11:34:50.087Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2e/e8/90d93356c88ac34c20cb5edffca68138df55ca9bbd1a06eccfbcec8fdbe5/griffecli-2.0.2-py3-none-any.whl", hash = "sha256:0d44d39e59afa81e288a3e1c3bf352cc4fa537483326ac06b8bb6a51fd8303a0", size = 9500, upload-time = "2026-03-27T11:34:48.81Z" }, +] + +[[package]] +name = "griffelib" +version = "2.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9d/82/74f4a3310cdabfbb10da554c3a672847f1ed33c6f61dd472681ce7f1fe67/griffelib-2.0.2.tar.gz", hash = "sha256:3cf20b3bc470e83763ffbf236e0076b1211bac1bc67de13daf494640f2de707e", size = 166461, upload-time = "2026-03-27T11:34:51.091Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/8c/c9138d881c79aa0ea9ed83cbd58d5ca75624378b38cee225dcf5c42cc91f/griffelib-2.0.2-py3-none-any.whl", hash = "sha256:925c857658fb1ba40c0772c37acbc2ab650bd794d9c1b9726922e36ea4117ea1", size = 142357, upload-time = "2026-03-27T11:34:46.275Z" }, +] + [[package]] name = "h11" version = "0.16.0" @@ -454,8 +607,8 @@ name = "httpx" version = "0.28.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "anyio", version = "4.12.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "anyio", version = "4.13.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "anyio", version = "4.12.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "anyio", version = "4.13.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, { name = "certifi" }, { name = "httpcore" }, { name = "idna" }, @@ -487,12 +640,114 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5d/13/ad7d7ca3808a898b4612b6fe93cde56b53f3034dcde235acb1f0e1df24c6/idna-3.13-py3-none-any.whl", hash = "sha256:892ea0cde124a99ce773decba204c5552b69c3c67ffd5f232eb7696135bc8bb3", size = 68629, upload-time = "2026-04-22T16:42:40.909Z" }, ] +[[package]] +name = "importlib-metadata" +version = "8.7.1" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.10'", +] +dependencies = [ + { name = "zipp", marker = "python_full_version < '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f3/49/3b30cad09e7771a4982d9975a8cbf64f00d4a1ececb53297f1d9a7be1b10/importlib_metadata-8.7.1.tar.gz", hash = "sha256:49fef1ae6440c182052f407c8d34a68f72efc36db9ca90dc0113398f2fdde8bb", size = 57107, upload-time = "2025-12-21T10:00:19.278Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl", hash = "sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151", size = 27865, upload-time = "2025-12-21T10:00:18.329Z" }, +] + +[[package]] +name = "importlib-metadata" +version = "9.0.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.14' and extra != 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2'", + "python_full_version >= '3.10' and python_full_version < '3.14' and extra != 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2'", + "python_full_version >= '3.10' and extra == 'group-10-cloudflare-pydantic-v1' and extra != 'group-10-cloudflare-pydantic-v2'", + "python_full_version >= '3.10' and extra != 'group-10-cloudflare-pydantic-v1' and extra != 'group-10-cloudflare-pydantic-v2'", +] +dependencies = [ + { name = "zipp", marker = "python_full_version >= '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a9/01/15bb152d77b21318514a96f43af312635eb2500c96b55398d020c93d86ea/importlib_metadata-9.0.0.tar.gz", hash = "sha256:a4f57ab599e6a2e3016d7595cfd72eb4661a5106e787a95bcc90c7105b831efc", size = 56405, upload-time = "2026-03-20T06:42:56.999Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/3d/2d244233ac4f76e38533cfcb2991c9eb4c7bf688ae0a036d30725b8faafe/importlib_metadata-9.0.0-py3-none-any.whl", hash = "sha256:2d21d1cc5a017bd0559e36150c21c830ab1dc304dedd1b7ea85d20f45ef3edd7", size = 27789, upload-time = "2026-03-20T06:42:55.665Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.10'", +] +sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.14' and extra != 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2'", + "python_full_version >= '3.10' and python_full_version < '3.14' and extra != 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2'", + "python_full_version >= '3.10' and extra == 'group-10-cloudflare-pydantic-v1' and extra != 'group-10-cloudflare-pydantic-v2'", + "python_full_version >= '3.10' and extra != 'group-10-cloudflare-pydantic-v1' and extra != 'group-10-cloudflare-pydantic-v2'", +] +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + +[[package]] +name = "markdown-it-py" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.10'", +] +dependencies = [ + { name = "mdurl", marker = "python_full_version < '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" }, +] + +[[package]] +name = "markdown-it-py" +version = "4.0.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.14' and extra != 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2'", + "python_full_version >= '3.10' and python_full_version < '3.14' and extra != 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2'", + "python_full_version >= '3.10' and extra == 'group-10-cloudflare-pydantic-v1' and extra != 'group-10-cloudflare-pydantic-v2'", + "python_full_version >= '3.10' and extra != 'group-10-cloudflare-pydantic-v1' and extra != 'group-10-cloudflare-pydantic-v2'", +] +dependencies = [ + { name = "mdurl", marker = "python_full_version >= '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, +] + [[package]] name = "multidict" version = "6.7.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions", marker = "python_full_version < '3.11' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/1a/c2/c2d94cbe6ac1753f3fc980da97b3d930efe1da3af3c9f5125354436c073d/multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d", size = 102010, upload-time = "2026-01-26T02:46:45.979Z" } wheels = [ @@ -643,6 +898,96 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/81/08/7036c080d7117f28a4af526d794aab6a84463126db031b007717c1a6676e/multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56", size = 12319, upload-time = "2026-01-26T02:46:44.004Z" }, ] +[[package]] +name = "mypy" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mypy-extensions" }, + { name = "pathspec" }, + { name = "tomli", marker = "python_full_version < '3.11' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1e/e3/034322d5a779685218ed69286c32faa505247f1f096251ef66c8fd203b08/mypy-1.17.0.tar.gz", hash = "sha256:e5d7ccc08ba089c06e2f5629c660388ef1fee708444f1dee0b9203fa031dee03", size = 3352114, upload-time = "2025-07-14T20:34:30.181Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/31/e762baa3b73905c856d45ab77b4af850e8159dffffd86a52879539a08c6b/mypy-1.17.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f8e08de6138043108b3b18f09d3f817a4783912e48828ab397ecf183135d84d6", size = 10998313, upload-time = "2025-07-14T20:33:24.519Z" }, + { url = "https://files.pythonhosted.org/packages/1c/c1/25b2f0d46fb7e0b5e2bee61ec3a47fe13eff9e3c2f2234f144858bbe6485/mypy-1.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ce4a17920ec144647d448fc43725b5873548b1aae6c603225626747ededf582d", size = 10128922, upload-time = "2025-07-14T20:34:06.414Z" }, + { url = "https://files.pythonhosted.org/packages/02/78/6d646603a57aa8a2886df1b8881fe777ea60f28098790c1089230cd9c61d/mypy-1.17.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6ff25d151cc057fdddb1cb1881ef36e9c41fa2a5e78d8dd71bee6e4dcd2bc05b", size = 11913524, upload-time = "2025-07-14T20:33:19.109Z" }, + { url = "https://files.pythonhosted.org/packages/4f/19/dae6c55e87ee426fb76980f7e78484450cad1c01c55a1dc4e91c930bea01/mypy-1.17.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93468cf29aa9a132bceb103bd8475f78cacde2b1b9a94fd978d50d4bdf616c9a", size = 12650527, upload-time = "2025-07-14T20:32:44.095Z" }, + { url = "https://files.pythonhosted.org/packages/86/e1/f916845a235235a6c1e4d4d065a3930113767001d491b8b2e1b61ca56647/mypy-1.17.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:98189382b310f16343151f65dd7e6867386d3e35f7878c45cfa11383d175d91f", size = 12897284, upload-time = "2025-07-14T20:33:38.168Z" }, + { url = "https://files.pythonhosted.org/packages/ae/dc/414760708a4ea1b096bd214d26a24e30ac5e917ef293bc33cdb6fe22d2da/mypy-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:c004135a300ab06a045c1c0d8e3f10215e71d7b4f5bb9a42ab80236364429937", size = 9506493, upload-time = "2025-07-14T20:34:01.093Z" }, + { url = "https://files.pythonhosted.org/packages/d4/24/82efb502b0b0f661c49aa21cfe3e1999ddf64bf5500fc03b5a1536a39d39/mypy-1.17.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9d4fe5c72fd262d9c2c91c1117d16aac555e05f5beb2bae6a755274c6eec42be", size = 10914150, upload-time = "2025-07-14T20:31:51.985Z" }, + { url = "https://files.pythonhosted.org/packages/03/96/8ef9a6ff8cedadff4400e2254689ca1dc4b420b92c55255b44573de10c54/mypy-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d96b196e5c16f41b4f7736840e8455958e832871990c7ba26bf58175e357ed61", size = 10039845, upload-time = "2025-07-14T20:32:30.527Z" }, + { url = "https://files.pythonhosted.org/packages/df/32/7ce359a56be779d38021d07941cfbb099b41411d72d827230a36203dbb81/mypy-1.17.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:73a0ff2dd10337ceb521c080d4147755ee302dcde6e1a913babd59473904615f", size = 11837246, upload-time = "2025-07-14T20:32:01.28Z" }, + { url = "https://files.pythonhosted.org/packages/82/16/b775047054de4d8dbd668df9137707e54b07fe18c7923839cd1e524bf756/mypy-1.17.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:24cfcc1179c4447854e9e406d3af0f77736d631ec87d31c6281ecd5025df625d", size = 12571106, upload-time = "2025-07-14T20:34:26.942Z" }, + { url = "https://files.pythonhosted.org/packages/a1/cf/fa33eaf29a606102c8d9ffa45a386a04c2203d9ad18bf4eef3e20c43ebc8/mypy-1.17.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3c56f180ff6430e6373db7a1d569317675b0a451caf5fef6ce4ab365f5f2f6c3", size = 12759960, upload-time = "2025-07-14T20:33:42.882Z" }, + { url = "https://files.pythonhosted.org/packages/94/75/3f5a29209f27e739ca57e6350bc6b783a38c7621bdf9cac3ab8a08665801/mypy-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:eafaf8b9252734400f9b77df98b4eee3d2eecab16104680d51341c75702cad70", size = 9503888, upload-time = "2025-07-14T20:32:34.392Z" }, + { url = "https://files.pythonhosted.org/packages/12/e9/e6824ed620bbf51d3bf4d6cbbe4953e83eaf31a448d1b3cfb3620ccb641c/mypy-1.17.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f986f1cab8dbec39ba6e0eaa42d4d3ac6686516a5d3dccd64be095db05ebc6bb", size = 11086395, upload-time = "2025-07-14T20:34:11.452Z" }, + { url = "https://files.pythonhosted.org/packages/ba/51/a4afd1ae279707953be175d303f04a5a7bd7e28dc62463ad29c1c857927e/mypy-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:51e455a54d199dd6e931cd7ea987d061c2afbaf0960f7f66deef47c90d1b304d", size = 10120052, upload-time = "2025-07-14T20:33:09.897Z" }, + { url = "https://files.pythonhosted.org/packages/8a/71/19adfeac926ba8205f1d1466d0d360d07b46486bf64360c54cb5a2bd86a8/mypy-1.17.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3204d773bab5ff4ebbd1f8efa11b498027cd57017c003ae970f310e5b96be8d8", size = 11861806, upload-time = "2025-07-14T20:32:16.028Z" }, + { url = "https://files.pythonhosted.org/packages/0b/64/d6120eca3835baf7179e6797a0b61d6c47e0bc2324b1f6819d8428d5b9ba/mypy-1.17.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1051df7ec0886fa246a530ae917c473491e9a0ba6938cfd0ec2abc1076495c3e", size = 12744371, upload-time = "2025-07-14T20:33:33.503Z" }, + { url = "https://files.pythonhosted.org/packages/1f/dc/56f53b5255a166f5bd0f137eed960e5065f2744509dfe69474ff0ba772a5/mypy-1.17.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f773c6d14dcc108a5b141b4456b0871df638eb411a89cd1c0c001fc4a9d08fc8", size = 12914558, upload-time = "2025-07-14T20:33:56.961Z" }, + { url = "https://files.pythonhosted.org/packages/69/ac/070bad311171badc9add2910e7f89271695a25c136de24bbafc7eded56d5/mypy-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:1619a485fd0e9c959b943c7b519ed26b712de3002d7de43154a489a2d0fd817d", size = 9585447, upload-time = "2025-07-14T20:32:20.594Z" }, + { url = "https://files.pythonhosted.org/packages/be/7b/5f8ab461369b9e62157072156935cec9d272196556bdc7c2ff5f4c7c0f9b/mypy-1.17.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2c41aa59211e49d717d92b3bb1238c06d387c9325d3122085113c79118bebb06", size = 11070019, upload-time = "2025-07-14T20:32:07.99Z" }, + { url = "https://files.pythonhosted.org/packages/9c/f8/c49c9e5a2ac0badcc54beb24e774d2499748302c9568f7f09e8730e953fa/mypy-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0e69db1fb65b3114f98c753e3930a00514f5b68794ba80590eb02090d54a5d4a", size = 10114457, upload-time = "2025-07-14T20:33:47.285Z" }, + { url = "https://files.pythonhosted.org/packages/89/0c/fb3f9c939ad9beed3e328008b3fb90b20fda2cddc0f7e4c20dbefefc3b33/mypy-1.17.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:03ba330b76710f83d6ac500053f7727270b6b8553b0423348ffb3af6f2f7b889", size = 11857838, upload-time = "2025-07-14T20:33:14.462Z" }, + { url = "https://files.pythonhosted.org/packages/4c/66/85607ab5137d65e4f54d9797b77d5a038ef34f714929cf8ad30b03f628df/mypy-1.17.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:037bc0f0b124ce46bfde955c647f3e395c6174476a968c0f22c95a8d2f589bba", size = 12731358, upload-time = "2025-07-14T20:32:25.579Z" }, + { url = "https://files.pythonhosted.org/packages/73/d0/341dbbfb35ce53d01f8f2969facbb66486cee9804048bf6c01b048127501/mypy-1.17.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c38876106cb6132259683632b287238858bd58de267d80defb6f418e9ee50658", size = 12917480, upload-time = "2025-07-14T20:34:21.868Z" }, + { url = "https://files.pythonhosted.org/packages/64/63/70c8b7dbfc520089ac48d01367a97e8acd734f65bd07813081f508a8c94c/mypy-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:d30ba01c0f151998f367506fab31c2ac4527e6a7b2690107c7a7f9e3cb419a9c", size = 9589666, upload-time = "2025-07-14T20:34:16.841Z" }, + { url = "https://files.pythonhosted.org/packages/9f/a0/6263dd11941231f688f0a8f2faf90ceac1dc243d148d314a089d2fe25108/mypy-1.17.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:63e751f1b5ab51d6f3d219fe3a2fe4523eaa387d854ad06906c63883fde5b1ab", size = 10988185, upload-time = "2025-07-14T20:33:04.797Z" }, + { url = "https://files.pythonhosted.org/packages/02/13/b8f16d6b0dc80277129559c8e7dbc9011241a0da8f60d031edb0e6e9ac8f/mypy-1.17.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f7fb09d05e0f1c329a36dcd30e27564a3555717cde87301fae4fb542402ddfad", size = 10120169, upload-time = "2025-07-14T20:32:38.84Z" }, + { url = "https://files.pythonhosted.org/packages/14/ef/978ba79df0d65af680e20d43121363cf643eb79b04bf3880d01fc8afeb6f/mypy-1.17.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b72c34ce05ac3a1361ae2ebb50757fb6e3624032d91488d93544e9f82db0ed6c", size = 11918121, upload-time = "2025-07-14T20:33:52.328Z" }, + { url = "https://files.pythonhosted.org/packages/f4/10/55ef70b104151a0d8280474f05268ff0a2a79be8d788d5e647257d121309/mypy-1.17.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:434ad499ad8dde8b2f6391ddfa982f41cb07ccda8e3c67781b1bfd4e5f9450a8", size = 12648821, upload-time = "2025-07-14T20:32:59.631Z" }, + { url = "https://files.pythonhosted.org/packages/26/8c/7781fcd2e1eef48fbedd3a422c21fe300a8e03ed5be2eb4bd10246a77f4e/mypy-1.17.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:f105f61a5eff52e137fd73bee32958b2add9d9f0a856f17314018646af838e97", size = 12896955, upload-time = "2025-07-14T20:32:49.543Z" }, + { url = "https://files.pythonhosted.org/packages/78/13/03ac759dabe86e98ca7b6681f114f90ee03f3ff8365a57049d311bd4a4e3/mypy-1.17.0-cp39-cp39-win_amd64.whl", hash = "sha256:ba06254a5a22729853209550d80f94e28690d5530c661f9416a68ac097b13fc4", size = 9512957, upload-time = "2025-07-14T20:33:28.619Z" }, + { url = "https://files.pythonhosted.org/packages/e3/fc/ee058cc4316f219078464555873e99d170bde1d9569abd833300dbeb484a/mypy-1.17.0-py3-none-any.whl", hash = "sha256:15d9d0018237ab058e5de3d8fce61b6fa72cc59cc78fd91f1b474bce12abf496", size = 2283195, upload-time = "2025-07-14T20:31:54.753Z" }, +] + +[[package]] +name = "mypy-extensions" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, +] + +[[package]] +name = "nodeenv" +version = "1.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611, upload-time = "2025-12-20T14:08:54.006Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" }, +] + +[[package]] +name = "packaging" +version = "26.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" }, +] + +[[package]] +name = "pathspec" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/82/42f767fc1c1143d6fd36efb827202a2d997a375e160a71eb2888a925aac1/pathspec-1.1.1.tar.gz", hash = "sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a", size = 135180, upload-time = "2026-04-27T01:46:08.907Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", size = 57328, upload-time = "2026-04-27T01:46:07.06Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + [[package]] name = "propcache" version = "0.4.1" @@ -772,15 +1117,68 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" }, ] +[[package]] +name = "pydantic" +version = "1.10.26" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.10'", + "python_full_version < '3.10'", +] +dependencies = [ + { name = "typing-extensions", marker = "extra == 'group-10-cloudflare-pydantic-v1'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7b/da/fd89f987a376c807cd81ea0eff4589aade783bbb702637b4734ef2c743a2/pydantic-1.10.26.tar.gz", hash = "sha256:8c6aa39b494c5af092e690127c283d84f363ac36017106a9e66cb33a22ac412e", size = 357906, upload-time = "2025-12-18T15:47:46.557Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/71/08/2587a6d4314e7539eec84acd062cb7b037638edb57a0335d20e4c5b8878c/pydantic-1.10.26-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f7ae36fa0ecef8d39884120f212e16c06bb096a38f523421278e2f39c1784546", size = 2444588, upload-time = "2025-12-18T15:46:28.882Z" }, + { url = "https://files.pythonhosted.org/packages/47/e6/10df5f08c105bcbb4adbee7d1108ff4b347702b110fed058f6a03f1c6b73/pydantic-1.10.26-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d95a76cf503f0f72ed7812a91de948440b2bf564269975738a4751e4fadeb572", size = 2255972, upload-time = "2025-12-18T15:46:31.72Z" }, + { url = "https://files.pythonhosted.org/packages/ba/7d/fdb961e7adc2c31f394feba6f560ef2c74c446f0285e2c2eb87d2b7206c7/pydantic-1.10.26-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a943ce8e00ad708ed06a1d9df5b4fd28f5635a003b82a4908ece6f24c0b18464", size = 2857175, upload-time = "2025-12-18T15:46:34Z" }, + { url = "https://files.pythonhosted.org/packages/8f/6c/f21e27dda475d4c562bd01b5874284dd3180f336c1e669413b743ca8b278/pydantic-1.10.26-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:465ad8edb29b15c10b779b16431fe8e77c380098badf6db367b7a1d3e572cf53", size = 2947001, upload-time = "2025-12-18T15:46:35.922Z" }, + { url = "https://files.pythonhosted.org/packages/6d/f6/27ea206232cbb6ec24dc4e4e8888a9a734f96a1eaf13504be4b30ef26aa7/pydantic-1.10.26-cp310-cp310-win_amd64.whl", hash = "sha256:80e6be6272839c8a7641d26ad569ab77772809dd78f91d0068dc0fc97f071945", size = 2066217, upload-time = "2025-12-18T15:46:37.614Z" }, + { url = "https://files.pythonhosted.org/packages/1d/c1/d521e64c8130e1ad9d22c270bed3fabcc0940c9539b076b639c88fd32a8d/pydantic-1.10.26-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:116233e53889bcc536f617e38c1b8337d7fa9c280f0fd7a4045947515a785637", size = 2428347, upload-time = "2025-12-18T15:46:39.41Z" }, + { url = "https://files.pythonhosted.org/packages/2c/08/f4b804a00c16e3ea994cb640a7c25c579b4f1fa674cde6a19fa0dfb0ae4f/pydantic-1.10.26-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c3cfdd361addb6eb64ccd26ac356ad6514cee06a61ab26b27e16b5ed53108f77", size = 2212605, upload-time = "2025-12-18T15:46:41.006Z" }, + { url = "https://files.pythonhosted.org/packages/5d/78/0df4b9efef29bbc5e39f247fcba99060d15946b4463d82a5589cf7923d71/pydantic-1.10.26-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0e4451951a9a93bf9a90576f3e25240b47ee49ab5236adccb8eff6ac943adf0f", size = 2753560, upload-time = "2025-12-18T15:46:43.215Z" }, + { url = "https://files.pythonhosted.org/packages/68/66/6ab6c1d3a116d05d2508fce64f96e35242938fac07544d611e11d0d363a0/pydantic-1.10.26-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9858ed44c6bea5f29ffe95308db9e62060791c877766c67dd5f55d072c8612b5", size = 2859235, upload-time = "2025-12-18T15:46:45.112Z" }, + { url = "https://files.pythonhosted.org/packages/61/4e/f1676bb0fcdf6ed2ce4670d7d1fc1d6c3a06d84497644acfbe02649503f1/pydantic-1.10.26-cp311-cp311-win_amd64.whl", hash = "sha256:ac1089f723e2106ebde434377d31239e00870a7563245072968e5af5cc4d33df", size = 2066646, upload-time = "2025-12-18T15:46:46.816Z" }, + { url = "https://files.pythonhosted.org/packages/02/6c/cd97a5a776c4515e6ee2ae81c2f2c5be51376dda6c31f965d7746ce0019f/pydantic-1.10.26-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:468d5b9cacfcaadc76ed0a4645354ab6f263ec01a63fb6d05630ea1df6ae453f", size = 2433795, upload-time = "2025-12-18T15:46:49.321Z" }, + { url = "https://files.pythonhosted.org/packages/47/12/de20affa30dcef728fcf9cc98e13ff4438c7a630de8d2f90eb38eba0891c/pydantic-1.10.26-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2c1b0b914be31671000ca25cf7ea17fcaaa68cfeadf6924529c5c5aa24b7ab1f", size = 2227387, upload-time = "2025-12-18T15:46:50.877Z" }, + { url = "https://files.pythonhosted.org/packages/7b/1d/9d65dcc5b8c17ba590f1f9f486e9306346831902318b7ee93f63516f4003/pydantic-1.10.26-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:15b13b9f8ba8867095769e1156e0d7fbafa1f65b898dd40fd1c02e34430973cb", size = 2629594, upload-time = "2025-12-18T15:46:53.42Z" }, + { url = "https://files.pythonhosted.org/packages/3f/76/acb41409356789e23e1a7ef58f93821410c96409183ce314ddb58d97f23e/pydantic-1.10.26-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad7025ca324ae263d4313998e25078dcaec5f9ed0392c06dedb57e053cc8086b", size = 2745305, upload-time = "2025-12-18T15:46:55.987Z" }, + { url = "https://files.pythonhosted.org/packages/22/72/a98c0c5e527a66057d969fedd61675223c7975ade61acebbca9f1abd6dc0/pydantic-1.10.26-cp312-cp312-win_amd64.whl", hash = "sha256:4482b299874dabb88a6c3759e3d85c6557c407c3b586891f7d808d8a38b66b9c", size = 1937647, upload-time = "2025-12-18T15:46:57.905Z" }, + { url = "https://files.pythonhosted.org/packages/28/b9/17a5a5a421c23ac27486b977724a42c9d5f8b7f0f4aab054251066223900/pydantic-1.10.26-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1ae7913bb40a96c87e3d3f6fe4e918ef53bf181583de4e71824360a9b11aef1c", size = 2494599, upload-time = "2025-12-18T15:47:00.209Z" }, + { url = "https://files.pythonhosted.org/packages/e6/8e/6e3bd4241076cf227b443d7577245dd5d181ecf40b3182fcb908bc8c197d/pydantic-1.10.26-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8154c13f58d4de5d3a856bb6c909c7370f41fb876a5952a503af6b975265f4ba", size = 2254391, upload-time = "2025-12-18T15:47:02.268Z" }, + { url = "https://files.pythonhosted.org/packages/a8/30/a1c4092eda2145ecbead6c92db489b223e101e1ba0da82576d0cf73dd422/pydantic-1.10.26-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f8af0507bf6118b054a9765fb2e402f18a8b70c964f420d95b525eb711122d62", size = 2609445, upload-time = "2025-12-18T15:47:04.909Z" }, + { url = "https://files.pythonhosted.org/packages/3a/2a/0491f1729ee4b7b6bc859ec22f69752f0c09bee1b66ac6f5f701136f34c3/pydantic-1.10.26-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dcb5a7318fb43189fde6af6f21ac7149c4bcbcfffc54bc87b5becddc46084847", size = 2732124, upload-time = "2025-12-18T15:47:07.464Z" }, + { url = "https://files.pythonhosted.org/packages/2a/56/b59f3b2f84e1df2b04ae768a1bb04d9f0288ff71b67cdcbb07683757b2c0/pydantic-1.10.26-cp313-cp313-win_amd64.whl", hash = "sha256:71cde228bc0600cf8619f0ee62db050d1880dcc477eba0e90b23011b4ee0f314", size = 1939888, upload-time = "2025-12-18T15:47:09.618Z" }, + { url = "https://files.pythonhosted.org/packages/d2/8b/0c3dc02d4b97790b0f199bf933f677c14e7be4a8d21307c5f2daae06aa41/pydantic-1.10.26-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:6b40730cc81d53d515dc0b8bb5c9b43fadb9bed46de4a3c03bd95e8571616dba", size = 2502689, upload-time = "2025-12-18T15:47:12.308Z" }, + { url = "https://files.pythonhosted.org/packages/d4/9d/d31aeea45542b2ae4b09ecba92b88aaba696b801c31919811aa979a1242d/pydantic-1.10.26-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c3bbb9c0eecdf599e4db9b372fa9cc55be12e80a0d9c6d307950a39050cb0e37", size = 2269494, upload-time = "2025-12-18T15:47:14.53Z" }, + { url = "https://files.pythonhosted.org/packages/78/c1/3a4d069593283ca4dd0006039ba33644e21e432cddc09da706ac50441610/pydantic-1.10.26-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc2e3fe7bc4993626ef6b6fa855defafa1d6f8996aa1caef2deb83c5ac4d043a", size = 2620047, upload-time = "2025-12-18T15:47:17.089Z" }, + { url = "https://files.pythonhosted.org/packages/e0/0e/340c3d29197d99c15ab04093d43bb9c9d0fd17c2a34b80cb9d36ed732b09/pydantic-1.10.26-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:36d9e46b588aaeb1dcd2409fa4c467fe0b331f3cc9f227b03a7a00643704e962", size = 2747625, upload-time = "2025-12-18T15:47:19.21Z" }, + { url = "https://files.pythonhosted.org/packages/1e/58/f12ab3727339b172c830b32151919456b67787cdfe8808b2568b322fb15c/pydantic-1.10.26-cp314-cp314-win_amd64.whl", hash = "sha256:81ce3c8616d12a7be31b4aadfd3434f78f6b44b75adbfaec2fe1ad4f7f999b8c", size = 1976436, upload-time = "2025-12-18T15:47:21.384Z" }, + { url = "https://files.pythonhosted.org/packages/e1/8a/3a5a6267d5f03617b5c0f1985aa9fdfbafd33a50ef6dadd866a15ed4d123/pydantic-1.10.26-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:502b9d30d18a2dfaf81b7302f6ba0e5853474b1c96212449eb4db912cb604b7d", size = 2457039, upload-time = "2025-12-18T15:47:34.584Z" }, + { url = "https://files.pythonhosted.org/packages/f3/fa/343ac0db26918a033ac6256c036d72c3b6eb1196b7de622e2e8a94b19079/pydantic-1.10.26-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0d8f6087bf697dec3bf7ffcd7fe8362674f16519f3151789f33cbe8f1d19fc15", size = 2266441, upload-time = "2025-12-18T15:47:36.807Z" }, + { url = "https://files.pythonhosted.org/packages/fc/36/1ab48136578608dba2f2a62e452f3db2083b474d4e49be5749c6ae0c123c/pydantic-1.10.26-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:dd40a99c358419910c85e6f5d22f9c56684c25b5e7abc40879b3b4a52f34ae90", size = 2869383, upload-time = "2025-12-18T15:47:38.883Z" }, + { url = "https://files.pythonhosted.org/packages/a2/25/41dbf1bffc31eb242cece8080561a4133eaeb513372dec36a84477a3fb71/pydantic-1.10.26-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ce3293b86ca9f4125df02ff0a70be91bc7946522467cbd98e7f1493f340616ba", size = 2963582, upload-time = "2025-12-18T15:47:40.854Z" }, + { url = "https://files.pythonhosted.org/packages/61/2f/f072ae160a300c85eb9f059915101fd33dacf12d8df08c2b804acb3b95d1/pydantic-1.10.26-cp39-cp39-win_amd64.whl", hash = "sha256:1a4e3062b71ab1d5df339ba12c48f9ed5817c5de6cb92a961dd5c64bb32e7b96", size = 2075530, upload-time = "2025-12-18T15:47:43.181Z" }, + { url = "https://files.pythonhosted.org/packages/1f/98/556e82f00b98486def0b8af85da95e69d2be7e367cf2431408e108bc3095/pydantic-1.10.26-py3-none-any.whl", hash = "sha256:c43ad70dc3ce7787543d563792426a16fd7895e14be4b194b5665e36459dd917", size = 166975, upload-time = "2025-12-18T15:47:44.927Z" }, +] + [[package]] name = "pydantic" version = "2.13.3" source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.14' and extra != 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2'", + "python_full_version >= '3.10' and python_full_version < '3.14' and extra != 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2'", + "python_full_version < '3.10' and extra != 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2'", + "python_full_version >= '3.10' and extra != 'group-10-cloudflare-pydantic-v1' and extra != 'group-10-cloudflare-pydantic-v2'", + "python_full_version < '3.10' and extra != 'group-10-cloudflare-pydantic-v1' and extra != 'group-10-cloudflare-pydantic-v2'", +] dependencies = [ - { name = "annotated-types" }, - { name = "pydantic-core" }, - { name = "typing-extensions" }, - { name = "typing-inspection" }, + { name = "annotated-types", marker = "extra == 'group-10-cloudflare-pydantic-v2' or extra != 'group-10-cloudflare-pydantic-v1'" }, + { name = "pydantic-core", marker = "extra == 'group-10-cloudflare-pydantic-v2' or extra != 'group-10-cloudflare-pydantic-v1'" }, + { name = "typing-extensions", marker = "extra == 'group-10-cloudflare-pydantic-v2' or extra != 'group-10-cloudflare-pydantic-v1'" }, + { name = "typing-inspection", marker = "extra == 'group-10-cloudflare-pydantic-v2' or extra != 'group-10-cloudflare-pydantic-v1'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d9/e4/40d09941a2cebcb20609b86a559817d5b9291c49dd6f8c87e5feffbe703a/pydantic-2.13.3.tar.gz", hash = "sha256:af09e9d1d09f4e7fe37145c1f577e1d61ceb9a41924bf0094a36506285d0a84d", size = 844068, upload-time = "2026-04-20T14:46:43.632Z" } wheels = [ @@ -792,7 +1190,7 @@ name = "pydantic-core" version = "2.46.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions" }, + { name = "typing-extensions", marker = "extra == 'group-10-cloudflare-pydantic-v2' or extra != 'group-10-cloudflare-pydantic-v1'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/2a/ef/f7abb56c49382a246fd2ce9c799691e3c3e7175ec74b14d99e798bcddb1a/pydantic_core-2.46.3.tar.gz", hash = "sha256:41c178f65b8c29807239d47e6050262eb6bf84eb695e41101e62e38df4a5bc2c", size = 471412, upload-time = "2026-04-20T14:40:56.672Z" } wheels = [ @@ -917,6 +1315,196 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/07/0f/1c34a74c8d07136f0d729ffe5e1fdab04fbdaa7684f61a92f92511a84a15/pydantic_core-2.46.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:b00b76f7142fc60c762ce579bd29c8fa44aaa56592dd3c54fab3928d0d4ca6ff", size = 2184144, upload-time = "2026-04-20T14:42:57Z" }, ] +[[package]] +name = "pygments" +version = "2.20.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, +] + +[[package]] +name = "pyright" +version = "1.1.399" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nodeenv" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/db/9d/d91d5f6d26b2db95476fefc772e2b9a16d54c6bd0ea6bb5c1b6d635ab8b4/pyright-1.1.399.tar.gz", hash = "sha256:439035d707a36c3d1b443aec980bc37053fbda88158eded24b8eedcf1c7b7a1b", size = 3856954, upload-time = "2025-04-10T04:40:25.703Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2f/b5/380380c9e7a534cb1783c70c3e8ac6d1193c599650a55838d0557586796e/pyright-1.1.399-py3-none-any.whl", hash = "sha256:55f9a875ddf23c9698f24208c764465ffdfd38be6265f7faf9a176e1dc549f3b", size = 5592584, upload-time = "2025-04-10T04:40:23.502Z" }, +] + +[[package]] +name = "pytest" +version = "8.4.2" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.10'", +] +dependencies = [ + { name = "colorama", marker = "(python_full_version < '3.10' and sys_platform == 'win32') or (python_full_version >= '3.10' and extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2') or (sys_platform != 'win32' and extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "exceptiongroup", marker = "python_full_version < '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "iniconfig", version = "2.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "packaging", marker = "python_full_version < '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "pluggy", marker = "python_full_version < '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "pygments", marker = "python_full_version < '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "tomli", marker = "python_full_version < '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size = 1519618, upload-time = "2025-09-04T14:34:22.711Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750, upload-time = "2025-09-04T14:34:20.226Z" }, +] + +[[package]] +name = "pytest" +version = "9.0.3" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.14' and extra != 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2'", + "python_full_version >= '3.10' and python_full_version < '3.14' and extra != 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2'", + "python_full_version >= '3.10' and extra == 'group-10-cloudflare-pydantic-v1' and extra != 'group-10-cloudflare-pydantic-v2'", + "python_full_version >= '3.10' and extra != 'group-10-cloudflare-pydantic-v1' and extra != 'group-10-cloudflare-pydantic-v2'", +] +dependencies = [ + { name = "colorama", marker = "(python_full_version >= '3.10' and sys_platform == 'win32') or (python_full_version < '3.10' and extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2') or (sys_platform != 'win32' and extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "exceptiongroup", marker = "python_full_version == '3.10.*' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "iniconfig", version = "2.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "packaging", marker = "python_full_version >= '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "pluggy", marker = "python_full_version >= '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "pygments", marker = "python_full_version >= '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "tomli", marker = "python_full_version == '3.10.*' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7d/0d/549bd94f1a0a402dc8cf64563a117c0f3765662e2e668477624baeec44d5/pytest-9.0.3.tar.gz", hash = "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c", size = 1572165, upload-time = "2026-04-07T17:16:18.027Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9", size = 375249, upload-time = "2026-04-07T17:16:16.13Z" }, +] + +[[package]] +name = "pytest-asyncio" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.10'", +] +dependencies = [ + { name = "backports-asyncio-runner", marker = "python_full_version < '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "pytest", version = "8.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "typing-extensions", marker = "python_full_version < '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/86/9e3c5f48f7b7b638b216e4b9e645f54d199d7abbbab7a64a13b4e12ba10f/pytest_asyncio-1.2.0.tar.gz", hash = "sha256:c609a64a2a8768462d0c99811ddb8bd2583c33fd33cf7f21af1c142e824ffb57", size = 50119, upload-time = "2025-09-12T07:33:53.816Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl", hash = "sha256:8e17ae5e46d8e7efe51ab6494dd2010f4ca8dae51652aa3c8d55acf50bfb2e99", size = 15095, upload-time = "2025-09-12T07:33:52.639Z" }, +] + +[[package]] +name = "pytest-asyncio" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.14' and extra != 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2'", + "python_full_version >= '3.10' and python_full_version < '3.14' and extra != 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2'", + "python_full_version >= '3.10' and extra == 'group-10-cloudflare-pydantic-v1' and extra != 'group-10-cloudflare-pydantic-v2'", + "python_full_version >= '3.10' and extra != 'group-10-cloudflare-pydantic-v1' and extra != 'group-10-cloudflare-pydantic-v2'", +] +dependencies = [ + { name = "backports-asyncio-runner", marker = "python_full_version == '3.10.*' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "pytest", version = "9.0.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "typing-extensions", marker = "(python_full_version >= '3.10' and python_full_version < '3.13') or (python_full_version < '3.10' and extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2') or (python_full_version >= '3.13' and extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/90/2c/8af215c0f776415f3590cac4f9086ccefd6fd463befeae41cd4d3f193e5a/pytest_asyncio-1.3.0.tar.gz", hash = "sha256:d7f52f36d231b80ee124cd216ffb19369aa168fc10095013c6b014a34d3ee9e5", size = 50087, upload-time = "2025-11-10T16:07:47.256Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/35/f8b19922b6a25bc0880171a2f1a003eaeb93657475193ab516fd87cac9da/pytest_asyncio-1.3.0-py3-none-any.whl", hash = "sha256:611e26147c7f77640e6d0a92a38ed17c3e9848063698d5c93d5aa7aa11cebff5", size = 15075, upload-time = "2025-11-10T16:07:45.537Z" }, +] + +[[package]] +name = "pytest-xdist" +version = "3.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "execnet" }, + { name = "pytest", version = "8.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "pytest", version = "9.0.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/78/b4/439b179d1ff526791eb921115fca8e44e596a13efeda518b9d845a619450/pytest_xdist-3.8.0.tar.gz", hash = "sha256:7e578125ec9bc6050861aa93f2d59f1d8d085595d6551c2c90b6f4fad8d3a9f1", size = 88069, upload-time = "2025-07-01T13:30:59.346Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ca/31/d4e37e9e550c2b92a9cbc2e4d0b7420a27224968580b5a447f420847c975/pytest_xdist-3.8.0-py3-none-any.whl", hash = "sha256:202ca578cfeb7370784a8c33d6d05bc6e13b4f25b5053c30a152269fd10f0b88", size = 46396, upload-time = "2025-07-01T13:30:56.632Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six", marker = "python_full_version < '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "respx" +version = "0.23.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "httpx" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/43/98/4e55c9c486404ec12373708d015ebce157966965a5ebe7f28ff2c784d41b/respx-0.23.1.tar.gz", hash = "sha256:242dcc6ce6b5b9bf621f5870c82a63997e8e82bc7c947f9ffe272b8f3dd5a780", size = 29243, upload-time = "2026-04-08T14:37:16.008Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1d/4a/221da6ca167db45693d8d26c7dc79ccfc978a440251bf6721c9aaf251ac0/respx-0.23.1-py2.py3-none-any.whl", hash = "sha256:b18004b029935384bccfa6d7d9d74b4ec9af73a081cc28600fffc0447f4b8c1a", size = 25557, upload-time = "2026-04-08T14:37:14.613Z" }, +] + +[[package]] +name = "rich" +version = "15.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py", version = "3.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "markdown-it-py", version = "4.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c0/8f/0722ca900cc807c13a6a0c696dacf35430f72e0ec571c4275d2371fca3e9/rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36", size = 230680, upload-time = "2026-04-12T08:24:00.75Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654, upload-time = "2026-04-12T08:24:02.83Z" }, +] + +[[package]] +name = "ruff" +version = "0.15.12" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/99/43/3291f1cc9106f4c63bdce7a8d0df5047fe8422a75b091c16b5e9355e0b11/ruff-0.15.12.tar.gz", hash = "sha256:ecea26adb26b4232c0c2ca19ccbc0083a68344180bba2a600605538ce51a40a6", size = 4643852, upload-time = "2026-04-24T18:17:14.305Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c3/6e/e78ffb61d4686f3d96ba3df2c801161843746dcbcbb17a1e927d4829312b/ruff-0.15.12-py3-none-linux_armv6l.whl", hash = "sha256:f86f176e188e94d6bdbc09f09bfd9dc729059ad93d0e7390b5a73efe19f8861c", size = 10640713, upload-time = "2026-04-24T18:17:22.841Z" }, + { url = "https://files.pythonhosted.org/packages/ae/08/a317bc231fb9e7b93e4ef3089501e51922ff88d6936ce5cf870c4fe55419/ruff-0.15.12-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e3bcd123364c3770b8e1b7baaf343cc99a35f197c5c6e8af79015c666c423a6c", size = 11069267, upload-time = "2026-04-24T18:17:30.105Z" }, + { url = "https://files.pythonhosted.org/packages/aa/a4/f828e9718d3dce1f5f11c39c4f65afd32783c8b2aebb2e3d259e492c47bd/ruff-0.15.12-py3-none-macosx_11_0_arm64.whl", hash = "sha256:fe87510d000220aa1ed530d4448a7c696a0cae1213e5ec30e5874287b66557b5", size = 10397182, upload-time = "2026-04-24T18:17:07.177Z" }, + { url = "https://files.pythonhosted.org/packages/71/e0/3310fc6d1b5e1fdea22bf3b1b807c7e187b581021b0d7d4514cccdb5fb71/ruff-0.15.12-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84a1630093121375a3e2a95b4a6dc7b59e2b4ee76216e32d81aae550a832d002", size = 10758012, upload-time = "2026-04-24T18:16:55.759Z" }, + { url = "https://files.pythonhosted.org/packages/11/c1/a606911aee04c324ddaa883ae418f3569792fd3c4a10c50e0dd0a2311e1e/ruff-0.15.12-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fb129f40f114f089ebe0ca56c0d251cf2061b17651d464bb6478dc01e69f11f5", size = 10447479, upload-time = "2026-04-24T18:16:51.677Z" }, + { url = "https://files.pythonhosted.org/packages/9d/68/4201e8444f0894f21ab4aeeaee68aa4f10b51613514a20d80bd628d57e88/ruff-0.15.12-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0c862b172d695db7598426b8af465e7e9ac00a3ea2a3630ee67eb82e366aaa6", size = 11234040, upload-time = "2026-04-24T18:17:16.529Z" }, + { url = "https://files.pythonhosted.org/packages/34/ff/8a6d6cf4ccc23fd67060874e832c18919d1557a0611ebef03fdb01fff11e/ruff-0.15.12-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2849ea9f3484c3aca43a82f484210370319e7170df4dfe4843395ddf6c57bc33", size = 12087377, upload-time = "2026-04-24T18:17:04.944Z" }, + { url = "https://files.pythonhosted.org/packages/85/f6/c669cf73f5152f623d34e69866a46d5e6185816b19fcd5b6dd8a2d299922/ruff-0.15.12-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9e77c7e51c07fe396826d5969a5b846d9cd4c402535835fb6e21ce8b28fef847", size = 11367784, upload-time = "2026-04-24T18:17:25.409Z" }, + { url = "https://files.pythonhosted.org/packages/e8/39/c61d193b8a1daaa8977f7dea9e8d8ba866e02ea7b65d32f6861693aa4c12/ruff-0.15.12-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83b2f4f2f3b1026b5fb449b467d9264bf22067b600f7b6f41fc5958909f449d0", size = 11344088, upload-time = "2026-04-24T18:17:12.258Z" }, + { url = "https://files.pythonhosted.org/packages/c2/8d/49afab3645e31e12c590acb6d3b5b69d7aab5b81926dbaf7461f9441f37a/ruff-0.15.12-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:9ba3b8f1afd7e2e43d8943e55f249e13f9682fde09711644a6e7290eb4f3e339", size = 11271770, upload-time = "2026-04-24T18:17:02.457Z" }, + { url = "https://files.pythonhosted.org/packages/46/06/33f41fe94403e2b755481cdfb9b7ef3e4e0ed031c4581124658d935d52b4/ruff-0.15.12-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e852ba9fdc890655e1d78f2df1499efbe0e54126bd405362154a75e2bde159c5", size = 10719355, upload-time = "2026-04-24T18:17:27.648Z" }, + { url = "https://files.pythonhosted.org/packages/0d/59/18aa4e014debbf559670e4048e39260a85c7fcee84acfd761ac01e7b8d35/ruff-0.15.12-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:dd8aed930da53780d22fc70bdf84452c843cf64f8cb4eb38984319c24c5cd5fd", size = 10462758, upload-time = "2026-04-24T18:17:32.347Z" }, + { url = "https://files.pythonhosted.org/packages/25/e7/cc9f16fd0f3b5fddcbd7ec3d6ae30c8f3fde1047f32a4093a98d633c6570/ruff-0.15.12-py3-none-musllinux_1_2_i686.whl", hash = "sha256:01da3988d225628b709493d7dc67c3b9b12c0210016b08690ef9bd27970b262b", size = 10953498, upload-time = "2026-04-24T18:17:20.674Z" }, + { url = "https://files.pythonhosted.org/packages/72/7a/a9ba7f98c7a575978698f4230c5e8cc54bbc761af34f560818f933dafa0c/ruff-0.15.12-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:9cae0f92bd5700d1213188b31cd3bdd2b315361296d10b96b8e2337d3d11f53e", size = 11447765, upload-time = "2026-04-24T18:17:09.755Z" }, + { url = "https://files.pythonhosted.org/packages/ea/f9/0ae446942c846b8266059ad8a30702a35afae55f5cdc54c5adf8d7afdc27/ruff-0.15.12-py3-none-win32.whl", hash = "sha256:d0185894e038d7043ba8fd6aee7499ece6462dc0ea9f1e260c7451807c714c20", size = 10657277, upload-time = "2026-04-24T18:17:18.591Z" }, + { url = "https://files.pythonhosted.org/packages/33/f1/9614e03e1cdcbf9437570b5400ced8a720b5db22b28d8e0f1bda429f660d/ruff-0.15.12-py3-none-win_amd64.whl", hash = "sha256:c87a162d61ab3adca47c03f7f717c68672edec7d1b5499e652331780fe74950d", size = 11837758, upload-time = "2026-04-24T18:17:00.113Z" }, + { url = "https://files.pythonhosted.org/packages/c0/98/6beb4b351e472e5f4c4613f7c35a5290b8be2497e183825310c4c3a3984b/ruff-0.15.12-py3-none-win_arm64.whl", hash = "sha256:a538f7a82d061cee7be55542aca1d86d1393d55d81d4fcc314370f4340930d4f", size = 11120821, upload-time = "2026-04-24T18:16:57.979Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + [[package]] name = "sniffio" version = "1.3.1" @@ -926,6 +1514,253 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, ] +[[package]] +name = "time-machine" +version = "2.19.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.10'", +] +dependencies = [ + { name = "python-dateutil", marker = "python_full_version < '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f8/a4/1b5fdd165f61b67f445fac2a7feb0c655118edef429cd09ff5a8067f7f1d/time_machine-2.19.0.tar.gz", hash = "sha256:7c5065a8b3f2bbb449422c66ef71d114d3f909c276a6469642ecfffb6a0fcd29", size = 14576, upload-time = "2025-08-19T17:22:08.402Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/8f/19125611ebbcb3a14da14cd982b9eb4573e2733db60c9f1fbf6a39534f40/time_machine-2.19.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b5169018ef47206997b46086ce01881cd3a4666fd2998c9d76a87858ca3e49e9", size = 19659, upload-time = "2025-08-19T17:20:30.062Z" }, + { url = "https://files.pythonhosted.org/packages/74/da/9b0a928321e7822a3ff96dbd1eae089883848e30e9e1b149b85fb96ba56b/time_machine-2.19.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:85bb7ed440fccf6f6d0c8f7d68d849e7c3d1f771d5e0b2cdf871fa6561da569f", size = 15157, upload-time = "2025-08-19T17:20:31.931Z" }, + { url = "https://files.pythonhosted.org/packages/36/ff/d7e943422038f5f2161fe2c2d791e64a45be691ef946020b20f3a6efc4d4/time_machine-2.19.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a3b12028af1cdc09ccd595be2168b7b26f206c1e190090b048598fbe278beb8e", size = 32860, upload-time = "2025-08-19T17:20:33.241Z" }, + { url = "https://files.pythonhosted.org/packages/fc/80/2b0f1070ed9808ee7da7a6da62a4a0b776957cb4d861578348f86446e778/time_machine-2.19.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c261f073086cf081d1443cbf7684148c662659d3d139d06b772bfe3fe7cc71a6", size = 34510, upload-time = "2025-08-19T17:20:34.221Z" }, + { url = "https://files.pythonhosted.org/packages/ef/b4/48038691c8d89924b36c83335a73adeeb68c884f5a1da08a5b17b8a956f3/time_machine-2.19.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:011954d951230a9f1079f22b39ed1a3a9abb50ee297dfb8c557c46351659d94d", size = 36204, upload-time = "2025-08-19T17:20:35.163Z" }, + { url = "https://files.pythonhosted.org/packages/37/2e/60e8adb541df195e83cb74b720b2cfb1f22ed99c5a7f8abf2a9ab3442cb5/time_machine-2.19.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b0f83308b29c7872006803f2e77318874eb84d0654f2afe0e48e3822e7a2e39b", size = 34936, upload-time = "2025-08-19T17:20:36.61Z" }, + { url = "https://files.pythonhosted.org/packages/5e/72/e8cee59c6cd99dd3b25b8001a0253e779a286aa8f44d5b40777cbd66210b/time_machine-2.19.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:39733ef844e2984620ec9382a42d00cccc4757d75a5dd572be8c2572e86e50b9", size = 32932, upload-time = "2025-08-19T17:20:37.901Z" }, + { url = "https://files.pythonhosted.org/packages/2c/eb/83f300d93c1504965d944e03679f1c943a923bce2d0fdfadef0e2e22cc13/time_machine-2.19.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f8db99f6334432e9ffbf00c215caf2ae9773f17cec08304d77e9e90febc3507b", size = 34010, upload-time = "2025-08-19T17:20:39.202Z" }, + { url = "https://files.pythonhosted.org/packages/e1/77/f35f2500e04daac5033a22fbfd17e68467822b8406ee77966bf222ccaa26/time_machine-2.19.0-cp310-cp310-win32.whl", hash = "sha256:72bf66cd19e27ffd26516b9cbe676d50c2e0b026153289765dfe0cf406708128", size = 17121, upload-time = "2025-08-19T17:20:40.108Z" }, + { url = "https://files.pythonhosted.org/packages/db/df/32d3e0404be1760a64a44caab2af34b07e952bfe00a23134fea9ddba3e8a/time_machine-2.19.0-cp310-cp310-win_amd64.whl", hash = "sha256:46f1c945934ce3d6b4f388b8e581fce7f87ec891ea90d7128e19520e434f96f0", size = 17957, upload-time = "2025-08-19T17:20:41.079Z" }, + { url = "https://files.pythonhosted.org/packages/66/df/598a71a1afb4b509a4587273b76590b16d9110a3e9106f01eedc68d02bb2/time_machine-2.19.0-cp310-cp310-win_arm64.whl", hash = "sha256:fb4897c7a5120a4fd03f0670f332d83b7e55645886cd8864a71944c4c2e5b35b", size = 16821, upload-time = "2025-08-19T17:20:41.967Z" }, + { url = "https://files.pythonhosted.org/packages/1d/ed/4815ebcc9b6c14273f692b9be38a9b09eae52a7e532407cc61a51912b121/time_machine-2.19.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5ee91664880434d98e41585c3446dac7180ec408c786347451ddfca110d19296", size = 19342, upload-time = "2025-08-19T17:20:43.207Z" }, + { url = "https://files.pythonhosted.org/packages/ee/08/154cce8b11b60d8238b0b751b8901d369999f4e8f7c3a5f917caa5d95b0b/time_machine-2.19.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ed3732b83a893d1c7b8cabde762968b4dc5680ee0d305b3ecca9bb516f4e3862", size = 14978, upload-time = "2025-08-19T17:20:44.134Z" }, + { url = "https://files.pythonhosted.org/packages/c7/b7/b689d8c8eeca7af375cfcd64973e49e83aa817cc00f80f98548d42c0eb50/time_machine-2.19.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6ba0303e9cc9f7f947e344f501e26bedfb68fab521e3c2729d370f4f332d2d55", size = 30964, upload-time = "2025-08-19T17:20:45.366Z" }, + { url = "https://files.pythonhosted.org/packages/80/91/38bf9c79674e95ce32e23c267055f281dff651eec77ed32a677db3dc011a/time_machine-2.19.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2851825b524a988ee459c37c1c26bdfaa7eff78194efb2b562ea497a6f375b0a", size = 32606, upload-time = "2025-08-19T17:20:46.693Z" }, + { url = "https://files.pythonhosted.org/packages/19/4a/e9222d85d4de68975a5e799f539a9d32f3a134a9101fca0a61fa6aa33d68/time_machine-2.19.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:68d32b09ecfd7fef59255c091e8e7c24dd117f882c4880b5c7ab8c5c32a98f89", size = 34405, upload-time = "2025-08-19T17:20:48.032Z" }, + { url = "https://files.pythonhosted.org/packages/14/e2/09480d608d42d6876f9ff74593cfc9197a7eb2c31381a74fb2b145575b65/time_machine-2.19.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:60c46ab527bf2fa144b530f639cc9e12803524c9e1f111dc8c8f493bb6586eeb", size = 33181, upload-time = "2025-08-19T17:20:48.937Z" }, + { url = "https://files.pythonhosted.org/packages/84/64/f9359e000fad32d9066305c48abc527241d608bcdf77c19d67d66e268455/time_machine-2.19.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:56f26ab9f0201c453d18fe76bb7d1cf05fe58c1b9d9cb0c7d243d05132e01292", size = 31036, upload-time = "2025-08-19T17:20:50.276Z" }, + { url = "https://files.pythonhosted.org/packages/71/0d/fab2aacec71e3e482bd7fce0589381f9414a4a97f8766bddad04ad047b7b/time_machine-2.19.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6c806cf3c1185baa1d807b7f51bed0db7a6506832c961d5d1b4c94c775749bc0", size = 32145, upload-time = "2025-08-19T17:20:51.449Z" }, + { url = "https://files.pythonhosted.org/packages/44/fb/faeba2405fb27553f7b28db441a500e2064ffdb2dcba001ee315fdd2c121/time_machine-2.19.0-cp311-cp311-win32.whl", hash = "sha256:b30039dfd89855c12138095bee39c540b4633cbc3684580d684ef67a99a91587", size = 17004, upload-time = "2025-08-19T17:20:52.38Z" }, + { url = "https://files.pythonhosted.org/packages/2f/84/87e483d660ca669426192969280366635c845c3154a9fe750be546ed3afc/time_machine-2.19.0-cp311-cp311-win_amd64.whl", hash = "sha256:13ed8b34430f1de79905877f5600adffa626793ab4546a70a99fb72c6a3350d8", size = 17822, upload-time = "2025-08-19T17:20:53.348Z" }, + { url = "https://files.pythonhosted.org/packages/41/f4/ebf7bbf5047854a528adaf54a5e8780bc5f7f0104c298ab44566a3053bf8/time_machine-2.19.0-cp311-cp311-win_arm64.whl", hash = "sha256:cc29a50a0257d8750b08056b66d7225daab47606832dea1a69e8b017323bf511", size = 16680, upload-time = "2025-08-19T17:20:54.26Z" }, + { url = "https://files.pythonhosted.org/packages/9b/aa/7e00614d339e4d687f6e96e312a1566022528427d237ec639df66c4547bc/time_machine-2.19.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:c85cf437dc3c07429456d8d6670ac90ecbd8241dcd0fbf03e8db2800576f91ff", size = 19308, upload-time = "2025-08-19T17:20:55.25Z" }, + { url = "https://files.pythonhosted.org/packages/ab/3c/bde3c757394f5bca2fbc1528d4117960a26c38f9b160bf471b38d2378d8f/time_machine-2.19.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d9238897e8ef54acdf59f5dff16f59ca0720e7c02d820c56b4397c11db5d3eb9", size = 15019, upload-time = "2025-08-19T17:20:56.204Z" }, + { url = "https://files.pythonhosted.org/packages/c8/e0/8ca916dd918018352d377f1f5226ee071cfbeb7dbbde2b03d14a411ac2b1/time_machine-2.19.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e312c7d5d6bfffb96c6a7b39ff29e3046de100d7efaa3c01552654cfbd08f14c", size = 33079, upload-time = "2025-08-19T17:20:57.166Z" }, + { url = "https://files.pythonhosted.org/packages/48/69/184a0209f02dd0cb5e01e8d13cd4c97a5f389c4e3d09b95160dd676ad1e7/time_machine-2.19.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:714c40b2c90d1c57cc403382d5a9cf16e504cb525bfe9650095317da3c3d62b5", size = 34925, upload-time = "2025-08-19T17:20:58.117Z" }, + { url = "https://files.pythonhosted.org/packages/43/42/4bbf4309e8e57cea1086eb99052d97ff6ddecc1ab6a3b07aa4512f8bf963/time_machine-2.19.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2eaa1c675d500dc3ccae19e9fb1feff84458a68c132bbea47a80cc3dd2df7072", size = 36384, upload-time = "2025-08-19T17:20:59.108Z" }, + { url = "https://files.pythonhosted.org/packages/b1/af/9f510dc1719157348c1a2e87423aed406589070b54b503cb237d9bf3a4fe/time_machine-2.19.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e77a414e9597988af53b2b2e67242c9d2f409769df0d264b6d06fda8ca3360d4", size = 34881, upload-time = "2025-08-19T17:21:00.116Z" }, + { url = "https://files.pythonhosted.org/packages/ca/28/61764a635c70cc76c76ba582dfdc1a84834cddaeb96789023af5214426b2/time_machine-2.19.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:cd93996970e11c382b04d4937c3cd0b0167adeef14725ece35aae88d8a01733c", size = 32931, upload-time = "2025-08-19T17:21:01.095Z" }, + { url = "https://files.pythonhosted.org/packages/b6/e0/f028d93b266e6ade8aca5851f76ebbc605b2905cdc29981a2943b43e1a6c/time_machine-2.19.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8e20a6d8d6e23174bd7e931e134d9610b136db460b249d07e84ecdad029ec352", size = 34241, upload-time = "2025-08-19T17:21:02.052Z" }, + { url = "https://files.pythonhosted.org/packages/7d/a6/36d1950ed1d3f613158024cf1dcc73db1d9ef0b9117cf51ef2e37dc06499/time_machine-2.19.0-cp312-cp312-win32.whl", hash = "sha256:95afc9bc65228b27be80c2756799c20b8eb97c4ef382a9b762b6d7888bc84099", size = 17021, upload-time = "2025-08-19T17:21:03.374Z" }, + { url = "https://files.pythonhosted.org/packages/b1/0d/e2dce93355abda3cac69e77fe96566757e98b8fe7fdcbddce89c9ced3f5f/time_machine-2.19.0-cp312-cp312-win_amd64.whl", hash = "sha256:e84909af950e2448f4e2562ea5759c946248c99ab380d2b47d79b62bd76fa236", size = 17857, upload-time = "2025-08-19T17:21:04.331Z" }, + { url = "https://files.pythonhosted.org/packages/eb/28/50ae6fb83b7feeeca7a461c0dc156cf7ef5e6ef594a600d06634fde6a2cb/time_machine-2.19.0-cp312-cp312-win_arm64.whl", hash = "sha256:0390a1ea9fa7e9d772a39b7c61b34fdcca80eb9ffac339cc0441c6c714c81470", size = 16677, upload-time = "2025-08-19T17:21:05.39Z" }, + { url = "https://files.pythonhosted.org/packages/a9/b8/24ebce67aa531bae2cbe164bb3f4abc6467dc31f3aead35e77f5a075ea3e/time_machine-2.19.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5e172866753e6041d3b29f3037dc47c20525176a494a71bbd0998dfdc4f11f2f", size = 19373, upload-time = "2025-08-19T17:21:06.701Z" }, + { url = "https://files.pythonhosted.org/packages/53/a5/c9a5240fd2f845d3ff9fa26f8c8eaa29f7239af9d65007e61d212250f15b/time_machine-2.19.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f70f68379bd6f542ae6775cce9a4fa3dcc20bf7959c42eaef871c14469e18097", size = 15056, upload-time = "2025-08-19T17:21:07.667Z" }, + { url = "https://files.pythonhosted.org/packages/b9/92/66cce5d2fb2a5e68459aca85fd18a7e2d216f725988940cd83f96630f2f1/time_machine-2.19.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e69e0b0f694728a00e72891ef8dd00c7542952cb1c87237db594b6b27d504a96", size = 33172, upload-time = "2025-08-19T17:21:08.619Z" }, + { url = "https://files.pythonhosted.org/packages/ae/20/b499e9ab4364cd466016c33dcdf4f56629ca4c20b865bd4196d229f31d92/time_machine-2.19.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3ae0a8b869574301ec5637e32c270c7384cca5cd6e230f07af9d29271a7fa293", size = 35042, upload-time = "2025-08-19T17:21:09.622Z" }, + { url = "https://files.pythonhosted.org/packages/41/32/b252d3d32791eb16c07d553c820dbc33d9c7fa771de3d1c602190bded2b7/time_machine-2.19.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:554e4317de90e2f7605ff80d153c8bb56b38c0d0c0279feb17e799521e987b8c", size = 36535, upload-time = "2025-08-19T17:21:10.571Z" }, + { url = "https://files.pythonhosted.org/packages/98/cf/4d0470062b9742e1b040ab81bad04d1a5d1de09806507bb6188989cfa1a7/time_machine-2.19.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6567a5ec5538ed550539ac29be11b3cb36af1f9894e2a72940cba0292cc7c3c9", size = 34945, upload-time = "2025-08-19T17:21:11.538Z" }, + { url = "https://files.pythonhosted.org/packages/24/71/2f741b29d98b1c18f6777a32236497c3d3264b6077e431cea4695684c8a1/time_machine-2.19.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:82e9ffe8dfff07b0d810a2ad015a82cd78c6a237f6c7cf185fa7f747a3256f8a", size = 33014, upload-time = "2025-08-19T17:21:12.858Z" }, + { url = "https://files.pythonhosted.org/packages/e8/83/ca8dba6106562843fd99f672e5aaf95badbc10f4f13f7cfe8d8640a7019d/time_machine-2.19.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7e1c4e578cdd69b3531d8dd3fbcb92a0cd879dadb912ee37af99c3a9e3c0d285", size = 34350, upload-time = "2025-08-19T17:21:13.923Z" }, + { url = "https://files.pythonhosted.org/packages/21/7f/34fe540450e18d0a993240100e4b86e8d03d831b92af8bb6ddb2662dc6fc/time_machine-2.19.0-cp313-cp313-win32.whl", hash = "sha256:72dbd4cbc3d96dec9dd281ddfbb513982102776b63e4e039f83afb244802a9e5", size = 17047, upload-time = "2025-08-19T17:21:14.874Z" }, + { url = "https://files.pythonhosted.org/packages/bf/5d/c8be73df82c7ebe7cd133279670e89b8b110af3ce1412c551caa9d08e625/time_machine-2.19.0-cp313-cp313-win_amd64.whl", hash = "sha256:e17e3e089ac95f9a145ce07ff615e3c85674f7de36f2d92aaf588493a23ffb4b", size = 17868, upload-time = "2025-08-19T17:21:15.819Z" }, + { url = "https://files.pythonhosted.org/packages/92/13/2dfd3b8fb285308f61cd7aa9bfa96f46ddf916e3549a0f0afd094c556599/time_machine-2.19.0-cp313-cp313-win_arm64.whl", hash = "sha256:149072aff8e3690e14f4916103d898ea0d5d9c95531b6aa0995251c299533f7b", size = 16710, upload-time = "2025-08-19T17:21:16.748Z" }, + { url = "https://files.pythonhosted.org/packages/05/c1/deebb361727d2c5790f9d4d874be1b19afd41f4375581df465e6718b46a2/time_machine-2.19.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:f3589fee1ed0ab6ee424a55b0ea1ec694c4ba64cc26895bcd7d99f3d1bc6a28a", size = 20053, upload-time = "2025-08-19T17:21:17.704Z" }, + { url = "https://files.pythonhosted.org/packages/45/e8/fe3376951e6118d8ec1d1f94066a169b791424fe4a26c7dfc069b153ee08/time_machine-2.19.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:7887e85275c4975fe54df03dcdd5f38bd36be973adc68a8c77e17441c3b443d6", size = 15423, upload-time = "2025-08-19T17:21:18.668Z" }, + { url = "https://files.pythonhosted.org/packages/9c/c7/f88d95cd1a87c650cf3749b4d64afdaf580297aa18ad7f4b44ec9d252dfc/time_machine-2.19.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ce0be294c209928563fcce1c587963e60ec803436cf1e181acd5bc1e425d554b", size = 39630, upload-time = "2025-08-19T17:21:19.645Z" }, + { url = "https://files.pythonhosted.org/packages/cc/5d/65a5c48a65357e56ec6f032972e4abd1c02d4fca4b0717a3aaefd19014d4/time_machine-2.19.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a62fd1ab380012c86f4c042010418ed45eb31604f4bf4453e17c9fa60bc56a29", size = 41242, upload-time = "2025-08-19T17:21:20.979Z" }, + { url = "https://files.pythonhosted.org/packages/f6/f9/fe5209e1615fde0a8cad6c4e857157b150333ed1fe31a7632b08cfe0ebdd/time_machine-2.19.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b25ec853a4530a5800731257f93206b12cbdee85ede964ebf8011b66086a7914", size = 44278, upload-time = "2025-08-19T17:21:21.984Z" }, + { url = "https://files.pythonhosted.org/packages/4a/3a/a5e5fe9c5d614cde0a9387ff35e8dfd12c5ef6384e4c1a21b04e6e0b905d/time_machine-2.19.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a430e4d0e0556f021a9c78e9b9f68e5e8910bdace4aa34ed4d1a73e239ed9384", size = 42321, upload-time = "2025-08-19T17:21:23.755Z" }, + { url = "https://files.pythonhosted.org/packages/a1/c5/56eca774e9162bc1ce59111d2bd69140dc8908c9478c92ec7bd15d547600/time_machine-2.19.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:2415b7495ec4364c8067071e964fbadfe746dd4cdb43983f2f0bd6ebed13315c", size = 39270, upload-time = "2025-08-19T17:21:26.009Z" }, + { url = "https://files.pythonhosted.org/packages/9b/69/5dd0c420667578169a12acc8c8fd7452e8cfb181e41c9b4ac7e88fa36686/time_machine-2.19.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dbfc6b90c10f288594e1bf89a728a98cc0030791fd73541bbdc6b090aff83143", size = 40193, upload-time = "2025-08-19T17:21:27.054Z" }, + { url = "https://files.pythonhosted.org/packages/75/a7/de974d421bd55c9355583427c2a38fb0237bb5fd6614af492ba89dacb2f9/time_machine-2.19.0-cp313-cp313t-win32.whl", hash = "sha256:16f5d81f650c0a4d117ab08036dc30b5f8b262e11a4a0becc458e7f1c011b228", size = 17542, upload-time = "2025-08-19T17:21:28.674Z" }, + { url = "https://files.pythonhosted.org/packages/76/0a/aa0d05becd5d06ae8d3f16d657dc8cc9400c8d79aef80299de196467ff12/time_machine-2.19.0-cp313-cp313t-win_amd64.whl", hash = "sha256:645699616ec14e147094f601e6ab9553ff6cea37fad9c42720a6d7ed04bcd5dc", size = 18703, upload-time = "2025-08-19T17:21:29.663Z" }, + { url = "https://files.pythonhosted.org/packages/1f/c0/f785a4c7c73aa176510f7c48b84b49c26be84af0d534deb222e0327f750e/time_machine-2.19.0-cp313-cp313t-win_arm64.whl", hash = "sha256:b32daa965d13237536ea3afaa5ad61ade2b2d9314bc3a20196a0d2e1d7b57c6a", size = 17020, upload-time = "2025-08-19T17:21:30.653Z" }, + { url = "https://files.pythonhosted.org/packages/ed/97/c5fb51def06c0b2b6735332ad118ab35b4d9b85368792e5b638e99b1b686/time_machine-2.19.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:31cb43c8fd2d961f31bed0ff4e0026964d2b35e5de9e0fabbfecf756906d3612", size = 19360, upload-time = "2025-08-19T17:21:31.94Z" }, + { url = "https://files.pythonhosted.org/packages/2d/4e/2d795f7d6b7f5205ffe737a05bb1cf19d8038233b797062b2ef412b8512b/time_machine-2.19.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:bdf481a75afc6bff3e520db594501975b652f7def21cd1de6aa971d35ba644e6", size = 15033, upload-time = "2025-08-19T17:21:32.934Z" }, + { url = "https://files.pythonhosted.org/packages/dd/32/9bad501e360b4e758c58fae616ca5f8c7ad974b343f2463a15b2bf77a366/time_machine-2.19.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:00bee4bb950ac6a08d62af78e4da0cf2b4fc2abf0de2320d0431bf610db06e7c", size = 33379, upload-time = "2025-08-19T17:21:33.925Z" }, + { url = "https://files.pythonhosted.org/packages/a3/45/eda0ca4d793dfd162478d6163759b1c6ce7f6e61daa7fd7d62b31f21f87f/time_machine-2.19.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9f02199490906582302ce09edd32394fb393271674c75d7aa76c7a3245f16003", size = 35123, upload-time = "2025-08-19T17:21:34.945Z" }, + { url = "https://files.pythonhosted.org/packages/f0/5a/97e16325442ae5731fcaac794f0a1ef9980eff8a5491e58201d7eb814a34/time_machine-2.19.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e35726c7ba625f844c13b1fc0d4f81f394eefaee1d3a094a9093251521f2ef15", size = 36588, upload-time = "2025-08-19T17:21:35.975Z" }, + { url = "https://files.pythonhosted.org/packages/e8/9d/bf0b2ccc930cc4a316f26f1c78d3f313cd0fa13bb7480369b730a8f129db/time_machine-2.19.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:304315023999cd401ff02698870932b893369e1cfeb2248d09f6490507a92e97", size = 35013, upload-time = "2025-08-19T17:21:37.017Z" }, + { url = "https://files.pythonhosted.org/packages/f0/5a/39ac6a3078174f9715d88364871348b249631f12e76de1b862433b3f8862/time_machine-2.19.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:9765d4f003f263ea8bfd90d2d15447ca4b3dfa181922cf6cf808923b02ac180a", size = 33303, upload-time = "2025-08-19T17:21:38.352Z" }, + { url = "https://files.pythonhosted.org/packages/b3/ac/d8646baf9f95f2e792a6d7a7b35e92fca253c4a992afff801beafae0e5c2/time_machine-2.19.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7837ef3fd5911eb9b480909bb93d922737b6bdecea99dfcedb0a03807de9b2d3", size = 34440, upload-time = "2025-08-19T17:21:39.382Z" }, + { url = "https://files.pythonhosted.org/packages/ce/8b/8b6568c5ae966d80ead03ab537be3c6acf2af06fb501c2d466a3162c6295/time_machine-2.19.0-cp314-cp314-win32.whl", hash = "sha256:4bb5bd43b1bdfac3007b920b51d8e761f024ed465cfeec63ac4296922a4ec428", size = 17162, upload-time = "2025-08-19T17:21:40.381Z" }, + { url = "https://files.pythonhosted.org/packages/46/a5/211c1ab4566eba5308b2dc001b6349e3a032e3f6afa67ca2f27ea6b27af5/time_machine-2.19.0-cp314-cp314-win_amd64.whl", hash = "sha256:f583bbd0aa8ab4a7c45a684bf636d9e042d466e30bcbae1d13e7541e2cbe7207", size = 18040, upload-time = "2025-08-19T17:21:41.363Z" }, + { url = "https://files.pythonhosted.org/packages/b8/fc/4c2fb705f6371cb83824da45a8b967514a922fc092a0ef53979334d97a70/time_machine-2.19.0-cp314-cp314-win_arm64.whl", hash = "sha256:f379c6f8a6575a8284592179cf528ce89373f060301323edcc44f1fa1d37be12", size = 16752, upload-time = "2025-08-19T17:21:42.336Z" }, + { url = "https://files.pythonhosted.org/packages/79/ab/6437d18f31c666b5116c97572a282ac2590a82a0a9867746a6647eaf4613/time_machine-2.19.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:a3b8981f9c663b0906b05ab4d0ca211fae4b63b47c6ec26de5374fe56c836162", size = 20057, upload-time = "2025-08-19T17:21:43.35Z" }, + { url = "https://files.pythonhosted.org/packages/6c/a2/e03639ec2ba7200328bbcad8a2b2b1d5fccca9cceb9481b164a1cabdcb33/time_machine-2.19.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8e9c6363893e7f52c226afbebb23e825259222d100e67dfd24c8a6d35f1a1907", size = 15430, upload-time = "2025-08-19T17:21:44.725Z" }, + { url = "https://files.pythonhosted.org/packages/5d/ff/39e63a48e840f3e36ce24846ee51dd99c6dba635659b1750a2993771e88e/time_machine-2.19.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:206fcd6c9a6f00cac83db446ad1effc530a8cec244d2780af62db3a2d0a9871b", size = 39622, upload-time = "2025-08-19T17:21:45.821Z" }, + { url = "https://files.pythonhosted.org/packages/9a/2e/ee5ac79c4954768705801e54817c7d58e07e25a0bb227e775f501f3e2122/time_machine-2.19.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bf33016a1403c123373ffaeff25e26e69d63bf2c63b6163932efed94160db7ef", size = 41235, upload-time = "2025-08-19T17:21:46.783Z" }, + { url = "https://files.pythonhosted.org/packages/3a/3e/9af5f39525e779185c77285b8bbae15340eeeaa0afb33d458bc8b47d459b/time_machine-2.19.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9247c4bb9bbd3ff584ef4efbdec8efd9f37aa08bcfc4728bde1e489c2cb445bd", size = 44276, upload-time = "2025-08-19T17:21:47.759Z" }, + { url = "https://files.pythonhosted.org/packages/59/fe/572c7443cc27140bbeae3947279bbd4a120f9e8622253a20637f260b7813/time_machine-2.19.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:77f9bb0b86758d1f2d9352642c874946ad5815df53ef4ca22eb9d532179fe50d", size = 42330, upload-time = "2025-08-19T17:21:48.881Z" }, + { url = "https://files.pythonhosted.org/packages/cf/24/1a81c2e08ee7dae13ec8ceed27a29afa980c3d63852e42f1e023bf0faa03/time_machine-2.19.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:0b529e262df3b9c449f427385f4d98250828c879168c2e00eec844439f40b370", size = 39281, upload-time = "2025-08-19T17:21:49.907Z" }, + { url = "https://files.pythonhosted.org/packages/d2/60/6f0d6e5108978ca1a2a4ffb4d1c7e176d9199bb109fd44efe2680c60b52a/time_machine-2.19.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9199246e31cdc810e5d89cb71d09144c4d745960fdb0824da4994d152aca3303", size = 40201, upload-time = "2025-08-19T17:21:50.953Z" }, + { url = "https://files.pythonhosted.org/packages/73/b9/3ea4951e8293b0643feb98c0b9a176fa822154f1810835db3f282968ab10/time_machine-2.19.0-cp314-cp314t-win32.whl", hash = "sha256:0fe81bae55b7aefc2c2a34eb552aa82e6c61a86b3353a3c70df79b9698cb02ca", size = 17743, upload-time = "2025-08-19T17:21:51.948Z" }, + { url = "https://files.pythonhosted.org/packages/e4/8b/cd802884ca8a98e2b6cdc2397d57dd12ff8a7d1481e06fc3fad3d4e7e5ff/time_machine-2.19.0-cp314-cp314t-win_amd64.whl", hash = "sha256:7253791b8d7e7399fbeed7a8193cb01bc004242864306288797056badbdaf80b", size = 18956, upload-time = "2025-08-19T17:21:52.997Z" }, + { url = "https://files.pythonhosted.org/packages/c6/49/cabb1593896082fd55e34768029b8b0ca23c9be8b2dc127e0fc14796d33e/time_machine-2.19.0-cp314-cp314t-win_arm64.whl", hash = "sha256:536bd1ac31ab06a1522e7bf287602188f502dc19d122b1502c4f60b1e8efac79", size = 17068, upload-time = "2025-08-19T17:21:54.064Z" }, + { url = "https://files.pythonhosted.org/packages/d6/05/0608376c3167afe6cf7cdfd2b05c142ea4c42616eee9ba06d1799965806a/time_machine-2.19.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d8bb00b30ec9fe56d01e9812df1ffe39f331437cef9bfaebcc81c83f7f8f8ee2", size = 19659, upload-time = "2025-08-19T17:21:55.426Z" }, + { url = "https://files.pythonhosted.org/packages/11/c4/72eb8c7b36830cf36c51d7bc2f1ac313d68881c3a58040fb6b42c4523d20/time_machine-2.19.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d821c60efc08a97cc11e5482798e6fd5eba5c0f22a02db246b50895dbdc0de41", size = 15153, upload-time = "2025-08-19T17:21:56.505Z" }, + { url = "https://files.pythonhosted.org/packages/89/1a/0782e1f5c8ab8809ebd992709e1bb69d67600191baa023af7a5d32023a3c/time_machine-2.19.0-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:fb051aec7b3b6e96a200d911c225901e6133ff3da11e470e24111a53bbc13637", size = 32555, upload-time = "2025-08-19T17:21:57.74Z" }, + { url = "https://files.pythonhosted.org/packages/94/b0/8ef58e2f6321851d5900ca3d18044938832c2ed42a2ac7570ca6aa29768a/time_machine-2.19.0-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fe59909d95a2ef5e01ce3354fdea3908404c2932c2069f00f66dff6f27e9363e", size = 34185, upload-time = "2025-08-19T17:21:59.361Z" }, + { url = "https://files.pythonhosted.org/packages/82/74/ce0c9867f788c1fb22c417ec1aae47a24117e53d51f6ff97d7c6ca5392f6/time_machine-2.19.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:29e84b8682645b16eb6f9e8ec11c35324ad091841a11cf4fc3fc7f6119094c89", size = 35917, upload-time = "2025-08-19T17:22:00.421Z" }, + { url = "https://files.pythonhosted.org/packages/d2/70/6f97a8f552dbaa66feb10170b5726dab74bc531673d1ed9d6f271547e54c/time_machine-2.19.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4a11f1c0e0d06023dc01614c964e256138913551d3ae6dca5148f79081156336", size = 34584, upload-time = "2025-08-19T17:22:01.447Z" }, + { url = "https://files.pythonhosted.org/packages/48/c8/cf139088ce537c15d7f03cf56ec317d3a5cfb520e30aa711ea0248d0ae8a/time_machine-2.19.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:57a235a6307c54df50e69f1906e2f199e47da91bde4b886ee05aff57fe4b6bf6", size = 32608, upload-time = "2025-08-19T17:22:02.548Z" }, + { url = "https://files.pythonhosted.org/packages/b1/17/0ec41ef7a30c6753fb226a28b74162b264b35724905ced4098f2f5076ded/time_machine-2.19.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:426aba552f7af9604adad9ef570c859af7c1081d878db78089fac159cd911b0a", size = 33686, upload-time = "2025-08-19T17:22:03.606Z" }, + { url = "https://files.pythonhosted.org/packages/b0/19/586f15159083ec84f178d494c60758c46603b00c9641b04deb63f1950128/time_machine-2.19.0-cp39-cp39-win32.whl", hash = "sha256:67772c7197a3a712d1b970ed545c6e98db73524bd90e245fd3c8fa7ad7630768", size = 17133, upload-time = "2025-08-19T17:22:04.989Z" }, + { url = "https://files.pythonhosted.org/packages/6a/c2/bfe4b906a9fe0bf2d011534314212ed752d6b8f392c9c82f6ac63dccc5ab/time_machine-2.19.0-cp39-cp39-win_amd64.whl", hash = "sha256:011d7859089263204dc5fdf83dce7388f986fe833c9381d6106b4edfda2ebd3e", size = 17972, upload-time = "2025-08-19T17:22:06.026Z" }, + { url = "https://files.pythonhosted.org/packages/5d/73/182343eba05aa5787732aaa68f3b3feb5e40ddf86b928ae941be45646393/time_machine-2.19.0-cp39-cp39-win_arm64.whl", hash = "sha256:e1af66550fa4685434f00002808a525f176f1f92746646c0019bb86fbff48b27", size = 16820, upload-time = "2025-08-19T17:22:07.227Z" }, +] + +[[package]] +name = "time-machine" +version = "3.2.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.14' and extra != 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2'", + "python_full_version >= '3.10' and python_full_version < '3.14' and extra != 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2'", + "python_full_version >= '3.10' and extra == 'group-10-cloudflare-pydantic-v1' and extra != 'group-10-cloudflare-pydantic-v2'", + "python_full_version >= '3.10' and extra != 'group-10-cloudflare-pydantic-v1' and extra != 'group-10-cloudflare-pydantic-v2'", +] +sdist = { url = "https://files.pythonhosted.org/packages/02/fc/37b02f6094dbb1f851145330460532176ed2f1dc70511a35828166c41e52/time_machine-3.2.0.tar.gz", hash = "sha256:a4ddd1cea17b8950e462d1805a42b20c81eb9aafc8f66b392dd5ce997e037d79", size = 14804, upload-time = "2025-12-17T23:33:02.599Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9c/31/6bf41cb4a326230518d9b76c910dfc11d4fc23444d1cbfdf2d7652bd99f4/time_machine-3.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:68142c070e78b62215d8029ec7394905083a4f9aacb0a2a11514ce70b5951b13", size = 19447, upload-time = "2025-12-17T23:31:30.181Z" }, + { url = "https://files.pythonhosted.org/packages/fa/14/d71ce771712e1cbfa15d8c24452225109262b16cb6caaf967e9f60662b67/time_machine-3.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:161bbd0648802ffdfcb4bb297ecb26b3009684a47d3a4dedb90bc549df4fa2ad", size = 15432, upload-time = "2025-12-17T23:31:31.381Z" }, + { url = "https://files.pythonhosted.org/packages/8b/d6/dcb43a11f8029561996fad58ff9d3dc5e6d7f32b74f0745a2965d7e4b4f3/time_machine-3.2.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1359ba8c258be695ba69253bc84db882fd616fe69b426cc6056536da2c7bf68e", size = 32956, upload-time = "2025-12-17T23:31:32.469Z" }, + { url = "https://files.pythonhosted.org/packages/77/da/d802cd3c335c414f9b11b479f7459aa72df5de6485c799966cfdf8856d53/time_machine-3.2.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c85b169998ca2c24a78fb214586ec11c4cad56d9c38f55ad8326235cb481c884", size = 34556, upload-time = "2025-12-17T23:31:33.946Z" }, + { url = "https://files.pythonhosted.org/packages/85/ee/51ad553514ab0b940c7c82c6e1519dd10fd06ac07b32039a1d153ef09c88/time_machine-3.2.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:65b9367cb8a10505bc8f67da0da514ba20fa816fc47e11f434f7c60350322b4c", size = 36101, upload-time = "2025-12-17T23:31:35.462Z" }, + { url = "https://files.pythonhosted.org/packages/11/39/938b111b5bb85a2b07502d0f9d8a704fc75bd760d62e76bce23c89ed16c9/time_machine-3.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9faca6a0f1973d7df3233c951fc2a11ff0c54df74087d8aaf41ae3deb19d0893", size = 34905, upload-time = "2025-12-17T23:31:36.543Z" }, + { url = "https://files.pythonhosted.org/packages/dd/50/0951f73b23e76455de0b4a3a58ac5a24bd8d10489624b1c5e03f10c6fc0b/time_machine-3.2.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:213b1ada7f385d467e598999b642eda4a8e89ae10ad5dc4f5d8f672cbf604261", size = 33012, upload-time = "2025-12-17T23:31:37.967Z" }, + { url = "https://files.pythonhosted.org/packages/4f/95/5304912d3dcecc4e14ed222dbe0396352efdf8497534abc3c9edd67a7528/time_machine-3.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:160b6afd94c39855af04d39c58e4cf602406abd6d79427ab80e830ea71789cfb", size = 34104, upload-time = "2025-12-17T23:31:39.449Z" }, + { url = "https://files.pythonhosted.org/packages/d4/1c/af56518652ec7adac4ced193b7a42c4ff354fef28a412b3b5ffa5763aead/time_machine-3.2.0-cp310-cp310-win32.whl", hash = "sha256:c15d9ac257c78c124d112e4fc91fa9f3dcb004bdda913c19f0e7368d713cf080", size = 17468, upload-time = "2025-12-17T23:31:40.432Z" }, + { url = "https://files.pythonhosted.org/packages/48/15/0213f00ca3cf6fe1c9fdbd7fd467e801052fc85534f30c0e4684bd474190/time_machine-3.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:3bf0f428487f93b8fe9d27aa01eccc817885da3290b467341b4a4a795e1d1891", size = 18313, upload-time = "2025-12-17T23:31:41.617Z" }, + { url = "https://files.pythonhosted.org/packages/77/e4/811f96aa7a634b2b264d9a476f3400e710744dda503b4ad87a5c76db32c9/time_machine-3.2.0-cp310-cp310-win_arm64.whl", hash = "sha256:347f6be2129fcd35b1c94b9387fcb2cbe7949b1e649228c5f22949a811b78976", size = 17037, upload-time = "2025-12-17T23:31:42.924Z" }, + { url = "https://files.pythonhosted.org/packages/f5/e1/03aae5fbaa53859f665094af696338fc7cae733d926a024af69982712350/time_machine-3.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c188a9dda9fcf975022f1b325b466651b96a4dfc223c523ed7ed8d979f9bf3e8", size = 19143, upload-time = "2025-12-17T23:31:44.258Z" }, + { url = "https://files.pythonhosted.org/packages/75/8f/98cb17bebb52b22ff4ec26984dd44280f9c71353c3bae0640a470e6683e5/time_machine-3.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:17245f1cc2dd13f9d63a174be59bb2684a9e5e0a112ab707e37be92068cd655f", size = 15273, upload-time = "2025-12-17T23:31:45.246Z" }, + { url = "https://files.pythonhosted.org/packages/dd/2f/ca11e4a7897234bb9331fcc5f4ed4714481ba4012370cc79a0ae8c42ea0a/time_machine-3.2.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d9bd1de1996e76efd36ae15970206c5089fb3728356794455bd5cd8d392b5537", size = 31049, upload-time = "2025-12-17T23:31:46.613Z" }, + { url = "https://files.pythonhosted.org/packages/cf/ad/d17d83a59943094e6b6c6a3743caaf6811b12203c3e07a30cc7bcc2ab7ee/time_machine-3.2.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:98493cd50e8b7f941eab69b9e18e697ad69db1a0ec1959f78f3d7b0387107e5c", size = 32632, upload-time = "2025-12-17T23:31:47.72Z" }, + { url = "https://files.pythonhosted.org/packages/71/50/d60576d047a0dfb5638cdfb335e9c3deb6e8528544fa0b3966a8480f72b7/time_machine-3.2.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:31f2a33d595d9f91eb9bc7f157f0dc5721f5789f4c4a9e8b852cdedb2a7d9b16", size = 34289, upload-time = "2025-12-17T23:31:48.913Z" }, + { url = "https://files.pythonhosted.org/packages/fa/fe/4afa602dbdebddde6d0ea4a7fe849e49b9bb85dc3fb415725a87ccb4b471/time_machine-3.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9f78ac4213c10fbc44283edd1a29cfb7d3382484f4361783ddc057292aaa1889", size = 33175, upload-time = "2025-12-17T23:31:50.611Z" }, + { url = "https://files.pythonhosted.org/packages/0d/87/c152e23977c1d7d7c94eb3ed3ea45cc55971796205125c6fdff40db2c60f/time_machine-3.2.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c1326b09e947b360926d529a96d1d9e126ce120359b63b506ecdc6ee20755c23", size = 31170, upload-time = "2025-12-17T23:31:51.645Z" }, + { url = "https://files.pythonhosted.org/packages/80/af/54acf51d0f3ade3b51eab73df6192937c9a938753ef5456dff65eb8630be/time_machine-3.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9f2949f03d15264cc15c38918a2cda8966001f0f4ebe190cbfd9c56d91aed8ac", size = 32292, upload-time = "2025-12-17T23:31:52.803Z" }, + { url = "https://files.pythonhosted.org/packages/cc/bc/3745963f36e75661a807196428639327a366f4332f35f1f775c074d4062f/time_machine-3.2.0-cp311-cp311-win32.whl", hash = "sha256:6dfe48e0499e6e16751476b9799e67be7514e6ef04cdf39571ef95a279645831", size = 17349, upload-time = "2025-12-17T23:31:54.19Z" }, + { url = "https://files.pythonhosted.org/packages/82/a2/057469232a99d1f5a0160ae7c5bae7b095c9168b333dd598fcbcfbc1c87b/time_machine-3.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:809bdf267a29189c304154873620fe0bcc0c9513295fa46b19e21658231c4915", size = 18191, upload-time = "2025-12-17T23:31:55.472Z" }, + { url = "https://files.pythonhosted.org/packages/79/d8/bf9c8de57262ee7130d92a6ed49ed6a6e40a36317e46979428d373630c12/time_machine-3.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:a3f4c17fa90f54902a3f8692c75caf67be87edc3429eeb71cb4595da58198f8e", size = 16905, upload-time = "2025-12-17T23:31:56.658Z" }, + { url = "https://files.pythonhosted.org/packages/71/8b/080c8eedcd67921a52ba5bd0e075362062509ab63c86fc1a0442fad241a6/time_machine-3.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:cc4bee5b0214d7dc4ebc91f4a4c600f1a598e9b5606ac751f42cb6f6740b1dbb", size = 19255, upload-time = "2025-12-17T23:31:58.057Z" }, + { url = "https://files.pythonhosted.org/packages/66/17/0e5291e9eb705bf8a5a1305f826e979af307bbeb79def4ddbf4b3f9a81e0/time_machine-3.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3ca036304b4460ae2fdc1b52dd8b1fa7cf1464daa427fc49567413c09aa839c1", size = 15360, upload-time = "2025-12-17T23:31:59.048Z" }, + { url = "https://files.pythonhosted.org/packages/8b/e8/9ab87b71d2e2b62463b9b058b7ae7ac09fb57f8fcd88729dec169d304340/time_machine-3.2.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5442735b41d7a2abc2f04579b4ca6047ed4698a8338a4fec92c7c9423e7938cb", size = 33029, upload-time = "2025-12-17T23:32:00.413Z" }, + { url = "https://files.pythonhosted.org/packages/4b/26/b5ca19da6f25ea905b3e10a0ea95d697c1aeba0404803a43c68f1af253e6/time_machine-3.2.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:97da3e971e505cb637079fb07ab0bcd36e33279f8ecac888ff131f45ef1e4d8d", size = 34579, upload-time = "2025-12-17T23:32:01.431Z" }, + { url = "https://files.pythonhosted.org/packages/79/ca/6ac7ad5f10ea18cc1d9de49716ba38c32132c7b64532430d92ef240c116b/time_machine-3.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3cdda6dee4966e38aeb487309bb414c6cb23a81fc500291c77a8fcd3098832e7", size = 35961, upload-time = "2025-12-17T23:32:02.521Z" }, + { url = "https://files.pythonhosted.org/packages/33/67/390dd958bed395ab32d79a9fe61fe111825c0dd4ded54dbba7e867f171e6/time_machine-3.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:33d9efd302a6998bcc8baa4d84f259f8a4081105bd3d7f7af7f1d0abd3b1c8aa", size = 34668, upload-time = "2025-12-17T23:32:03.585Z" }, + { url = "https://files.pythonhosted.org/packages/da/57/c88fff034a4e9538b3ae7c68c9cfb283670b14d17522c5a8bc17d29f9a4b/time_machine-3.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3a0b0a33971f14145853c9bd95a6ab0353cf7e0019fa2a7aa1ae9fddfe8eab50", size = 32891, upload-time = "2025-12-17T23:32:04.656Z" }, + { url = "https://files.pythonhosted.org/packages/2d/70/ebbb76022dba0fec8f9156540fc647e4beae1680c787c01b1b6200e56d70/time_machine-3.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2d0be9e5f22c38082d247a2cdcd8a936504e9db60b7b3606855fb39f299e9548", size = 34080, upload-time = "2025-12-17T23:32:06.146Z" }, + { url = "https://files.pythonhosted.org/packages/db/9a/2ca9e7af3df540dc1c79e3de588adeddb7dcc2107829248e6969c4f14167/time_machine-3.2.0-cp312-cp312-win32.whl", hash = "sha256:3f74623648b936fdce5f911caf386c0a0b579456410975de8c0dfeaaffece1d8", size = 17371, upload-time = "2025-12-17T23:32:07.164Z" }, + { url = "https://files.pythonhosted.org/packages/d8/ce/21d23efc9c2151939af1b7ee4e60d86d661b74ef32b8eaa148f6fe8c899c/time_machine-3.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:34e26a41d994b5e4b205136a90e9578470386749cc9a2ecf51ca18f83ce25e23", size = 18132, upload-time = "2025-12-17T23:32:08.447Z" }, + { url = "https://files.pythonhosted.org/packages/2f/34/c2b70be483accf6db9e5d6c3139bce3c38fe51f898ccf64e8d3fe14fbf4d/time_machine-3.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:0615d3d82c418d6293f271c348945c5091a71f37e37173653d5c26d0e74b13a8", size = 16930, upload-time = "2025-12-17T23:32:09.477Z" }, + { url = "https://files.pythonhosted.org/packages/ee/cd/43ad5efc88298af3c59b66769cea7f055567a85071579ed40536188530c1/time_machine-3.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c421a8eb85a4418a7675a41bf8660224318c46cc62e4751c8f1ceca752059090", size = 19318, upload-time = "2025-12-17T23:32:10.518Z" }, + { url = "https://files.pythonhosted.org/packages/b0/f6/084010ef7f4a3f38b5a4900923d7c85b29e797655c4f6ee4ce54d903cca8/time_machine-3.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8f4e758f7727d0058c4950c66b58200c187072122d6f7a98b610530a4233ea7b", size = 15390, upload-time = "2025-12-17T23:32:11.625Z" }, + { url = "https://files.pythonhosted.org/packages/25/aa/1cabb74134f492270dc6860cb7865859bf40ecf828be65972827646e91ad/time_machine-3.2.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:154bd3f75c81f70218b2585cc12b60762fb2665c507eec5ec5037d8756d9b4e0", size = 33115, upload-time = "2025-12-17T23:32:13.219Z" }, + { url = "https://files.pythonhosted.org/packages/5e/03/78c5d7dfa366924eb4dbfcc3fc917c39a4280ca234b12819cc1f16c03d88/time_machine-3.2.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d50cfe5ebea422c896ad8d278af9648412b7533b8ea6adeeee698a3fd9b1d3b7", size = 34705, upload-time = "2025-12-17T23:32:14.29Z" }, + { url = "https://files.pythonhosted.org/packages/86/93/d5e877c24541f674c6869ff6e9c56833369796010190252e92c9d7ae5f0f/time_machine-3.2.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:636576501724bd6a9124e69d86e5aef263479e89ef739c5db361469f0463a0a1", size = 36104, upload-time = "2025-12-17T23:32:15.354Z" }, + { url = "https://files.pythonhosted.org/packages/22/1c/d4bae72f388f67efc9609f89b012e434bb19d9549c7a7b47d6c7d9e5c55d/time_machine-3.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:40e6f40c57197fcf7ec32d2c563f4df0a82c42cdcc3cab27f688e98f6060df10", size = 34765, upload-time = "2025-12-17T23:32:16.434Z" }, + { url = "https://files.pythonhosted.org/packages/1d/c3/ac378cf301d527d8dfad2f0db6bad0dfb1ab73212eaa56d6b96ee5d9d20b/time_machine-3.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a1bcf0b846bbfc19a79bc19e3fa04d8c7b1e8101c1b70340ffdb689cd801ea53", size = 33010, upload-time = "2025-12-17T23:32:17.532Z" }, + { url = "https://files.pythonhosted.org/packages/06/35/7ce897319accda7a6970b288a9a8c52d25227342a7508505a2b3d235b649/time_machine-3.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ae55a56c179f4fe7a62575ad5148b6ed82f6c7e5cf2f9a9ec65f2f5b067db5f5", size = 34185, upload-time = "2025-12-17T23:32:18.566Z" }, + { url = "https://files.pythonhosted.org/packages/bf/28/f922022269749cb02eee2b62919671153c4088994fa955a6b0e50327ff81/time_machine-3.2.0-cp313-cp313-win32.whl", hash = "sha256:a66fe55a107e46916007a391d4030479df8864ec6ad6f6a6528221befc5c886e", size = 17397, upload-time = "2025-12-17T23:32:19.605Z" }, + { url = "https://files.pythonhosted.org/packages/ee/dc/fd87cde397f4a7bea493152f0aca8fd569ec709cad9e0f2ca7011eb8c7f7/time_machine-3.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:30c9ce57165df913e4f74e285a8ab829ff9b7aa3e5ec0973f88f642b9a7b3d15", size = 18139, upload-time = "2025-12-17T23:32:20.991Z" }, + { url = "https://files.pythonhosted.org/packages/75/81/b8ce58233addc5d7d54d2fabc49dcbc02d79e3f079d150aa1bec3d5275ef/time_machine-3.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:89cad7e179e9bdcc84dcf09efe52af232c4cc7a01b3de868356bbd59d95bd9b8", size = 16964, upload-time = "2025-12-17T23:32:22.075Z" }, + { url = "https://files.pythonhosted.org/packages/67/e7/487f0ba5fe6c58186a5e1af2a118dfa2c160fedb37ef53a7e972d410408e/time_machine-3.2.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:59d71545e62525a4b85b6de9ab5c02ee3c61110fd7f636139914a2335dcbfc9c", size = 20000, upload-time = "2025-12-17T23:32:23.058Z" }, + { url = "https://files.pythonhosted.org/packages/e1/17/eb2c0054c8d44dd42df84ccd434539249a9c7d0b8eb53f799be2102500ab/time_machine-3.2.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:999672c621c35362bc28e03ca0c7df21500195540773c25993421fd8d6cc5003", size = 15657, upload-time = "2025-12-17T23:32:24.125Z" }, + { url = "https://files.pythonhosted.org/packages/43/21/93443b5d1dd850f8bb9442e90d817a9033dcce6bfbdd3aabbb9786251c80/time_machine-3.2.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5faf7397f0580c7b9d67288522c8d7863e85f0cffadc0f1fccdb2c3dfce5783e", size = 39216, upload-time = "2025-12-17T23:32:25.542Z" }, + { url = "https://files.pythonhosted.org/packages/9f/9e/18544cf8acc72bb1dc03762231c82ecc259733f4bb6770a7bbe5cd138603/time_machine-3.2.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d3dd886ec49f1fa5a00e844f5947e5c0f98ce574750c24b7424c6f77fc1c3e87", size = 40764, upload-time = "2025-12-17T23:32:26.643Z" }, + { url = "https://files.pythonhosted.org/packages/27/f7/9fe9ce2795636a3a7467307af6bdf38bb613ddb701a8a5cd50ec713beb5e/time_machine-3.2.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:da0ecd96bc7bbe450acaaabe569d84e81688f1be8ad58d1470e42371d145fb53", size = 43526, upload-time = "2025-12-17T23:32:27.693Z" }, + { url = "https://files.pythonhosted.org/packages/03/c1/a93e975ba9dec22e87ec92d18c28e67d36bd536f9119ffa439b2892b0c9c/time_machine-3.2.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:158220e946c1c4fb8265773a0282c88c35a7e3bb5d78e3561214e3b3231166f3", size = 41727, upload-time = "2025-12-17T23:32:28.985Z" }, + { url = "https://files.pythonhosted.org/packages/5f/fb/e3633e5a6bbed1c76bb2e9810dabc2f8467532ffcd29b9aed404b473061a/time_machine-3.2.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:8c1aee29bc54356f248d5d7dfdd131e12ca825e850a08c0ebdb022266d073013", size = 38952, upload-time = "2025-12-17T23:32:30.031Z" }, + { url = "https://files.pythonhosted.org/packages/82/3d/02e9fb2526b3d6b1b45bc8e4d912d95d1cd699d1a3f6df985817d37a0600/time_machine-3.2.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c8ed2224f09d25b1c2fc98683613aca12f90f682a427eabb68fc824d27014e4a", size = 39829, upload-time = "2025-12-17T23:32:31.075Z" }, + { url = "https://files.pythonhosted.org/packages/85/c8/c14265212436da8e0814c45463987b3f57de3eca4de023cc2eabb0c62ef3/time_machine-3.2.0-cp313-cp313t-win32.whl", hash = "sha256:3498719f8dab51da76d29a20c1b5e52ee7db083dddf3056af7fa69c1b94e1fe6", size = 17852, upload-time = "2025-12-17T23:32:32.079Z" }, + { url = "https://files.pythonhosted.org/packages/1d/bc/8acb13cf6149f47508097b158a9a8bec9ec4530a70cb406124e8023581f5/time_machine-3.2.0-cp313-cp313t-win_amd64.whl", hash = "sha256:e0d90bee170b219e1d15e6a58164aa808f5170090e4f090bd0670303e34181b1", size = 18918, upload-time = "2025-12-17T23:32:33.106Z" }, + { url = "https://files.pythonhosted.org/packages/24/87/c443ee508c2708fd2514ccce9052f5e48888783ce690506919629ebc8eb0/time_machine-3.2.0-cp313-cp313t-win_arm64.whl", hash = "sha256:051de220fdb6e20d648111bbad423d9506fdbb2e44d4429cef3dc0382abf1fc2", size = 17261, upload-time = "2025-12-17T23:32:34.446Z" }, + { url = "https://files.pythonhosted.org/packages/61/70/b4b980d126ed155c78d1879c50d60c8dcbd47bd11cb14ee7be50e0dfc07f/time_machine-3.2.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:1398980c017fe5744d66f419e0115ee48a53b00b146d738e1416c225eb610b82", size = 19303, upload-time = "2025-12-17T23:32:35.796Z" }, + { url = "https://files.pythonhosted.org/packages/73/73/eaa33603c69a68fe2b6f54f9dd75481693d62f1d29676531002be06e2d1c/time_machine-3.2.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:4f8f4e35f4191ef70c2ab8ff490761ee9051b891afce2bf86dde3918eb7b537b", size = 15431, upload-time = "2025-12-17T23:32:37.244Z" }, + { url = "https://files.pythonhosted.org/packages/76/10/b81e138e86cc7bab40cdb59d294b341e172201f4a6c84bb0ec080407977a/time_machine-3.2.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6db498686ecf6163c5aa8cf0bcd57bbe0f4081184f247edf3ee49a2612b584f9", size = 33206, upload-time = "2025-12-17T23:32:38.713Z" }, + { url = "https://files.pythonhosted.org/packages/d3/72/4deab446b579e8bd5dca91de98595c5d6bd6a17ce162abf5c5f2ce40d3d8/time_machine-3.2.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:027c1807efb74d0cd58ad16524dec94212fbe900115d70b0123399883657ac0f", size = 34792, upload-time = "2025-12-17T23:32:40.223Z" }, + { url = "https://files.pythonhosted.org/packages/2c/39/439c6b587ddee76d533fe972289d0646e0a5520e14dc83d0a30aeb5565f7/time_machine-3.2.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92432610c05676edd5e6946a073c6f0c926923123ce7caee1018dc10782c713d", size = 36187, upload-time = "2025-12-17T23:32:41.705Z" }, + { url = "https://files.pythonhosted.org/packages/4b/db/2da4368db15180989bab83746a857bde05ad16e78f326801c142bb747a06/time_machine-3.2.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c25586b62480eb77ef3d953fba273209478e1ef49654592cd6a52a68dfe56a67", size = 34855, upload-time = "2025-12-17T23:32:42.817Z" }, + { url = "https://files.pythonhosted.org/packages/88/84/120a431fee50bc4c241425bee4d3a4910df4923b7ab5f7dff1bf0c772f08/time_machine-3.2.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:6bf3a2fa738d15e0b95d14469a0b8ea42635467408d8b490e263d5d45c9a177f", size = 33222, upload-time = "2025-12-17T23:32:43.94Z" }, + { url = "https://files.pythonhosted.org/packages/f9/ea/89cfda82bb8c57ff91bb9a26751aa234d6d90e9b4d5ab0ad9dce0f9f0329/time_machine-3.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ce76b82276d7ad2a66cdc85dad4df19d1422b69183170a34e8fbc4c3f35502f7", size = 34270, upload-time = "2025-12-17T23:32:45.037Z" }, + { url = "https://files.pythonhosted.org/packages/8a/aa/235357da4f69a51a8d35fcbfcfa77cdc7dc24f62ae54025006570bda7e2d/time_machine-3.2.0-cp314-cp314-win32.whl", hash = "sha256:14d6778273c543441863dff712cd1d7803dee946b18de35921eb8df10714539d", size = 17544, upload-time = "2025-12-17T23:32:46.099Z" }, + { url = "https://files.pythonhosted.org/packages/7b/51/6c8405a7276be79693b792cff22ce41067ec05db26a7d02f2d5b06324434/time_machine-3.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:cbf821da96dbc80d349fa9e7c36e670b41d68a878d28c8850057992fed430eef", size = 18423, upload-time = "2025-12-17T23:32:47.468Z" }, + { url = "https://files.pythonhosted.org/packages/d9/03/a3cf419e20c35fc203c6e4fed48b5b667c1a2b4da456d9971e605f73ecef/time_machine-3.2.0-cp314-cp314-win_arm64.whl", hash = "sha256:71c75d71f8e68abc8b669bca26ed2ddd558430a6c171e32b8620288565f18c0e", size = 17050, upload-time = "2025-12-17T23:32:48.91Z" }, + { url = "https://files.pythonhosted.org/packages/86/a1/142de946dc4393f910bf4564b5c3ba819906e1f49b06c9cb557519c849e4/time_machine-3.2.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:4e374779021446fc2b5c29d80457ec9a3b1a5df043dc2aae07d7c1415d52323c", size = 19991, upload-time = "2025-12-17T23:32:49.933Z" }, + { url = "https://files.pythonhosted.org/packages/ee/62/7f17def6289901f94726921811a16b9adce46e666362c75d45730c60274f/time_machine-3.2.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:122310a6af9c36e9a636da32830e591e7923e8a07bdd0a43276c3a36c6821c90", size = 15707, upload-time = "2025-12-17T23:32:50.969Z" }, + { url = "https://files.pythonhosted.org/packages/5d/d3/3502fb9bd3acb159c18844b26c43220201a0d4a622c0c853785d07699a92/time_machine-3.2.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ba3eeb0f018cc362dd8128befa3426696a2e16dd223c3fb695fde184892d4d8c", size = 39207, upload-time = "2025-12-17T23:32:52.033Z" }, + { url = "https://files.pythonhosted.org/packages/5a/be/8b27f4aa296fda14a5a2ad7f588ddd450603c33415ab3f8e85b2f1a44678/time_machine-3.2.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:77d38ba664b381a7793f8786efc13b5004f0d5f672dae814430445b8202a67a6", size = 40764, upload-time = "2025-12-17T23:32:53.167Z" }, + { url = "https://files.pythonhosted.org/packages/42/cd/fe4c4e5c8ab6d48fab3624c32be9116fb120173a35fe67e482e5cf68b3d2/time_machine-3.2.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f09abeb8f03f044d72712207e0489a62098ad3ad16dac38927fcf80baca4d6a7", size = 43508, upload-time = "2025-12-17T23:32:54.597Z" }, + { url = "https://files.pythonhosted.org/packages/b4/28/5a3ba2fce85b97655a425d6bb20a441550acd2b304c96b2c19d3839f721a/time_machine-3.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6b28367ce4f73987a55e230e1d30a57a3af85da8eb1a140074eb6e8c7e6ef19f", size = 41712, upload-time = "2025-12-17T23:32:55.781Z" }, + { url = "https://files.pythonhosted.org/packages/81/58/e38084be7fdabb4835db68a3a47e58c34182d79fc35df1ecbe0db2c5359f/time_machine-3.2.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:903c7751c904581da9f7861c3015bed7cdc40047321291d3694a3cdc783bbca3", size = 38939, upload-time = "2025-12-17T23:32:56.867Z" }, + { url = "https://files.pythonhosted.org/packages/40/d0/ad3feb0a392ef4e0c08bc32024950373ddc0669002cbdcbb9f3bf0c2d114/time_machine-3.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:528217cad85ede5f85c8bc78b0341868d3c3cfefc6ecb5b622e1cacb6c73247b", size = 39837, upload-time = "2025-12-17T23:32:58.283Z" }, + { url = "https://files.pythonhosted.org/packages/5b/9e/5f4b2ea63b267bd78f3245e76f5528836611b5f2d30b5e7300a722fe4428/time_machine-3.2.0-cp314-cp314t-win32.whl", hash = "sha256:75724762ffd517e7e80aaec1fad1ff5a7414bd84e2b3ee7a0bacfeb67c14926e", size = 18091, upload-time = "2025-12-17T23:32:59.403Z" }, + { url = "https://files.pythonhosted.org/packages/39/6f/456b1f4d2700ae02b19eba830f870596a4b89b74bac3b6c80666f1b108c5/time_machine-3.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2526abbd053c5bca898d1b3e7898eec34626b12206718d8c7ce88fd12c1c9c5c", size = 19208, upload-time = "2025-12-17T23:33:00.488Z" }, + { url = "https://files.pythonhosted.org/packages/2f/22/8063101427ecd3d2652aada4d21d0876b07a3dc789125bca2ee858fec3ed/time_machine-3.2.0-cp314-cp314t-win_arm64.whl", hash = "sha256:7f2fb6784b414edbe2c0b558bfaab0c251955ba27edd62946cce4a01675a992c", size = 17359, upload-time = "2025-12-17T23:33:01.54Z" }, +] + +[[package]] +name = "tomli" +version = "2.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/22/de/48c59722572767841493b26183a0d1cc411d54fd759c5607c4590b6563a6/tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f", size = 17543, upload-time = "2026-03-25T20:22:03.828Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/11/db3d5885d8528263d8adc260bb2d28ebf1270b96e98f0e0268d32b8d9900/tomli-2.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f8f0fc26ec2cc2b965b7a3b87cd19c5c6b8c5e5f436b984e85f486d652285c30", size = 154704, upload-time = "2026-03-25T20:21:10.473Z" }, + { url = "https://files.pythonhosted.org/packages/6d/f7/675db52c7e46064a9aa928885a9b20f4124ecb9bc2e1ce74c9106648d202/tomli-2.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ab97e64ccda8756376892c53a72bd1f964e519c77236368527f758fbc36a53a", size = 149454, upload-time = "2026-03-25T20:21:12.036Z" }, + { url = "https://files.pythonhosted.org/packages/61/71/81c50943cf953efa35bce7646caab3cf457a7d8c030b27cfb40d7235f9ee/tomli-2.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96481a5786729fd470164b47cdb3e0e58062a496f455ee41b4403be77cb5a076", size = 237561, upload-time = "2026-03-25T20:21:13.098Z" }, + { url = "https://files.pythonhosted.org/packages/48/c1/f41d9cb618acccca7df82aaf682f9b49013c9397212cb9f53219e3abac37/tomli-2.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a881ab208c0baf688221f8cecc5401bd291d67e38a1ac884d6736cbcd8247e9", size = 243824, upload-time = "2026-03-25T20:21:14.569Z" }, + { url = "https://files.pythonhosted.org/packages/22/e4/5a816ecdd1f8ca51fb756ef684b90f2780afc52fc67f987e3c61d800a46d/tomli-2.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47149d5bd38761ac8be13a84864bf0b7b70bc051806bc3669ab1cbc56216b23c", size = 242227, upload-time = "2026-03-25T20:21:15.712Z" }, + { url = "https://files.pythonhosted.org/packages/6b/49/2b2a0ef529aa6eec245d25f0c703e020a73955ad7edf73e7f54ddc608aa5/tomli-2.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ec9bfaf3ad2df51ace80688143a6a4ebc09a248f6ff781a9945e51937008fcbc", size = 247859, upload-time = "2026-03-25T20:21:17.001Z" }, + { url = "https://files.pythonhosted.org/packages/83/bd/6c1a630eaca337e1e78c5903104f831bda934c426f9231429396ce3c3467/tomli-2.4.1-cp311-cp311-win32.whl", hash = "sha256:ff2983983d34813c1aeb0fa89091e76c3a22889ee83ab27c5eeb45100560c049", size = 97204, upload-time = "2026-03-25T20:21:18.079Z" }, + { url = "https://files.pythonhosted.org/packages/42/59/71461df1a885647e10b6bb7802d0b8e66480c61f3f43079e0dcd315b3954/tomli-2.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:5ee18d9ebdb417e384b58fe414e8d6af9f4e7a0ae761519fb50f721de398dd4e", size = 108084, upload-time = "2026-03-25T20:21:18.978Z" }, + { url = "https://files.pythonhosted.org/packages/b8/83/dceca96142499c069475b790e7913b1044c1a4337e700751f48ed723f883/tomli-2.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:c2541745709bad0264b7d4705ad453b76ccd191e64aa6f0fc66b69a293a45ece", size = 95285, upload-time = "2026-03-25T20:21:20.309Z" }, + { url = "https://files.pythonhosted.org/packages/c1/ba/42f134a3fe2b370f555f44b1d72feebb94debcab01676bf918d0cb70e9aa/tomli-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a", size = 155924, upload-time = "2026-03-25T20:21:21.626Z" }, + { url = "https://files.pythonhosted.org/packages/dc/c7/62d7a17c26487ade21c5422b646110f2162f1fcc95980ef7f63e73c68f14/tomli-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085", size = 150018, upload-time = "2026-03-25T20:21:23.002Z" }, + { url = "https://files.pythonhosted.org/packages/5c/05/79d13d7c15f13bdef410bdd49a6485b1c37d28968314eabee452c22a7fda/tomli-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9", size = 244948, upload-time = "2026-03-25T20:21:24.04Z" }, + { url = "https://files.pythonhosted.org/packages/10/90/d62ce007a1c80d0b2c93e02cab211224756240884751b94ca72df8a875ca/tomli-2.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5", size = 253341, upload-time = "2026-03-25T20:21:25.177Z" }, + { url = "https://files.pythonhosted.org/packages/1a/7e/caf6496d60152ad4ed09282c1885cca4eea150bfd007da84aea07bcc0a3e/tomli-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585", size = 248159, upload-time = "2026-03-25T20:21:26.364Z" }, + { url = "https://files.pythonhosted.org/packages/99/e7/c6f69c3120de34bbd882c6fba7975f3d7a746e9218e56ab46a1bc4b42552/tomli-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1", size = 253290, upload-time = "2026-03-25T20:21:27.46Z" }, + { url = "https://files.pythonhosted.org/packages/d6/2f/4a3c322f22c5c66c4b836ec58211641a4067364f5dcdd7b974b4c5da300c/tomli-2.4.1-cp312-cp312-win32.whl", hash = "sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917", size = 98141, upload-time = "2026-03-25T20:21:28.492Z" }, + { url = "https://files.pythonhosted.org/packages/24/22/4daacd05391b92c55759d55eaee21e1dfaea86ce5c571f10083360adf534/tomli-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9", size = 108847, upload-time = "2026-03-25T20:21:29.386Z" }, + { url = "https://files.pythonhosted.org/packages/68/fd/70e768887666ddd9e9f5d85129e84910f2db2796f9096aa02b721a53098d/tomli-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257", size = 95088, upload-time = "2026-03-25T20:21:30.677Z" }, + { url = "https://files.pythonhosted.org/packages/07/06/b823a7e818c756d9a7123ba2cda7d07bc2dd32835648d1a7b7b7a05d848d/tomli-2.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:36d2bd2ad5fb9eaddba5226aa02c8ec3fa4f192631e347b3ed28186d43be6b54", size = 155866, upload-time = "2026-03-25T20:21:31.65Z" }, + { url = "https://files.pythonhosted.org/packages/14/6f/12645cf7f08e1a20c7eb8c297c6f11d31c1b50f316a7e7e1e1de6e2e7b7e/tomli-2.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:eb0dc4e38e6a1fd579e5d50369aa2e10acfc9cace504579b2faabb478e76941a", size = 149887, upload-time = "2026-03-25T20:21:33.028Z" }, + { url = "https://files.pythonhosted.org/packages/5c/e0/90637574e5e7212c09099c67ad349b04ec4d6020324539297b634a0192b0/tomli-2.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7f2c7f2b9ca6bdeef8f0fa897f8e05085923eb091721675170254cbc5b02897", size = 243704, upload-time = "2026-03-25T20:21:34.51Z" }, + { url = "https://files.pythonhosted.org/packages/10/8f/d3ddb16c5a4befdf31a23307f72828686ab2096f068eaf56631e136c1fdd/tomli-2.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3c6818a1a86dd6dca7ddcaaf76947d5ba31aecc28cb1b67009a5877c9a64f3f", size = 251628, upload-time = "2026-03-25T20:21:36.012Z" }, + { url = "https://files.pythonhosted.org/packages/e3/f1/dbeeb9116715abee2485bf0a12d07a8f31af94d71608c171c45f64c0469d/tomli-2.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d312ef37c91508b0ab2cee7da26ec0b3ed2f03ce12bd87a588d771ae15dcf82d", size = 247180, upload-time = "2026-03-25T20:21:37.136Z" }, + { url = "https://files.pythonhosted.org/packages/d3/74/16336ffd19ed4da28a70959f92f506233bd7cfc2332b20bdb01591e8b1d1/tomli-2.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51529d40e3ca50046d7606fa99ce3956a617f9b36380da3b7f0dd3dd28e68cb5", size = 251674, upload-time = "2026-03-25T20:21:38.298Z" }, + { url = "https://files.pythonhosted.org/packages/16/f9/229fa3434c590ddf6c0aa9af64d3af4b752540686cace29e6281e3458469/tomli-2.4.1-cp313-cp313-win32.whl", hash = "sha256:2190f2e9dd7508d2a90ded5ed369255980a1bcdd58e52f7fe24b8162bf9fedbd", size = 97976, upload-time = "2026-03-25T20:21:39.316Z" }, + { url = "https://files.pythonhosted.org/packages/6a/1e/71dfd96bcc1c775420cb8befe7a9d35f2e5b1309798f009dca17b7708c1e/tomli-2.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:8d65a2fbf9d2f8352685bc1364177ee3923d6baf5e7f43ea4959d7d8bc326a36", size = 108755, upload-time = "2026-03-25T20:21:40.248Z" }, + { url = "https://files.pythonhosted.org/packages/83/7a/d34f422a021d62420b78f5c538e5b102f62bea616d1d75a13f0a88acb04a/tomli-2.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:4b605484e43cdc43f0954ddae319fb75f04cc10dd80d830540060ee7cd0243cd", size = 95265, upload-time = "2026-03-25T20:21:41.219Z" }, + { url = "https://files.pythonhosted.org/packages/3c/fb/9a5c8d27dbab540869f7c1f8eb0abb3244189ce780ba9cd73f3770662072/tomli-2.4.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fd0409a3653af6c147209d267a0e4243f0ae46b011aa978b1080359fddc9b6cf", size = 155726, upload-time = "2026-03-25T20:21:42.23Z" }, + { url = "https://files.pythonhosted.org/packages/62/05/d2f816630cc771ad836af54f5001f47a6f611d2d39535364f148b6a92d6b/tomli-2.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a120733b01c45e9a0c34aeef92bf0cf1d56cfe81ed9d47d562f9ed591a9828ac", size = 149859, upload-time = "2026-03-25T20:21:43.386Z" }, + { url = "https://files.pythonhosted.org/packages/ce/48/66341bdb858ad9bd0ceab5a86f90eddab127cf8b046418009f2125630ecb/tomli-2.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:559db847dc486944896521f68d8190be1c9e719fced785720d2216fe7022b662", size = 244713, upload-time = "2026-03-25T20:21:44.474Z" }, + { url = "https://files.pythonhosted.org/packages/df/6d/c5fad00d82b3c7a3ab6189bd4b10e60466f22cfe8a08a9394185c8a8111c/tomli-2.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01f520d4f53ef97964a240a035ec2a869fe1a37dde002b57ebc4417a27ccd853", size = 252084, upload-time = "2026-03-25T20:21:45.62Z" }, + { url = "https://files.pythonhosted.org/packages/00/71/3a69e86f3eafe8c7a59d008d245888051005bd657760e96d5fbfb0b740c2/tomli-2.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7f94b27a62cfad8496c8d2513e1a222dd446f095fca8987fceef261225538a15", size = 247973, upload-time = "2026-03-25T20:21:46.937Z" }, + { url = "https://files.pythonhosted.org/packages/67/50/361e986652847fec4bd5e4a0208752fbe64689c603c7ae5ea7cb16b1c0ca/tomli-2.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ede3e6487c5ef5d28634ba3f31f989030ad6af71edfb0055cbbd14189ff240ba", size = 256223, upload-time = "2026-03-25T20:21:48.467Z" }, + { url = "https://files.pythonhosted.org/packages/8c/9a/b4173689a9203472e5467217e0154b00e260621caa227b6fa01feab16998/tomli-2.4.1-cp314-cp314-win32.whl", hash = "sha256:3d48a93ee1c9b79c04bb38772ee1b64dcf18ff43085896ea460ca8dec96f35f6", size = 98973, upload-time = "2026-03-25T20:21:49.526Z" }, + { url = "https://files.pythonhosted.org/packages/14/58/640ac93bf230cd27d002462c9af0d837779f8773bc03dee06b5835208214/tomli-2.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:88dceee75c2c63af144e456745e10101eb67361050196b0b6af5d717254dddf7", size = 109082, upload-time = "2026-03-25T20:21:50.506Z" }, + { url = "https://files.pythonhosted.org/packages/d5/2f/702d5e05b227401c1068f0d386d79a589bb12bf64c3d2c72ce0631e3bc49/tomli-2.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:b8c198f8c1805dc42708689ed6864951fd2494f924149d3e4bce7710f8eb5232", size = 96490, upload-time = "2026-03-25T20:21:51.474Z" }, + { url = "https://files.pythonhosted.org/packages/45/4b/b877b05c8ba62927d9865dd980e34a755de541eb65fffba52b4cc495d4d2/tomli-2.4.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:d4d8fe59808a54658fcc0160ecfb1b30f9089906c50b23bcb4c69eddc19ec2b4", size = 164263, upload-time = "2026-03-25T20:21:52.543Z" }, + { url = "https://files.pythonhosted.org/packages/24/79/6ab420d37a270b89f7195dec5448f79400d9e9c1826df982f3f8e97b24fd/tomli-2.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7008df2e7655c495dd12d2a4ad038ff878d4ca4b81fccaf82b714e07eae4402c", size = 160736, upload-time = "2026-03-25T20:21:53.674Z" }, + { url = "https://files.pythonhosted.org/packages/02/e0/3630057d8eb170310785723ed5adcdfb7d50cb7e6455f85ba8a3deed642b/tomli-2.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1d8591993e228b0c930c4bb0db464bdad97b3289fb981255d6c9a41aedc84b2d", size = 270717, upload-time = "2026-03-25T20:21:55.129Z" }, + { url = "https://files.pythonhosted.org/packages/7a/b4/1613716072e544d1a7891f548d8f9ec6ce2faf42ca65acae01d76ea06bb0/tomli-2.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:734e20b57ba95624ecf1841e72b53f6e186355e216e5412de414e3c51e5e3c41", size = 278461, upload-time = "2026-03-25T20:21:56.228Z" }, + { url = "https://files.pythonhosted.org/packages/05/38/30f541baf6a3f6df77b3df16b01ba319221389e2da59427e221ef417ac0c/tomli-2.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8a650c2dbafa08d42e51ba0b62740dae4ecb9338eefa093aa5c78ceb546fcd5c", size = 274855, upload-time = "2026-03-25T20:21:57.653Z" }, + { url = "https://files.pythonhosted.org/packages/77/a3/ec9dd4fd2c38e98de34223b995a3b34813e6bdadf86c75314c928350ed14/tomli-2.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:504aa796fe0569bb43171066009ead363de03675276d2d121ac1a4572397870f", size = 283144, upload-time = "2026-03-25T20:21:59.089Z" }, + { url = "https://files.pythonhosted.org/packages/ef/be/605a6261cac79fba2ec0c9827e986e00323a1945700969b8ee0b30d85453/tomli-2.4.1-cp314-cp314t-win32.whl", hash = "sha256:b1d22e6e9387bf4739fbe23bfa80e93f6b0373a7f1b96c6227c32bef95a4d7a8", size = 108683, upload-time = "2026-03-25T20:22:00.214Z" }, + { url = "https://files.pythonhosted.org/packages/12/64/da524626d3b9cc40c168a13da8335fe1c51be12c0a63685cc6db7308daae/tomli-2.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:2c1c351919aca02858f740c6d33adea0c5deea37f9ecca1cc1ef9e884a619d26", size = 121196, upload-time = "2026-03-25T20:22:01.169Z" }, + { url = "https://files.pythonhosted.org/packages/5a/cd/e80b62269fc78fc36c9af5a6b89c835baa8af28ff5ad28c7028d60860320/tomli-2.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:eab21f45c7f66c13f2a9e0e1535309cee140182a9cdae1e041d02e47291e8396", size = 100393, upload-time = "2026-03-25T20:22:02.137Z" }, + { url = "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe", size = 14583, upload-time = "2026-03-25T20:22:03.012Z" }, +] + [[package]] name = "typing-extensions" version = "4.15.0" @@ -940,7 +1775,7 @@ name = "typing-inspection" version = "0.4.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions" }, + { name = "typing-extensions", marker = "extra == 'group-10-cloudflare-pydantic-v2' or extra != 'group-10-cloudflare-pydantic-v1'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } wheels = [ @@ -955,9 +1790,9 @@ resolution-markers = [ "python_full_version < '3.10'", ] dependencies = [ - { name = "idna", marker = "python_full_version < '3.10'" }, - { name = "multidict", marker = "python_full_version < '3.10'" }, - { name = "propcache", marker = "python_full_version < '3.10'" }, + { name = "idna", marker = "python_full_version < '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "multidict", marker = "python_full_version < '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "propcache", marker = "python_full_version < '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/57/63/0c6ebca57330cd313f6102b16dd57ffaf3ec4c83403dcb45dbd15c6f3ea1/yarl-1.22.0.tar.gz", hash = "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71", size = 187169, upload-time = "2025-10-06T14:12:55.963Z" } wheels = [ @@ -1097,12 +1932,15 @@ name = "yarl" version = "1.23.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.10'", + "python_full_version >= '3.14' and extra != 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2'", + "python_full_version >= '3.10' and python_full_version < '3.14' and extra != 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2'", + "python_full_version >= '3.10' and extra == 'group-10-cloudflare-pydantic-v1' and extra != 'group-10-cloudflare-pydantic-v2'", + "python_full_version >= '3.10' and extra != 'group-10-cloudflare-pydantic-v1' and extra != 'group-10-cloudflare-pydantic-v2'", ] dependencies = [ - { name = "idna", marker = "python_full_version >= '3.10'" }, - { name = "multidict", marker = "python_full_version >= '3.10'" }, - { name = "propcache", marker = "python_full_version >= '3.10'" }, + { name = "idna", marker = "python_full_version >= '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "multidict", marker = "python_full_version >= '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, + { name = "propcache", marker = "python_full_version >= '3.10' or (extra == 'group-10-cloudflare-pydantic-v1' and extra == 'group-10-cloudflare-pydantic-v2')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/23/6e/beb1beec874a72f23815c1434518bfc4ed2175065173fb138c3705f658d4/yarl-1.23.0.tar.gz", hash = "sha256:53b1ea6ca88ebd4420379c330aea57e258408dd0df9af0992e5de2078dc9f5d5", size = 194676, upload-time = "2026-03-01T22:07:53.373Z" } wheels = [ @@ -1234,3 +2072,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/51/47/3fa2286c3cb162c71cdb34c4224d5745a1ceceb391b2bd9b19b668a8d724/yarl-1.23.0-cp314-cp314t-win_arm64.whl", hash = "sha256:44bb7bef4ea409384e3f8bc36c063d77ea1b8d4a5b2706956c0d6695f07dcc25", size = 86041, upload-time = "2026-03-01T22:07:49.026Z" }, { url = "https://files.pythonhosted.org/packages/69/68/c8739671f5699c7dc470580a4f821ef37c32c4cb0b047ce223a7f115757f/yarl-1.23.0-py3-none-any.whl", hash = "sha256:a2df6afe50dea8ae15fa34c9f824a3ee958d785fd5d089063d960bae1daa0a3f", size = 48288, upload-time = "2026-03-01T22:07:51.388Z" }, ] + +[[package]] +name = "zipp" +version = "3.23.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/30/21/093488dfc7cc8964ded15ab726fad40f25fd3d788fd741cc1c5a17d78ee8/zipp-3.23.1.tar.gz", hash = "sha256:32120e378d32cd9714ad503c1d024619063ec28aad2248dc6672ad13edfa5110", size = 25965, upload-time = "2026-04-13T23:21:46.6Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/08/8a/0861bec20485572fbddf3dfba2910e38fe249796cb73ecdeb74e07eeb8d3/zipp-3.23.1-py3-none-any.whl", hash = "sha256:0b3596c50a5c700c9cb40ba8d86d9f2cc4807e9bedb06bcdf7fac85633e444dc", size = 10378, upload-time = "2026-04-13T23:21:45.386Z" }, +] From 3092db28e6c3edac0f1d127ef82214719f00ae66 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 30 Apr 2026 21:17:50 +0000 Subject: [PATCH 23/45] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index dfb0c0da36e..21863746d4f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 2195 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a6c352830d1270d0abb5bb983058ea21815e1bb7d2e163965335dcb0e706f057.yml -openapi_spec_hash: aa452e4dfaec546a7e50ef8665bd39f4 +openapi_spec_hash: f57832549e5b334bc424261018f352ca config_hash: d3379006654eb5479a62d9576648acc5 From 659ab0052c1e59d253bcb520abf854b24d746eea Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 1 May 2026 06:08:30 +0000 Subject: [PATCH 24/45] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 21863746d4f..75a5dac3ff4 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 2195 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a6c352830d1270d0abb5bb983058ea21815e1bb7d2e163965335dcb0e706f057.yml -openapi_spec_hash: f57832549e5b334bc424261018f352ca +openapi_spec_hash: b9621d5fbdbced049722fbb186b3632c config_hash: d3379006654eb5479a62d9576648acc5 From 2cf81d54d151dc3c41aed62c79dd8cb75602347a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 1 May 2026 16:41:22 +0000 Subject: [PATCH 25/45] chore(api): update composite API spec --- .stats.yml | 2 +- src/cloudflare/resources/zones/zones.py | 14 +++++++++- .../types/zones/setting_edit_response.py | 26 +++++++++++++++++++ .../types/zones/setting_get_response.py | 26 +++++++++++++++++++ .../types/zones/zone_list_params.py | 9 +++++++ tests/api_resources/test_zones.py | 2 ++ 6 files changed, 77 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 75a5dac3ff4..97744c2acca 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 2195 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a6c352830d1270d0abb5bb983058ea21815e1bb7d2e163965335dcb0e706f057.yml -openapi_spec_hash: b9621d5fbdbced049722fbb186b3632c +openapi_spec_hash: 4cd58fdf7a6fa895b2514a2e60d131b1 config_hash: d3379006654eb5479a62d9576648acc5 diff --git a/src/cloudflare/resources/zones/zones.py b/src/cloudflare/resources/zones/zones.py index 290011057ee..ceba8dfd843 100644 --- a/src/cloudflare/resources/zones/zones.py +++ b/src/cloudflare/resources/zones/zones.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Type as TypingType, Optional, cast +from typing import List, Type as TypingType, Optional, cast from typing_extensions import Literal import httpx @@ -209,6 +209,7 @@ def list( page: float | Omit = omit, per_page: float | Omit = omit, status: Literal["initializing", "pending", "active", "moved"] | Omit = omit, + type: List[Literal["full", "partial", "secondary", "internal"]] | Omit = omit, # 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, @@ -246,6 +247,10 @@ def list( status: Specify a zone status to filter by. + type: Zone types to filter by. Multiple types can be specified as a comma-separated + list (e.g., ?type=full,partial,secondary). When this parameter is not provided, + zones with type "internal" are excluded from the results. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -272,6 +277,7 @@ def list( "page": page, "per_page": per_page, "status": status, + "type": type, }, zone_list_params.ZoneListParams, ), @@ -537,6 +543,7 @@ def list( page: float | Omit = omit, per_page: float | Omit = omit, status: Literal["initializing", "pending", "active", "moved"] | Omit = omit, + type: List[Literal["full", "partial", "secondary", "internal"]] | Omit = omit, # 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, @@ -574,6 +581,10 @@ def list( status: Specify a zone status to filter by. + type: Zone types to filter by. Multiple types can be specified as a comma-separated + list (e.g., ?type=full,partial,secondary). When this parameter is not provided, + zones with type "internal" are excluded from the results. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -600,6 +611,7 @@ def list( "page": page, "per_page": per_page, "status": status, + "type": type, }, zone_list_params.ZoneListParams, ), diff --git a/src/cloudflare/types/zones/setting_edit_response.py b/src/cloudflare/types/zones/setting_edit_response.py index 9fd2e3ef777..e1107566376 100644 --- a/src/cloudflare/types/zones/setting_edit_response.py +++ b/src/cloudflare/types/zones/setting_edit_response.py @@ -63,6 +63,7 @@ "ZonesSchemasResponseBuffering", "ZonesSchemasRocketLoader", "ZonesSchemasAutomaticPlatformOptimization", + "ZonesSearchForAgents", "ZonesSchemasSecurityLevel", "ZonesSha1Support", "ZonesSchemasSortQueryStringForCache", @@ -616,6 +617,30 @@ class ZonesSchemasAutomaticPlatformOptimization(BaseModel): """last time this setting was modified.""" +class ZonesSearchForAgents(BaseModel): + """ + When enabled, Cloudflare provisions an AI Search instance for the zone + and exposes a /.well-known/ai-search endpoint that AI agents can query. + Markdown responses also receive an agent: YAML capability block advertising + the search endpoint. + """ + + id: Literal["search_for_agents"] + """ID of the zone setting.""" + + value: Literal["off", "on"] + """Current value of the zone setting.""" + + editable: Optional[Literal[True, False]] = None + """ + Whether or not this setting can be modified for this zone (based on your + Cloudflare plan level). + """ + + modified_on: Optional[datetime] = None + """last time this setting was modified.""" + + class ZonesSchemasSecurityLevel(BaseModel): """ Choose the appropriate security profile for your website, which will automatically adjust each of the security settings. If you choose to customize an individual security setting, the profile will become Custom. (https://support.cloudflare.com/hc/en-us/articles/200170056). @@ -855,6 +880,7 @@ class ZonesSchemasWAF(BaseModel): ZonesSchemasResponseBuffering, ZonesSchemasRocketLoader, ZonesSchemasAutomaticPlatformOptimization, + ZonesSearchForAgents, SecurityHeaders, ZonesSchemasSecurityLevel, ServerSideExcludes, diff --git a/src/cloudflare/types/zones/setting_get_response.py b/src/cloudflare/types/zones/setting_get_response.py index ac20c206eb1..3b66fbf3293 100644 --- a/src/cloudflare/types/zones/setting_get_response.py +++ b/src/cloudflare/types/zones/setting_get_response.py @@ -63,6 +63,7 @@ "ZonesSchemasResponseBuffering", "ZonesSchemasRocketLoader", "ZonesSchemasAutomaticPlatformOptimization", + "ZonesSearchForAgents", "ZonesSchemasSecurityLevel", "ZonesSha1Support", "ZonesSchemasSortQueryStringForCache", @@ -616,6 +617,30 @@ class ZonesSchemasAutomaticPlatformOptimization(BaseModel): """last time this setting was modified.""" +class ZonesSearchForAgents(BaseModel): + """ + When enabled, Cloudflare provisions an AI Search instance for the zone + and exposes a /.well-known/ai-search endpoint that AI agents can query. + Markdown responses also receive an agent: YAML capability block advertising + the search endpoint. + """ + + id: Literal["search_for_agents"] + """ID of the zone setting.""" + + value: Literal["off", "on"] + """Current value of the zone setting.""" + + editable: Optional[Literal[True, False]] = None + """ + Whether or not this setting can be modified for this zone (based on your + Cloudflare plan level). + """ + + modified_on: Optional[datetime] = None + """last time this setting was modified.""" + + class ZonesSchemasSecurityLevel(BaseModel): """ Choose the appropriate security profile for your website, which will automatically adjust each of the security settings. If you choose to customize an individual security setting, the profile will become Custom. (https://support.cloudflare.com/hc/en-us/articles/200170056). @@ -855,6 +880,7 @@ class ZonesSchemasWAF(BaseModel): ZonesSchemasResponseBuffering, ZonesSchemasRocketLoader, ZonesSchemasAutomaticPlatformOptimization, + ZonesSearchForAgents, SecurityHeaders, ZonesSchemasSecurityLevel, ServerSideExcludes, diff --git a/src/cloudflare/types/zones/zone_list_params.py b/src/cloudflare/types/zones/zone_list_params.py index 8e6985ebfe1..706077d2171 100644 --- a/src/cloudflare/types/zones/zone_list_params.py +++ b/src/cloudflare/types/zones/zone_list_params.py @@ -2,6 +2,7 @@ from __future__ import annotations +from typing import List from typing_extensions import Literal, TypedDict __all__ = ["ZoneListParams", "Account"] @@ -43,6 +44,14 @@ class ZoneListParams(TypedDict, total=False): status: Literal["initializing", "pending", "active", "moved"] """Specify a zone status to filter by.""" + type: List[Literal["full", "partial", "secondary", "internal"]] + """Zone types to filter by. + + Multiple types can be specified as a comma-separated list (e.g., + ?type=full,partial,secondary). When this parameter is not provided, zones with + type "internal" are excluded from the results. + """ + class Account(TypedDict, total=False): id: str diff --git a/tests/api_resources/test_zones.py b/tests/api_resources/test_zones.py index 0ee90986d59..60b348fbaea 100644 --- a/tests/api_resources/test_zones.py +++ b/tests/api_resources/test_zones.py @@ -83,6 +83,7 @@ def test_method_list_with_all_params(self, client: Cloudflare) -> None: page=1, per_page=5, status="initializing", + type=["full"], ) assert_matches_type(SyncV4PagePaginationArray[Zone], zone, path=["response"]) @@ -302,6 +303,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncCloudflare) page=1, per_page=5, status="initializing", + type=["full"], ) assert_matches_type(AsyncV4PagePaginationArray[Zone], zone, path=["response"]) From 561379884586a824a42bc88d0887565f4c163ba6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 1 May 2026 18:19:30 +0000 Subject: [PATCH 26/45] feat: feat(api): add zero_trust_device_deployment_groups resource * feat(api): add zero_trust_device_deployment_groups resource * feat(api): add zero_trust_device_deployment_groups resource --- .stats.yml | 4 +- src/cloudflare/resources/zero_trust/api.md | 16 + .../resources/zero_trust/devices/__init__.py | 14 + .../zero_trust/devices/deployment_groups.py | 668 ++++++++++++++++++ .../resources/zero_trust/devices/devices.py | 32 + .../types/zero_trust/devices/__init__.py | 5 + .../zero_trust/devices/deployment_group.py | 35 + .../devices/deployment_group_create_params.py | 31 + .../deployment_group_delete_response.py | 12 + .../devices/deployment_group_edit_params.py | 31 + .../devices/deployment_group_list_params.py | 17 + .../devices/test_deployment_groups.py | 604 ++++++++++++++++ 12 files changed, 1467 insertions(+), 2 deletions(-) create mode 100644 src/cloudflare/resources/zero_trust/devices/deployment_groups.py create mode 100644 src/cloudflare/types/zero_trust/devices/deployment_group.py create mode 100644 src/cloudflare/types/zero_trust/devices/deployment_group_create_params.py create mode 100644 src/cloudflare/types/zero_trust/devices/deployment_group_delete_response.py create mode 100644 src/cloudflare/types/zero_trust/devices/deployment_group_edit_params.py create mode 100644 src/cloudflare/types/zero_trust/devices/deployment_group_list_params.py create mode 100644 tests/api_resources/zero_trust/devices/test_deployment_groups.py diff --git a/.stats.yml b/.stats.yml index 97744c2acca..88038d23b32 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 2195 +configured_endpoints: 2200 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a6c352830d1270d0abb5bb983058ea21815e1bb7d2e163965335dcb0e706f057.yml openapi_spec_hash: 4cd58fdf7a6fa895b2514a2e60d131b1 -config_hash: d3379006654eb5479a62d9576648acc5 +config_hash: 98fb614048aec6722b11484583cc3819 diff --git a/src/cloudflare/resources/zero_trust/api.md b/src/cloudflare/resources/zero_trust/api.md index cedf199e090..35c0c1fd0d3 100644 --- a/src/cloudflare/resources/zero_trust/api.md +++ b/src/cloudflare/resources/zero_trust/api.md @@ -103,6 +103,22 @@ Methods: - client.zero_trust.devices.ip_profiles.delete(profile_id, \*, account_id) -> IPProfileDeleteResponse - client.zero_trust.devices.ip_profiles.get(profile_id, \*, account_id) -> IPProfile +### DeploymentGroups + +Types: + +```python +from cloudflare.types.zero_trust.devices import DeploymentGroup, DeploymentGroupDeleteResponse +``` + +Methods: + +- client.zero_trust.devices.deployment_groups.create(\*, account_id, \*\*params) -> DeploymentGroup +- client.zero_trust.devices.deployment_groups.list(\*, account_id, \*\*params) -> SyncV4PagePaginationArray[DeploymentGroup] +- client.zero_trust.devices.deployment_groups.delete(group_id, \*, account_id) -> DeploymentGroupDeleteResponse +- client.zero_trust.devices.deployment_groups.edit(group_id, \*, account_id, \*\*params) -> DeploymentGroup +- client.zero_trust.devices.deployment_groups.get(group_id, \*, account_id) -> DeploymentGroup + ### Networks Types: diff --git a/src/cloudflare/resources/zero_trust/devices/__init__.py b/src/cloudflare/resources/zero_trust/devices/__init__.py index a3579f08c06..45351e0fe62 100644 --- a/src/cloudflare/resources/zero_trust/devices/__init__.py +++ b/src/cloudflare/resources/zero_trust/devices/__init__.py @@ -104,6 +104,14 @@ OverrideCodesResourceWithStreamingResponse, AsyncOverrideCodesResourceWithStreamingResponse, ) +from .deployment_groups import ( + DeploymentGroupsResource, + AsyncDeploymentGroupsResource, + DeploymentGroupsResourceWithRawResponse, + AsyncDeploymentGroupsResourceWithRawResponse, + DeploymentGroupsResourceWithStreamingResponse, + AsyncDeploymentGroupsResourceWithStreamingResponse, +) __all__ = [ "ResilienceResource", @@ -130,6 +138,12 @@ "AsyncIPProfilesResourceWithRawResponse", "IPProfilesResourceWithStreamingResponse", "AsyncIPProfilesResourceWithStreamingResponse", + "DeploymentGroupsResource", + "AsyncDeploymentGroupsResource", + "DeploymentGroupsResourceWithRawResponse", + "AsyncDeploymentGroupsResourceWithRawResponse", + "DeploymentGroupsResourceWithStreamingResponse", + "AsyncDeploymentGroupsResourceWithStreamingResponse", "NetworksResource", "AsyncNetworksResource", "NetworksResourceWithRawResponse", diff --git a/src/cloudflare/resources/zero_trust/devices/deployment_groups.py b/src/cloudflare/resources/zero_trust/devices/deployment_groups.py new file mode 100644 index 00000000000..12df51fa905 --- /dev/null +++ b/src/cloudflare/resources/zero_trust/devices/deployment_groups.py @@ -0,0 +1,668 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Type, Iterable, cast + +import httpx + +from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ...._utils import path_template, 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 SyncV4PagePaginationArray, AsyncV4PagePaginationArray +from ...._base_client import AsyncPaginator, make_request_options +from ....types.zero_trust.devices import ( + deployment_group_edit_params, + deployment_group_list_params, + deployment_group_create_params, +) +from ....types.zero_trust.devices.deployment_group import DeploymentGroup +from ....types.zero_trust.devices.deployment_group_delete_response import DeploymentGroupDeleteResponse + +__all__ = ["DeploymentGroupsResource", "AsyncDeploymentGroupsResource"] + + +class DeploymentGroupsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> DeploymentGroupsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 DeploymentGroupsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> DeploymentGroupsResourceWithStreamingResponse: + """ + 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 DeploymentGroupsResourceWithStreamingResponse(self) + + def create( + self, + *, + account_id: str, + name: str, + version_config: Iterable[deployment_group_create_params.VersionConfig], + policy_ids: SequenceNotStr[str] | Omit = omit, + # 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, + ) -> DeploymentGroup: + """Creates a new deployment group. + + Policy IDs must be unique across all deployment + groups. This endpoint is in Beta. + + Args: + name: A user-friendly name for the deployment group. + + version_config: Contains at least one version configuration. + + policy_ids: Contains an optional list of policy IDs assigned to a group. + + 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( + path_template("/accounts/{account_id}/devices/deployment-groups", account_id=account_id), + body=maybe_transform( + { + "name": name, + "version_config": version_config, + "policy_ids": policy_ids, + }, + deployment_group_create_params.DeploymentGroupCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[DeploymentGroup]._unwrapper, + ), + cast_to=cast(Type[DeploymentGroup], ResultWrapper[DeploymentGroup]), + ) + + def list( + self, + *, + account_id: str, + page: int | Omit = omit, + per_page: int | Omit = omit, + # 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, + ) -> SyncV4PagePaginationArray[DeploymentGroup]: + """Lists all deployment groups for an account. + + Use deployment groups to assign + target WARP client versions to specific devices. This endpoint is in Beta. + + Args: + page: The page number to return. + + per_page: The maximum number of deployment groups to return per page. + + 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( + path_template("/accounts/{account_id}/devices/deployment-groups", account_id=account_id), + page=SyncV4PagePaginationArray[DeploymentGroup], + 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, + }, + deployment_group_list_params.DeploymentGroupListParams, + ), + ), + model=DeploymentGroup, + ) + + def delete( + self, + group_id: str, + *, + 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, + ) -> DeploymentGroupDeleteResponse: + """Deletes a deployment group. + + Associated policies no longer apply and devices stop + receiving version targets. This endpoint is in Beta. + + 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}") + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return self._delete( + path_template( + "/accounts/{account_id}/devices/deployment-groups/{group_id}", account_id=account_id, group_id=group_id + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[DeploymentGroupDeleteResponse]._unwrapper, + ), + cast_to=cast(Type[DeploymentGroupDeleteResponse], ResultWrapper[DeploymentGroupDeleteResponse]), + ) + + def edit( + self, + group_id: str, + *, + account_id: str, + name: str | Omit = omit, + policy_ids: SequenceNotStr[str] | Omit = omit, + version_config: Iterable[deployment_group_edit_params.VersionConfig] | Omit = omit, + # 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, + ) -> DeploymentGroup: + """Updates a deployment group. + + Returns 409 if any newly added policy IDs already + belong to another deployment group. This endpoint is in Beta. + + Args: + name: A user-friendly name for the deployment group. + + policy_ids: Replaces the entire list of policy IDs. + + version_config: Replaces the entire version_config array. + + 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 group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return self._patch( + path_template( + "/accounts/{account_id}/devices/deployment-groups/{group_id}", account_id=account_id, group_id=group_id + ), + body=maybe_transform( + { + "name": name, + "policy_ids": policy_ids, + "version_config": version_config, + }, + deployment_group_edit_params.DeploymentGroupEditParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[DeploymentGroup]._unwrapper, + ), + cast_to=cast(Type[DeploymentGroup], ResultWrapper[DeploymentGroup]), + ) + + def get( + self, + group_id: str, + *, + 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, + ) -> DeploymentGroup: + """Fetches a single deployment group by its ID. + + This endpoint is in Beta. + + 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}") + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return self._get( + path_template( + "/accounts/{account_id}/devices/deployment-groups/{group_id}", account_id=account_id, group_id=group_id + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[DeploymentGroup]._unwrapper, + ), + cast_to=cast(Type[DeploymentGroup], ResultWrapper[DeploymentGroup]), + ) + + +class AsyncDeploymentGroupsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncDeploymentGroupsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 AsyncDeploymentGroupsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncDeploymentGroupsResourceWithStreamingResponse: + """ + 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 AsyncDeploymentGroupsResourceWithStreamingResponse(self) + + async def create( + self, + *, + account_id: str, + name: str, + version_config: Iterable[deployment_group_create_params.VersionConfig], + policy_ids: SequenceNotStr[str] | Omit = omit, + # 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, + ) -> DeploymentGroup: + """Creates a new deployment group. + + Policy IDs must be unique across all deployment + groups. This endpoint is in Beta. + + Args: + name: A user-friendly name for the deployment group. + + version_config: Contains at least one version configuration. + + policy_ids: Contains an optional list of policy IDs assigned to a group. + + 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( + path_template("/accounts/{account_id}/devices/deployment-groups", account_id=account_id), + body=await async_maybe_transform( + { + "name": name, + "version_config": version_config, + "policy_ids": policy_ids, + }, + deployment_group_create_params.DeploymentGroupCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[DeploymentGroup]._unwrapper, + ), + cast_to=cast(Type[DeploymentGroup], ResultWrapper[DeploymentGroup]), + ) + + def list( + self, + *, + account_id: str, + page: int | Omit = omit, + per_page: int | Omit = omit, + # 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[DeploymentGroup, AsyncV4PagePaginationArray[DeploymentGroup]]: + """Lists all deployment groups for an account. + + Use deployment groups to assign + target WARP client versions to specific devices. This endpoint is in Beta. + + Args: + page: The page number to return. + + per_page: The maximum number of deployment groups to return per page. + + 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( + path_template("/accounts/{account_id}/devices/deployment-groups", account_id=account_id), + page=AsyncV4PagePaginationArray[DeploymentGroup], + 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, + }, + deployment_group_list_params.DeploymentGroupListParams, + ), + ), + model=DeploymentGroup, + ) + + async def delete( + self, + group_id: str, + *, + 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, + ) -> DeploymentGroupDeleteResponse: + """Deletes a deployment group. + + Associated policies no longer apply and devices stop + receiving version targets. This endpoint is in Beta. + + 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}") + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return await self._delete( + path_template( + "/accounts/{account_id}/devices/deployment-groups/{group_id}", account_id=account_id, group_id=group_id + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[DeploymentGroupDeleteResponse]._unwrapper, + ), + cast_to=cast(Type[DeploymentGroupDeleteResponse], ResultWrapper[DeploymentGroupDeleteResponse]), + ) + + async def edit( + self, + group_id: str, + *, + account_id: str, + name: str | Omit = omit, + policy_ids: SequenceNotStr[str] | Omit = omit, + version_config: Iterable[deployment_group_edit_params.VersionConfig] | Omit = omit, + # 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, + ) -> DeploymentGroup: + """Updates a deployment group. + + Returns 409 if any newly added policy IDs already + belong to another deployment group. This endpoint is in Beta. + + Args: + name: A user-friendly name for the deployment group. + + policy_ids: Replaces the entire list of policy IDs. + + version_config: Replaces the entire version_config array. + + 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 group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return await self._patch( + path_template( + "/accounts/{account_id}/devices/deployment-groups/{group_id}", account_id=account_id, group_id=group_id + ), + body=await async_maybe_transform( + { + "name": name, + "policy_ids": policy_ids, + "version_config": version_config, + }, + deployment_group_edit_params.DeploymentGroupEditParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[DeploymentGroup]._unwrapper, + ), + cast_to=cast(Type[DeploymentGroup], ResultWrapper[DeploymentGroup]), + ) + + async def get( + self, + group_id: str, + *, + 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, + ) -> DeploymentGroup: + """Fetches a single deployment group by its ID. + + This endpoint is in Beta. + + 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}") + if not group_id: + raise ValueError(f"Expected a non-empty value for `group_id` but received {group_id!r}") + return await self._get( + path_template( + "/accounts/{account_id}/devices/deployment-groups/{group_id}", account_id=account_id, group_id=group_id + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[DeploymentGroup]._unwrapper, + ), + cast_to=cast(Type[DeploymentGroup], ResultWrapper[DeploymentGroup]), + ) + + +class DeploymentGroupsResourceWithRawResponse: + def __init__(self, deployment_groups: DeploymentGroupsResource) -> None: + self._deployment_groups = deployment_groups + + self.create = to_raw_response_wrapper( + deployment_groups.create, + ) + self.list = to_raw_response_wrapper( + deployment_groups.list, + ) + self.delete = to_raw_response_wrapper( + deployment_groups.delete, + ) + self.edit = to_raw_response_wrapper( + deployment_groups.edit, + ) + self.get = to_raw_response_wrapper( + deployment_groups.get, + ) + + +class AsyncDeploymentGroupsResourceWithRawResponse: + def __init__(self, deployment_groups: AsyncDeploymentGroupsResource) -> None: + self._deployment_groups = deployment_groups + + self.create = async_to_raw_response_wrapper( + deployment_groups.create, + ) + self.list = async_to_raw_response_wrapper( + deployment_groups.list, + ) + self.delete = async_to_raw_response_wrapper( + deployment_groups.delete, + ) + self.edit = async_to_raw_response_wrapper( + deployment_groups.edit, + ) + self.get = async_to_raw_response_wrapper( + deployment_groups.get, + ) + + +class DeploymentGroupsResourceWithStreamingResponse: + def __init__(self, deployment_groups: DeploymentGroupsResource) -> None: + self._deployment_groups = deployment_groups + + self.create = to_streamed_response_wrapper( + deployment_groups.create, + ) + self.list = to_streamed_response_wrapper( + deployment_groups.list, + ) + self.delete = to_streamed_response_wrapper( + deployment_groups.delete, + ) + self.edit = to_streamed_response_wrapper( + deployment_groups.edit, + ) + self.get = to_streamed_response_wrapper( + deployment_groups.get, + ) + + +class AsyncDeploymentGroupsResourceWithStreamingResponse: + def __init__(self, deployment_groups: AsyncDeploymentGroupsResource) -> None: + self._deployment_groups = deployment_groups + + self.create = async_to_streamed_response_wrapper( + deployment_groups.create, + ) + self.list = async_to_streamed_response_wrapper( + deployment_groups.list, + ) + self.delete = async_to_streamed_response_wrapper( + deployment_groups.delete, + ) + self.edit = async_to_streamed_response_wrapper( + deployment_groups.edit, + ) + self.get = async_to_streamed_response_wrapper( + deployment_groups.get, + ) diff --git a/src/cloudflare/resources/zero_trust/devices/devices.py b/src/cloudflare/resources/zero_trust/devices/devices.py index d94495d96a1..efd14729f02 100644 --- a/src/cloudflare/resources/zero_trust/devices/devices.py +++ b/src/cloudflare/resources/zero_trust/devices/devices.py @@ -101,6 +101,14 @@ PostureResourceWithStreamingResponse, AsyncPostureResourceWithStreamingResponse, ) +from .deployment_groups import ( + DeploymentGroupsResource, + AsyncDeploymentGroupsResource, + DeploymentGroupsResourceWithRawResponse, + AsyncDeploymentGroupsResourceWithRawResponse, + DeploymentGroupsResourceWithStreamingResponse, + AsyncDeploymentGroupsResourceWithStreamingResponse, +) from .policies.policies import ( PoliciesResource, AsyncPoliciesResource, @@ -144,6 +152,10 @@ def dex_tests(self) -> DEXTestsResource: def ip_profiles(self) -> IPProfilesResource: return IPProfilesResource(self._client) + @cached_property + def deployment_groups(self) -> DeploymentGroupsResource: + return DeploymentGroupsResource(self._client) + @cached_property def networks(self) -> NetworksResource: return NetworksResource(self._client) @@ -312,6 +324,10 @@ def dex_tests(self) -> AsyncDEXTestsResource: def ip_profiles(self) -> AsyncIPProfilesResource: return AsyncIPProfilesResource(self._client) + @cached_property + def deployment_groups(self) -> AsyncDeploymentGroupsResource: + return AsyncDeploymentGroupsResource(self._client) + @cached_property def networks(self) -> AsyncNetworksResource: return AsyncNetworksResource(self._client) @@ -494,6 +510,10 @@ def dex_tests(self) -> DEXTestsResourceWithRawResponse: def ip_profiles(self) -> IPProfilesResourceWithRawResponse: return IPProfilesResourceWithRawResponse(self._devices.ip_profiles) + @cached_property + def deployment_groups(self) -> DeploymentGroupsResourceWithRawResponse: + return DeploymentGroupsResourceWithRawResponse(self._devices.deployment_groups) + @cached_property def networks(self) -> NetworksResourceWithRawResponse: return NetworksResourceWithRawResponse(self._devices.networks) @@ -562,6 +582,10 @@ def dex_tests(self) -> AsyncDEXTestsResourceWithRawResponse: def ip_profiles(self) -> AsyncIPProfilesResourceWithRawResponse: return AsyncIPProfilesResourceWithRawResponse(self._devices.ip_profiles) + @cached_property + def deployment_groups(self) -> AsyncDeploymentGroupsResourceWithRawResponse: + return AsyncDeploymentGroupsResourceWithRawResponse(self._devices.deployment_groups) + @cached_property def networks(self) -> AsyncNetworksResourceWithRawResponse: return AsyncNetworksResourceWithRawResponse(self._devices.networks) @@ -630,6 +654,10 @@ def dex_tests(self) -> DEXTestsResourceWithStreamingResponse: def ip_profiles(self) -> IPProfilesResourceWithStreamingResponse: return IPProfilesResourceWithStreamingResponse(self._devices.ip_profiles) + @cached_property + def deployment_groups(self) -> DeploymentGroupsResourceWithStreamingResponse: + return DeploymentGroupsResourceWithStreamingResponse(self._devices.deployment_groups) + @cached_property def networks(self) -> NetworksResourceWithStreamingResponse: return NetworksResourceWithStreamingResponse(self._devices.networks) @@ -698,6 +726,10 @@ def dex_tests(self) -> AsyncDEXTestsResourceWithStreamingResponse: def ip_profiles(self) -> AsyncIPProfilesResourceWithStreamingResponse: return AsyncIPProfilesResourceWithStreamingResponse(self._devices.ip_profiles) + @cached_property + def deployment_groups(self) -> AsyncDeploymentGroupsResourceWithStreamingResponse: + return AsyncDeploymentGroupsResourceWithStreamingResponse(self._devices.deployment_groups) + @cached_property def networks(self) -> AsyncNetworksResourceWithStreamingResponse: return AsyncNetworksResourceWithStreamingResponse(self._devices.networks) diff --git a/src/cloudflare/types/zero_trust/devices/__init__.py b/src/cloudflare/types/zero_trust/devices/__init__.py index b8a661717f2..55f3b9bb218 100644 --- a/src/cloudflare/types/zero_trust/devices/__init__.py +++ b/src/cloudflare/types/zero_trust/devices/__init__.py @@ -14,6 +14,7 @@ from .device_settings import DeviceSettings as DeviceSettings from .fallback_domain import FallbackDomain as FallbackDomain from .settings_policy import SettingsPolicy as SettingsPolicy +from .deployment_group import DeploymentGroup as DeploymentGroup from .file_input_param import FileInputParam as FileInputParam from .os_version_input import OSVersionInput as OSVersionInput from .carbonblack_input import CarbonblackInput as CarbonblackInput @@ -80,7 +81,11 @@ from .split_tunnel_include_param import SplitTunnelIncludeParam as SplitTunnelIncludeParam from .disk_encryption_input_param import DiskEncryptionInputParam as DiskEncryptionInputParam from .sentinelone_s2s_input_param import SentineloneS2sInputParam as SentineloneS2sInputParam +from .deployment_group_edit_params import DeploymentGroupEditParams as DeploymentGroupEditParams +from .deployment_group_list_params import DeploymentGroupListParams as DeploymentGroupListParams from .registration_unrevoke_params import RegistrationUnrevokeParams as RegistrationUnrevokeParams from .unique_client_id_input_param import UniqueClientIDInputParam as UniqueClientIDInputParam from .client_certificate_input_param import ClientCertificateInputParam as ClientCertificateInputParam +from .deployment_group_create_params import DeploymentGroupCreateParams as DeploymentGroupCreateParams from .registration_bulk_delete_params import RegistrationBulkDeleteParams as RegistrationBulkDeleteParams +from .deployment_group_delete_response import DeploymentGroupDeleteResponse as DeploymentGroupDeleteResponse diff --git a/src/cloudflare/types/zero_trust/devices/deployment_group.py b/src/cloudflare/types/zero_trust/devices/deployment_group.py new file mode 100644 index 00000000000..e85073b3be9 --- /dev/null +++ b/src/cloudflare/types/zero_trust/devices/deployment_group.py @@ -0,0 +1,35 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ...._models import BaseModel + +__all__ = ["DeploymentGroup", "VersionConfig"] + + +class VersionConfig(BaseModel): + target_environment: Optional[str] = None + """The target environment for the client version (e.g., windows, macos).""" + + version: str + """The specific client version to deploy.""" + + +class DeploymentGroup(BaseModel): + id: str + """The ID of the deployment group.""" + + created_at: str + """The RFC3339Nano timestamp when the deployment group was created.""" + + name: str + """A user-friendly name for the deployment group.""" + + updated_at: str + """The RFC3339Nano timestamp when the deployment group was last updated.""" + + version_config: List[VersionConfig] + """Contains version configurations for different target environments.""" + + policy_ids: Optional[List[str]] = None + """Contains a list of policy IDs assigned to this deployment group.""" diff --git a/src/cloudflare/types/zero_trust/devices/deployment_group_create_params.py b/src/cloudflare/types/zero_trust/devices/deployment_group_create_params.py new file mode 100644 index 00000000000..3cacec4ffe9 --- /dev/null +++ b/src/cloudflare/types/zero_trust/devices/deployment_group_create_params.py @@ -0,0 +1,31 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import Required, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["DeploymentGroupCreateParams", "VersionConfig"] + + +class DeploymentGroupCreateParams(TypedDict, total=False): + account_id: Required[str] + + name: Required[str] + """A user-friendly name for the deployment group.""" + + version_config: Required[Iterable[VersionConfig]] + """Contains at least one version configuration.""" + + policy_ids: SequenceNotStr[str] + """Contains an optional list of policy IDs assigned to a group.""" + + +class VersionConfig(TypedDict, total=False): + target_environment: Required[Optional[str]] + """The target environment for the client version (e.g., windows, macos).""" + + version: Required[str] + """The specific client version to deploy.""" diff --git a/src/cloudflare/types/zero_trust/devices/deployment_group_delete_response.py b/src/cloudflare/types/zero_trust/devices/deployment_group_delete_response.py new file mode 100644 index 00000000000..39c4b672b0f --- /dev/null +++ b/src/cloudflare/types/zero_trust/devices/deployment_group_delete_response.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ...._models import BaseModel + +__all__ = ["DeploymentGroupDeleteResponse"] + + +class DeploymentGroupDeleteResponse(BaseModel): + id: Optional[str] = None + """The ID of a deleted deployment group.""" diff --git a/src/cloudflare/types/zero_trust/devices/deployment_group_edit_params.py b/src/cloudflare/types/zero_trust/devices/deployment_group_edit_params.py new file mode 100644 index 00000000000..843dab242f1 --- /dev/null +++ b/src/cloudflare/types/zero_trust/devices/deployment_group_edit_params.py @@ -0,0 +1,31 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import Required, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["DeploymentGroupEditParams", "VersionConfig"] + + +class DeploymentGroupEditParams(TypedDict, total=False): + account_id: Required[str] + + name: str + """A user-friendly name for the deployment group.""" + + policy_ids: SequenceNotStr[str] + """Replaces the entire list of policy IDs.""" + + version_config: Iterable[VersionConfig] + """Replaces the entire version_config array.""" + + +class VersionConfig(TypedDict, total=False): + target_environment: Required[Optional[str]] + """The target environment for the client version (e.g., windows, macos).""" + + version: Required[str] + """The specific client version to deploy.""" diff --git a/src/cloudflare/types/zero_trust/devices/deployment_group_list_params.py b/src/cloudflare/types/zero_trust/devices/deployment_group_list_params.py new file mode 100644 index 00000000000..4c0295b4169 --- /dev/null +++ b/src/cloudflare/types/zero_trust/devices/deployment_group_list_params.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["DeploymentGroupListParams"] + + +class DeploymentGroupListParams(TypedDict, total=False): + account_id: Required[str] + + page: int + """The page number to return.""" + + per_page: int + """The maximum number of deployment groups to return per page.""" diff --git a/tests/api_resources/zero_trust/devices/test_deployment_groups.py b/tests/api_resources/zero_trust/devices/test_deployment_groups.py new file mode 100644 index 00000000000..99ad9758f85 --- /dev/null +++ b/tests/api_resources/zero_trust/devices/test_deployment_groups.py @@ -0,0 +1,604 @@ +# 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 pytest + +from cloudflare import Cloudflare, AsyncCloudflare +from tests.utils import assert_matches_type +from cloudflare.pagination import SyncV4PagePaginationArray, AsyncV4PagePaginationArray +from cloudflare.types.zero_trust.devices import ( + DeploymentGroup, + DeploymentGroupDeleteResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestDeploymentGroups: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Cloudflare) -> None: + deployment_group = client.zero_trust.devices.deployment_groups.create( + account_id="account_id", + name="Engineering Ring 0", + version_config=[ + { + "target_environment": "windows", + "version": "2026.5.234.0", + } + ], + ) + assert_matches_type(DeploymentGroup, deployment_group, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Cloudflare) -> None: + deployment_group = client.zero_trust.devices.deployment_groups.create( + account_id="account_id", + name="Engineering Ring 0", + version_config=[ + { + "target_environment": "windows", + "version": "2026.5.234.0", + } + ], + policy_ids=["string"], + ) + assert_matches_type(DeploymentGroup, deployment_group, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Cloudflare) -> None: + response = client.zero_trust.devices.deployment_groups.with_raw_response.create( + account_id="account_id", + name="Engineering Ring 0", + version_config=[ + { + "target_environment": "windows", + "version": "2026.5.234.0", + } + ], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment_group = response.parse() + assert_matches_type(DeploymentGroup, deployment_group, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Cloudflare) -> None: + with client.zero_trust.devices.deployment_groups.with_streaming_response.create( + account_id="account_id", + name="Engineering Ring 0", + version_config=[ + { + "target_environment": "windows", + "version": "2026.5.234.0", + } + ], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment_group = response.parse() + assert_matches_type(DeploymentGroup, deployment_group, 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.devices.deployment_groups.with_raw_response.create( + account_id="", + name="Engineering Ring 0", + version_config=[ + { + "target_environment": "windows", + "version": "2026.5.234.0", + } + ], + ) + + @parametrize + def test_method_list(self, client: Cloudflare) -> None: + deployment_group = client.zero_trust.devices.deployment_groups.list( + account_id="account_id", + ) + assert_matches_type(SyncV4PagePaginationArray[DeploymentGroup], deployment_group, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Cloudflare) -> None: + deployment_group = client.zero_trust.devices.deployment_groups.list( + account_id="account_id", + page=1, + per_page=1, + ) + assert_matches_type(SyncV4PagePaginationArray[DeploymentGroup], deployment_group, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Cloudflare) -> None: + response = client.zero_trust.devices.deployment_groups.with_raw_response.list( + account_id="account_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment_group = response.parse() + assert_matches_type(SyncV4PagePaginationArray[DeploymentGroup], deployment_group, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Cloudflare) -> None: + with client.zero_trust.devices.deployment_groups.with_streaming_response.list( + account_id="account_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment_group = response.parse() + assert_matches_type(SyncV4PagePaginationArray[DeploymentGroup], deployment_group, 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.devices.deployment_groups.with_raw_response.list( + account_id="", + ) + + @parametrize + def test_method_delete(self, client: Cloudflare) -> None: + deployment_group = client.zero_trust.devices.deployment_groups.delete( + group_id="group_id", + account_id="account_id", + ) + assert_matches_type(DeploymentGroupDeleteResponse, deployment_group, path=["response"]) + + @parametrize + def test_raw_response_delete(self, client: Cloudflare) -> None: + response = client.zero_trust.devices.deployment_groups.with_raw_response.delete( + group_id="group_id", + account_id="account_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment_group = response.parse() + assert_matches_type(DeploymentGroupDeleteResponse, deployment_group, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: Cloudflare) -> None: + with client.zero_trust.devices.deployment_groups.with_streaming_response.delete( + group_id="group_id", + account_id="account_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment_group = response.parse() + assert_matches_type(DeploymentGroupDeleteResponse, deployment_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_delete(self, client: Cloudflare) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): + client.zero_trust.devices.deployment_groups.with_raw_response.delete( + group_id="group_id", + account_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + client.zero_trust.devices.deployment_groups.with_raw_response.delete( + group_id="", + account_id="account_id", + ) + + @parametrize + def test_method_edit(self, client: Cloudflare) -> None: + deployment_group = client.zero_trust.devices.deployment_groups.edit( + group_id="group_id", + account_id="account_id", + ) + assert_matches_type(DeploymentGroup, deployment_group, path=["response"]) + + @parametrize + def test_method_edit_with_all_params(self, client: Cloudflare) -> None: + deployment_group = client.zero_trust.devices.deployment_groups.edit( + group_id="group_id", + account_id="account_id", + name="Engineering Ring 0", + policy_ids=["string"], + version_config=[ + { + "target_environment": "windows", + "version": "2026.5.234.0", + } + ], + ) + assert_matches_type(DeploymentGroup, deployment_group, path=["response"]) + + @parametrize + def test_raw_response_edit(self, client: Cloudflare) -> None: + response = client.zero_trust.devices.deployment_groups.with_raw_response.edit( + group_id="group_id", + account_id="account_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment_group = response.parse() + assert_matches_type(DeploymentGroup, deployment_group, path=["response"]) + + @parametrize + def test_streaming_response_edit(self, client: Cloudflare) -> None: + with client.zero_trust.devices.deployment_groups.with_streaming_response.edit( + group_id="group_id", + account_id="account_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment_group = response.parse() + assert_matches_type(DeploymentGroup, deployment_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_edit(self, client: Cloudflare) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): + client.zero_trust.devices.deployment_groups.with_raw_response.edit( + group_id="group_id", + account_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + client.zero_trust.devices.deployment_groups.with_raw_response.edit( + group_id="", + account_id="account_id", + ) + + @parametrize + def test_method_get(self, client: Cloudflare) -> None: + deployment_group = client.zero_trust.devices.deployment_groups.get( + group_id="group_id", + account_id="account_id", + ) + assert_matches_type(DeploymentGroup, deployment_group, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Cloudflare) -> None: + response = client.zero_trust.devices.deployment_groups.with_raw_response.get( + group_id="group_id", + account_id="account_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment_group = response.parse() + assert_matches_type(DeploymentGroup, deployment_group, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Cloudflare) -> None: + with client.zero_trust.devices.deployment_groups.with_streaming_response.get( + group_id="group_id", + account_id="account_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment_group = response.parse() + assert_matches_type(DeploymentGroup, deployment_group, 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.devices.deployment_groups.with_raw_response.get( + group_id="group_id", + account_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + client.zero_trust.devices.deployment_groups.with_raw_response.get( + group_id="", + account_id="account_id", + ) + + +class TestAsyncDeploymentGroups: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_create(self, async_client: AsyncCloudflare) -> None: + deployment_group = await async_client.zero_trust.devices.deployment_groups.create( + account_id="account_id", + name="Engineering Ring 0", + version_config=[ + { + "target_environment": "windows", + "version": "2026.5.234.0", + } + ], + ) + assert_matches_type(DeploymentGroup, deployment_group, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncCloudflare) -> None: + deployment_group = await async_client.zero_trust.devices.deployment_groups.create( + account_id="account_id", + name="Engineering Ring 0", + version_config=[ + { + "target_environment": "windows", + "version": "2026.5.234.0", + } + ], + policy_ids=["string"], + ) + assert_matches_type(DeploymentGroup, deployment_group, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncCloudflare) -> None: + response = await async_client.zero_trust.devices.deployment_groups.with_raw_response.create( + account_id="account_id", + name="Engineering Ring 0", + version_config=[ + { + "target_environment": "windows", + "version": "2026.5.234.0", + } + ], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment_group = await response.parse() + assert_matches_type(DeploymentGroup, deployment_group, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncCloudflare) -> None: + async with async_client.zero_trust.devices.deployment_groups.with_streaming_response.create( + account_id="account_id", + name="Engineering Ring 0", + version_config=[ + { + "target_environment": "windows", + "version": "2026.5.234.0", + } + ], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment_group = await response.parse() + assert_matches_type(DeploymentGroup, deployment_group, 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.devices.deployment_groups.with_raw_response.create( + account_id="", + name="Engineering Ring 0", + version_config=[ + { + "target_environment": "windows", + "version": "2026.5.234.0", + } + ], + ) + + @parametrize + async def test_method_list(self, async_client: AsyncCloudflare) -> None: + deployment_group = await async_client.zero_trust.devices.deployment_groups.list( + account_id="account_id", + ) + assert_matches_type(AsyncV4PagePaginationArray[DeploymentGroup], deployment_group, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncCloudflare) -> None: + deployment_group = await async_client.zero_trust.devices.deployment_groups.list( + account_id="account_id", + page=1, + per_page=1, + ) + assert_matches_type(AsyncV4PagePaginationArray[DeploymentGroup], deployment_group, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncCloudflare) -> None: + response = await async_client.zero_trust.devices.deployment_groups.with_raw_response.list( + account_id="account_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment_group = await response.parse() + assert_matches_type(AsyncV4PagePaginationArray[DeploymentGroup], deployment_group, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncCloudflare) -> None: + async with async_client.zero_trust.devices.deployment_groups.with_streaming_response.list( + account_id="account_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment_group = await response.parse() + assert_matches_type(AsyncV4PagePaginationArray[DeploymentGroup], deployment_group, 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.devices.deployment_groups.with_raw_response.list( + account_id="", + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncCloudflare) -> None: + deployment_group = await async_client.zero_trust.devices.deployment_groups.delete( + group_id="group_id", + account_id="account_id", + ) + assert_matches_type(DeploymentGroupDeleteResponse, deployment_group, path=["response"]) + + @parametrize + async def test_raw_response_delete(self, async_client: AsyncCloudflare) -> None: + response = await async_client.zero_trust.devices.deployment_groups.with_raw_response.delete( + group_id="group_id", + account_id="account_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment_group = await response.parse() + assert_matches_type(DeploymentGroupDeleteResponse, deployment_group, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncCloudflare) -> None: + async with async_client.zero_trust.devices.deployment_groups.with_streaming_response.delete( + group_id="group_id", + account_id="account_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment_group = await response.parse() + assert_matches_type(DeploymentGroupDeleteResponse, deployment_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_delete(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.devices.deployment_groups.with_raw_response.delete( + group_id="group_id", + account_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + await async_client.zero_trust.devices.deployment_groups.with_raw_response.delete( + group_id="", + account_id="account_id", + ) + + @parametrize + async def test_method_edit(self, async_client: AsyncCloudflare) -> None: + deployment_group = await async_client.zero_trust.devices.deployment_groups.edit( + group_id="group_id", + account_id="account_id", + ) + assert_matches_type(DeploymentGroup, deployment_group, path=["response"]) + + @parametrize + async def test_method_edit_with_all_params(self, async_client: AsyncCloudflare) -> None: + deployment_group = await async_client.zero_trust.devices.deployment_groups.edit( + group_id="group_id", + account_id="account_id", + name="Engineering Ring 0", + policy_ids=["string"], + version_config=[ + { + "target_environment": "windows", + "version": "2026.5.234.0", + } + ], + ) + assert_matches_type(DeploymentGroup, deployment_group, path=["response"]) + + @parametrize + async def test_raw_response_edit(self, async_client: AsyncCloudflare) -> None: + response = await async_client.zero_trust.devices.deployment_groups.with_raw_response.edit( + group_id="group_id", + account_id="account_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment_group = await response.parse() + assert_matches_type(DeploymentGroup, deployment_group, path=["response"]) + + @parametrize + async def test_streaming_response_edit(self, async_client: AsyncCloudflare) -> None: + async with async_client.zero_trust.devices.deployment_groups.with_streaming_response.edit( + group_id="group_id", + account_id="account_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment_group = await response.parse() + assert_matches_type(DeploymentGroup, deployment_group, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_edit(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.devices.deployment_groups.with_raw_response.edit( + group_id="group_id", + account_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + await async_client.zero_trust.devices.deployment_groups.with_raw_response.edit( + group_id="", + account_id="account_id", + ) + + @parametrize + async def test_method_get(self, async_client: AsyncCloudflare) -> None: + deployment_group = await async_client.zero_trust.devices.deployment_groups.get( + group_id="group_id", + account_id="account_id", + ) + assert_matches_type(DeploymentGroup, deployment_group, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncCloudflare) -> None: + response = await async_client.zero_trust.devices.deployment_groups.with_raw_response.get( + group_id="group_id", + account_id="account_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment_group = await response.parse() + assert_matches_type(DeploymentGroup, deployment_group, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncCloudflare) -> None: + async with async_client.zero_trust.devices.deployment_groups.with_streaming_response.get( + group_id="group_id", + account_id="account_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment_group = await response.parse() + assert_matches_type(DeploymentGroup, deployment_group, 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.devices.deployment_groups.with_raw_response.get( + group_id="group_id", + account_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_id` but received ''"): + await async_client.zero_trust.devices.deployment_groups.with_raw_response.get( + group_id="", + account_id="account_id", + ) From 051abef4e11e31f834515720a87028de965417fa Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 1 May 2026 19:25:02 +0000 Subject: [PATCH 27/45] feat: chore: skip failing deployment_groups tests --- .stats.yml | 2 +- .../devices/test_deployment_groups.py | 46 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 88038d23b32..3b853053e2c 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 2200 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a6c352830d1270d0abb5bb983058ea21815e1bb7d2e163965335dcb0e706f057.yml openapi_spec_hash: 4cd58fdf7a6fa895b2514a2e60d131b1 -config_hash: 98fb614048aec6722b11484583cc3819 +config_hash: a6f7ab07cd1fde3ee07c4cae6ed2d568 diff --git a/tests/api_resources/zero_trust/devices/test_deployment_groups.py b/tests/api_resources/zero_trust/devices/test_deployment_groups.py index 99ad9758f85..98dd6882828 100644 --- a/tests/api_resources/zero_trust/devices/test_deployment_groups.py +++ b/tests/api_resources/zero_trust/devices/test_deployment_groups.py @@ -21,6 +21,7 @@ class TestDeploymentGroups: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize def test_method_create(self, client: Cloudflare) -> None: deployment_group = client.zero_trust.devices.deployment_groups.create( @@ -35,6 +36,7 @@ def test_method_create(self, client: Cloudflare) -> None: ) assert_matches_type(DeploymentGroup, deployment_group, path=["response"]) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize def test_method_create_with_all_params(self, client: Cloudflare) -> None: deployment_group = client.zero_trust.devices.deployment_groups.create( @@ -50,6 +52,7 @@ def test_method_create_with_all_params(self, client: Cloudflare) -> None: ) assert_matches_type(DeploymentGroup, deployment_group, path=["response"]) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize def test_raw_response_create(self, client: Cloudflare) -> None: response = client.zero_trust.devices.deployment_groups.with_raw_response.create( @@ -68,6 +71,7 @@ def test_raw_response_create(self, client: Cloudflare) -> None: deployment_group = response.parse() assert_matches_type(DeploymentGroup, deployment_group, path=["response"]) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize def test_streaming_response_create(self, client: Cloudflare) -> None: with client.zero_trust.devices.deployment_groups.with_streaming_response.create( @@ -88,6 +92,7 @@ def test_streaming_response_create(self, client: Cloudflare) -> None: assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="HTTP 401 error from prism") @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 ''"): @@ -102,6 +107,7 @@ def test_path_params_create(self, client: Cloudflare) -> None: ], ) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize def test_method_list(self, client: Cloudflare) -> None: deployment_group = client.zero_trust.devices.deployment_groups.list( @@ -109,6 +115,7 @@ def test_method_list(self, client: Cloudflare) -> None: ) assert_matches_type(SyncV4PagePaginationArray[DeploymentGroup], deployment_group, path=["response"]) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize def test_method_list_with_all_params(self, client: Cloudflare) -> None: deployment_group = client.zero_trust.devices.deployment_groups.list( @@ -118,6 +125,7 @@ def test_method_list_with_all_params(self, client: Cloudflare) -> None: ) assert_matches_type(SyncV4PagePaginationArray[DeploymentGroup], deployment_group, path=["response"]) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize def test_raw_response_list(self, client: Cloudflare) -> None: response = client.zero_trust.devices.deployment_groups.with_raw_response.list( @@ -129,6 +137,7 @@ def test_raw_response_list(self, client: Cloudflare) -> None: deployment_group = response.parse() assert_matches_type(SyncV4PagePaginationArray[DeploymentGroup], deployment_group, path=["response"]) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize def test_streaming_response_list(self, client: Cloudflare) -> None: with client.zero_trust.devices.deployment_groups.with_streaming_response.list( @@ -142,6 +151,7 @@ def test_streaming_response_list(self, client: Cloudflare) -> None: assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="HTTP 401 error from prism") @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 ''"): @@ -149,6 +159,7 @@ def test_path_params_list(self, client: Cloudflare) -> None: account_id="", ) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize def test_method_delete(self, client: Cloudflare) -> None: deployment_group = client.zero_trust.devices.deployment_groups.delete( @@ -157,6 +168,7 @@ def test_method_delete(self, client: Cloudflare) -> None: ) assert_matches_type(DeploymentGroupDeleteResponse, deployment_group, path=["response"]) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize def test_raw_response_delete(self, client: Cloudflare) -> None: response = client.zero_trust.devices.deployment_groups.with_raw_response.delete( @@ -169,6 +181,7 @@ def test_raw_response_delete(self, client: Cloudflare) -> None: deployment_group = response.parse() assert_matches_type(DeploymentGroupDeleteResponse, deployment_group, path=["response"]) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize def test_streaming_response_delete(self, client: Cloudflare) -> None: with client.zero_trust.devices.deployment_groups.with_streaming_response.delete( @@ -183,6 +196,7 @@ def test_streaming_response_delete(self, client: Cloudflare) -> None: assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize def test_path_params_delete(self, client: Cloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): @@ -197,6 +211,7 @@ def test_path_params_delete(self, client: Cloudflare) -> None: account_id="account_id", ) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize def test_method_edit(self, client: Cloudflare) -> None: deployment_group = client.zero_trust.devices.deployment_groups.edit( @@ -205,6 +220,7 @@ def test_method_edit(self, client: Cloudflare) -> None: ) assert_matches_type(DeploymentGroup, deployment_group, path=["response"]) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize def test_method_edit_with_all_params(self, client: Cloudflare) -> None: deployment_group = client.zero_trust.devices.deployment_groups.edit( @@ -221,6 +237,7 @@ def test_method_edit_with_all_params(self, client: Cloudflare) -> None: ) assert_matches_type(DeploymentGroup, deployment_group, path=["response"]) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize def test_raw_response_edit(self, client: Cloudflare) -> None: response = client.zero_trust.devices.deployment_groups.with_raw_response.edit( @@ -233,6 +250,7 @@ def test_raw_response_edit(self, client: Cloudflare) -> None: deployment_group = response.parse() assert_matches_type(DeploymentGroup, deployment_group, path=["response"]) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize def test_streaming_response_edit(self, client: Cloudflare) -> None: with client.zero_trust.devices.deployment_groups.with_streaming_response.edit( @@ -247,6 +265,7 @@ def test_streaming_response_edit(self, client: Cloudflare) -> None: assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize def test_path_params_edit(self, client: Cloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): @@ -261,6 +280,7 @@ def test_path_params_edit(self, client: Cloudflare) -> None: account_id="account_id", ) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize def test_method_get(self, client: Cloudflare) -> None: deployment_group = client.zero_trust.devices.deployment_groups.get( @@ -269,6 +289,7 @@ def test_method_get(self, client: Cloudflare) -> None: ) assert_matches_type(DeploymentGroup, deployment_group, path=["response"]) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize def test_raw_response_get(self, client: Cloudflare) -> None: response = client.zero_trust.devices.deployment_groups.with_raw_response.get( @@ -281,6 +302,7 @@ def test_raw_response_get(self, client: Cloudflare) -> None: deployment_group = response.parse() assert_matches_type(DeploymentGroup, deployment_group, path=["response"]) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize def test_streaming_response_get(self, client: Cloudflare) -> None: with client.zero_trust.devices.deployment_groups.with_streaming_response.get( @@ -295,6 +317,7 @@ def test_streaming_response_get(self, client: Cloudflare) -> None: assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="HTTP 401 error from prism") @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 ''"): @@ -315,6 +338,7 @@ class TestAsyncDeploymentGroups: "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] ) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize async def test_method_create(self, async_client: AsyncCloudflare) -> None: deployment_group = await async_client.zero_trust.devices.deployment_groups.create( @@ -329,6 +353,7 @@ async def test_method_create(self, async_client: AsyncCloudflare) -> None: ) assert_matches_type(DeploymentGroup, deployment_group, path=["response"]) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize async def test_method_create_with_all_params(self, async_client: AsyncCloudflare) -> None: deployment_group = await async_client.zero_trust.devices.deployment_groups.create( @@ -344,6 +369,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncCloudflare ) assert_matches_type(DeploymentGroup, deployment_group, path=["response"]) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize async def test_raw_response_create(self, async_client: AsyncCloudflare) -> None: response = await async_client.zero_trust.devices.deployment_groups.with_raw_response.create( @@ -362,6 +388,7 @@ async def test_raw_response_create(self, async_client: AsyncCloudflare) -> None: deployment_group = await response.parse() assert_matches_type(DeploymentGroup, deployment_group, path=["response"]) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize async def test_streaming_response_create(self, async_client: AsyncCloudflare) -> None: async with async_client.zero_trust.devices.deployment_groups.with_streaming_response.create( @@ -382,6 +409,7 @@ async def test_streaming_response_create(self, async_client: AsyncCloudflare) -> assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="HTTP 401 error from prism") @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 ''"): @@ -396,6 +424,7 @@ async def test_path_params_create(self, async_client: AsyncCloudflare) -> None: ], ) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize async def test_method_list(self, async_client: AsyncCloudflare) -> None: deployment_group = await async_client.zero_trust.devices.deployment_groups.list( @@ -403,6 +432,7 @@ async def test_method_list(self, async_client: AsyncCloudflare) -> None: ) assert_matches_type(AsyncV4PagePaginationArray[DeploymentGroup], deployment_group, path=["response"]) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize async def test_method_list_with_all_params(self, async_client: AsyncCloudflare) -> None: deployment_group = await async_client.zero_trust.devices.deployment_groups.list( @@ -412,6 +442,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncCloudflare) ) assert_matches_type(AsyncV4PagePaginationArray[DeploymentGroup], deployment_group, path=["response"]) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize async def test_raw_response_list(self, async_client: AsyncCloudflare) -> None: response = await async_client.zero_trust.devices.deployment_groups.with_raw_response.list( @@ -423,6 +454,7 @@ async def test_raw_response_list(self, async_client: AsyncCloudflare) -> None: deployment_group = await response.parse() assert_matches_type(AsyncV4PagePaginationArray[DeploymentGroup], deployment_group, path=["response"]) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize async def test_streaming_response_list(self, async_client: AsyncCloudflare) -> None: async with async_client.zero_trust.devices.deployment_groups.with_streaming_response.list( @@ -436,6 +468,7 @@ async def test_streaming_response_list(self, async_client: AsyncCloudflare) -> N assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="HTTP 401 error from prism") @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 ''"): @@ -443,6 +476,7 @@ async def test_path_params_list(self, async_client: AsyncCloudflare) -> None: account_id="", ) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize async def test_method_delete(self, async_client: AsyncCloudflare) -> None: deployment_group = await async_client.zero_trust.devices.deployment_groups.delete( @@ -451,6 +485,7 @@ async def test_method_delete(self, async_client: AsyncCloudflare) -> None: ) assert_matches_type(DeploymentGroupDeleteResponse, deployment_group, path=["response"]) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize async def test_raw_response_delete(self, async_client: AsyncCloudflare) -> None: response = await async_client.zero_trust.devices.deployment_groups.with_raw_response.delete( @@ -463,6 +498,7 @@ async def test_raw_response_delete(self, async_client: AsyncCloudflare) -> None: deployment_group = await response.parse() assert_matches_type(DeploymentGroupDeleteResponse, deployment_group, path=["response"]) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize async def test_streaming_response_delete(self, async_client: AsyncCloudflare) -> None: async with async_client.zero_trust.devices.deployment_groups.with_streaming_response.delete( @@ -477,6 +513,7 @@ async def test_streaming_response_delete(self, async_client: AsyncCloudflare) -> assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize async def test_path_params_delete(self, async_client: AsyncCloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): @@ -491,6 +528,7 @@ async def test_path_params_delete(self, async_client: AsyncCloudflare) -> None: account_id="account_id", ) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize async def test_method_edit(self, async_client: AsyncCloudflare) -> None: deployment_group = await async_client.zero_trust.devices.deployment_groups.edit( @@ -499,6 +537,7 @@ async def test_method_edit(self, async_client: AsyncCloudflare) -> None: ) assert_matches_type(DeploymentGroup, deployment_group, path=["response"]) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize async def test_method_edit_with_all_params(self, async_client: AsyncCloudflare) -> None: deployment_group = await async_client.zero_trust.devices.deployment_groups.edit( @@ -515,6 +554,7 @@ async def test_method_edit_with_all_params(self, async_client: AsyncCloudflare) ) assert_matches_type(DeploymentGroup, deployment_group, path=["response"]) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize async def test_raw_response_edit(self, async_client: AsyncCloudflare) -> None: response = await async_client.zero_trust.devices.deployment_groups.with_raw_response.edit( @@ -527,6 +567,7 @@ async def test_raw_response_edit(self, async_client: AsyncCloudflare) -> None: deployment_group = await response.parse() assert_matches_type(DeploymentGroup, deployment_group, path=["response"]) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize async def test_streaming_response_edit(self, async_client: AsyncCloudflare) -> None: async with async_client.zero_trust.devices.deployment_groups.with_streaming_response.edit( @@ -541,6 +582,7 @@ async def test_streaming_response_edit(self, async_client: AsyncCloudflare) -> N assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize async def test_path_params_edit(self, async_client: AsyncCloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"): @@ -555,6 +597,7 @@ async def test_path_params_edit(self, async_client: AsyncCloudflare) -> None: account_id="account_id", ) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize async def test_method_get(self, async_client: AsyncCloudflare) -> None: deployment_group = await async_client.zero_trust.devices.deployment_groups.get( @@ -563,6 +606,7 @@ async def test_method_get(self, async_client: AsyncCloudflare) -> None: ) assert_matches_type(DeploymentGroup, deployment_group, path=["response"]) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize async def test_raw_response_get(self, async_client: AsyncCloudflare) -> None: response = await async_client.zero_trust.devices.deployment_groups.with_raw_response.get( @@ -575,6 +619,7 @@ async def test_raw_response_get(self, async_client: AsyncCloudflare) -> None: deployment_group = await response.parse() assert_matches_type(DeploymentGroup, deployment_group, path=["response"]) + @pytest.mark.skip(reason="HTTP 401 error from prism") @parametrize async def test_streaming_response_get(self, async_client: AsyncCloudflare) -> None: async with async_client.zero_trust.devices.deployment_groups.with_streaming_response.get( @@ -589,6 +634,7 @@ async def test_streaming_response_get(self, async_client: AsyncCloudflare) -> No assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="HTTP 401 error from prism") @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 ''"): From 90bfedc81916be83963190dfb2df93b968998896 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 2 May 2026 06:09:06 +0000 Subject: [PATCH 28/45] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 3b853053e2c..18f0f9afb04 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 2200 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a6c352830d1270d0abb5bb983058ea21815e1bb7d2e163965335dcb0e706f057.yml -openapi_spec_hash: 4cd58fdf7a6fa895b2514a2e60d131b1 +openapi_spec_hash: eefd0341bf7de31f0e0fa3f4020bee7c config_hash: a6f7ab07cd1fde3ee07c4cae6ed2d568 From 66b18de30ac617bbaf9caf5a601eaf1a063c5e28 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 4 May 2026 13:31:50 +0000 Subject: [PATCH 29/45] chore(api): update composite API spec --- .stats.yml | 2 +- .../resources/aisearch/instances/instances.py | 34 ++++++++++++++++--- .../namespaces/instances/instances.py | 34 ++++++++++++++++--- .../types/aisearch/instance_create_params.py | 7 ++++ .../aisearch/instance_create_response.py | 7 ++++ .../aisearch/instance_delete_response.py | 7 ++++ .../types/aisearch/instance_list_response.py | 7 ++++ .../types/aisearch/instance_read_response.py | 7 ++++ .../types/aisearch/instance_update_params.py | 7 ++++ .../aisearch/instance_update_response.py | 7 ++++ .../namespaces/instance_create_params.py | 7 ++++ .../namespaces/instance_create_response.py | 7 ++++ .../namespaces/instance_delete_response.py | 7 ++++ .../namespaces/instance_list_response.py | 7 ++++ .../namespaces/instance_read_response.py | 7 ++++ .../namespaces/instance_update_params.py | 7 ++++ .../namespaces/instance_update_response.py | 7 ++++ .../aisearch/namespaces/test_instances.py | 4 +++ .../api_resources/aisearch/test_instances.py | 4 +++ 19 files changed, 167 insertions(+), 9 deletions(-) diff --git a/.stats.yml b/.stats.yml index 18f0f9afb04..aa55cc098a9 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 2200 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a6c352830d1270d0abb5bb983058ea21815e1bb7d2e163965335dcb0e706f057.yml -openapi_spec_hash: eefd0341bf7de31f0e0fa3f4020bee7c +openapi_spec_hash: 887efce5205bdef9eec55d574113ef5b config_hash: a6f7ab07cd1fde3ee07c4cae6ed2d568 diff --git a/src/cloudflare/resources/aisearch/instances/instances.py b/src/cloudflare/resources/aisearch/instances/instances.py index 0b4aa0f18c3..58da83de22e 100644 --- a/src/cloudflare/resources/aisearch/instances/instances.py +++ b/src/cloudflare/resources/aisearch/instances/instances.py @@ -115,6 +115,7 @@ def create( cache: bool | Omit = omit, cache_threshold: Literal["super_strict_match", "close_enough", "flexible_friend", "anything_goes"] | Omit = omit, + cache_ttl: Literal[600, 1800, 3600, 7200, 21600, 43200, 86400, 172800, 259200, 518400] | Omit = omit, chunk: bool | Omit = omit, chunk_overlap: int | Omit = omit, chunk_size: int | Omit = omit, @@ -199,6 +200,10 @@ def create( Lowercase alphanumeric, hyphens, and underscores. + cache_ttl: Cache entry TTL in seconds. Allowed values: 600 (10min), 1800 (30min), 3600 + (1h), 7200 (2h), 21600 (6h), 43200 (12h), 86400 (24h), 172800 (48h), 259200 + (72h), 518400 (6d). + hybrid_search_enabled: Deprecated — use index_method instead. index_method: Controls which storage backends are used during indexing. Defaults to @@ -226,6 +231,7 @@ def create( "aisearch_model": aisearch_model, "cache": cache, "cache_threshold": cache_threshold, + "cache_ttl": cache_ttl, "chunk": chunk, "chunk_overlap": chunk_overlap, "chunk_size": chunk_size, @@ -306,6 +312,7 @@ def update( cache: bool | Omit = omit, cache_threshold: Literal["super_strict_match", "close_enough", "flexible_friend", "anything_goes"] | Omit = omit, + cache_ttl: Literal[600, 1800, 3600, 7200, 21600, 43200, 86400, 172800, 259200, 518400] | Omit = omit, chunk: bool | Omit = omit, chunk_overlap: int | Omit = omit, chunk_size: int | Omit = omit, @@ -420,10 +427,15 @@ def update( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> InstanceUpdateResponse: - """ - Update instance. + """Update instance. Args: + cache_ttl: Cache entry TTL in seconds. + + Allowed values: 600 (10min), 1800 (30min), 3600 + (1h), 7200 (2h), 21600 (6h), 43200 (12h), 86400 (24h), 172800 (48h), 259200 + (72h), 518400 (6d). + index_method: Controls which storage backends are used during indexing. Defaults to vector-only. @@ -450,6 +462,7 @@ def update( "aisearch_model": aisearch_model, "cache": cache, "cache_threshold": cache_threshold, + "cache_ttl": cache_ttl, "chunk": chunk, "chunk_overlap": chunk_overlap, "chunk_size": chunk_size, @@ -889,6 +902,7 @@ async def create( cache: bool | Omit = omit, cache_threshold: Literal["super_strict_match", "close_enough", "flexible_friend", "anything_goes"] | Omit = omit, + cache_ttl: Literal[600, 1800, 3600, 7200, 21600, 43200, 86400, 172800, 259200, 518400] | Omit = omit, chunk: bool | Omit = omit, chunk_overlap: int | Omit = omit, chunk_size: int | Omit = omit, @@ -973,6 +987,10 @@ async def create( Lowercase alphanumeric, hyphens, and underscores. + cache_ttl: Cache entry TTL in seconds. Allowed values: 600 (10min), 1800 (30min), 3600 + (1h), 7200 (2h), 21600 (6h), 43200 (12h), 86400 (24h), 172800 (48h), 259200 + (72h), 518400 (6d). + hybrid_search_enabled: Deprecated — use index_method instead. index_method: Controls which storage backends are used during indexing. Defaults to @@ -1000,6 +1018,7 @@ async def create( "aisearch_model": aisearch_model, "cache": cache, "cache_threshold": cache_threshold, + "cache_ttl": cache_ttl, "chunk": chunk, "chunk_overlap": chunk_overlap, "chunk_size": chunk_size, @@ -1080,6 +1099,7 @@ async def update( cache: bool | Omit = omit, cache_threshold: Literal["super_strict_match", "close_enough", "flexible_friend", "anything_goes"] | Omit = omit, + cache_ttl: Literal[600, 1800, 3600, 7200, 21600, 43200, 86400, 172800, 259200, 518400] | Omit = omit, chunk: bool | Omit = omit, chunk_overlap: int | Omit = omit, chunk_size: int | Omit = omit, @@ -1194,10 +1214,15 @@ async def update( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> InstanceUpdateResponse: - """ - Update instance. + """Update instance. Args: + cache_ttl: Cache entry TTL in seconds. + + Allowed values: 600 (10min), 1800 (30min), 3600 + (1h), 7200 (2h), 21600 (6h), 43200 (12h), 86400 (24h), 172800 (48h), 259200 + (72h), 518400 (6d). + index_method: Controls which storage backends are used during indexing. Defaults to vector-only. @@ -1224,6 +1249,7 @@ async def update( "aisearch_model": aisearch_model, "cache": cache, "cache_threshold": cache_threshold, + "cache_ttl": cache_ttl, "chunk": chunk, "chunk_overlap": chunk_overlap, "chunk_size": chunk_size, diff --git a/src/cloudflare/resources/aisearch/namespaces/instances/instances.py b/src/cloudflare/resources/aisearch/namespaces/instances/instances.py index d13a23fec7b..c0859761db9 100644 --- a/src/cloudflare/resources/aisearch/namespaces/instances/instances.py +++ b/src/cloudflare/resources/aisearch/namespaces/instances/instances.py @@ -128,6 +128,7 @@ def create( cache: bool | Omit = omit, cache_threshold: Literal["super_strict_match", "close_enough", "flexible_friend", "anything_goes"] | Omit = omit, + cache_ttl: Literal[600, 1800, 3600, 7200, 21600, 43200, 86400, 172800, 259200, 518400] | Omit = omit, chunk: bool | Omit = omit, chunk_overlap: int | Omit = omit, chunk_size: int | Omit = omit, @@ -212,6 +213,10 @@ def create( Lowercase alphanumeric, hyphens, and underscores. + cache_ttl: Cache entry TTL in seconds. Allowed values: 600 (10min), 1800 (30min), 3600 + (1h), 7200 (2h), 21600 (6h), 43200 (12h), 86400 (24h), 172800 (48h), 259200 + (72h), 518400 (6d). + hybrid_search_enabled: Deprecated — use index_method instead. index_method: Controls which storage backends are used during indexing. Defaults to @@ -243,6 +248,7 @@ def create( "aisearch_model": aisearch_model, "cache": cache, "cache_threshold": cache_threshold, + "cache_ttl": cache_ttl, "chunk": chunk, "chunk_overlap": chunk_overlap, "chunk_size": chunk_size, @@ -324,6 +330,7 @@ def update( cache: bool | Omit = omit, cache_threshold: Literal["super_strict_match", "close_enough", "flexible_friend", "anything_goes"] | Omit = omit, + cache_ttl: Literal[600, 1800, 3600, 7200, 21600, 43200, 86400, 172800, 259200, 518400] | Omit = omit, chunk: bool | Omit = omit, chunk_overlap: int | Omit = omit, chunk_size: int | Omit = omit, @@ -438,10 +445,15 @@ def update( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> InstanceUpdateResponse: - """ - Update instance. + """Update instance. Args: + cache_ttl: Cache entry TTL in seconds. + + Allowed values: 600 (10min), 1800 (30min), 3600 + (1h), 7200 (2h), 21600 (6h), 43200 (12h), 86400 (24h), 172800 (48h), 259200 + (72h), 518400 (6d). + index_method: Controls which storage backends are used during indexing. Defaults to vector-only. @@ -475,6 +487,7 @@ def update( "aisearch_model": aisearch_model, "cache": cache, "cache_threshold": cache_threshold, + "cache_ttl": cache_ttl, "chunk": chunk, "chunk_overlap": chunk_overlap, "chunk_size": chunk_size, @@ -962,6 +975,7 @@ async def create( cache: bool | Omit = omit, cache_threshold: Literal["super_strict_match", "close_enough", "flexible_friend", "anything_goes"] | Omit = omit, + cache_ttl: Literal[600, 1800, 3600, 7200, 21600, 43200, 86400, 172800, 259200, 518400] | Omit = omit, chunk: bool | Omit = omit, chunk_overlap: int | Omit = omit, chunk_size: int | Omit = omit, @@ -1046,6 +1060,10 @@ async def create( Lowercase alphanumeric, hyphens, and underscores. + cache_ttl: Cache entry TTL in seconds. Allowed values: 600 (10min), 1800 (30min), 3600 + (1h), 7200 (2h), 21600 (6h), 43200 (12h), 86400 (24h), 172800 (48h), 259200 + (72h), 518400 (6d). + hybrid_search_enabled: Deprecated — use index_method instead. index_method: Controls which storage backends are used during indexing. Defaults to @@ -1077,6 +1095,7 @@ async def create( "aisearch_model": aisearch_model, "cache": cache, "cache_threshold": cache_threshold, + "cache_ttl": cache_ttl, "chunk": chunk, "chunk_overlap": chunk_overlap, "chunk_size": chunk_size, @@ -1158,6 +1177,7 @@ async def update( cache: bool | Omit = omit, cache_threshold: Literal["super_strict_match", "close_enough", "flexible_friend", "anything_goes"] | Omit = omit, + cache_ttl: Literal[600, 1800, 3600, 7200, 21600, 43200, 86400, 172800, 259200, 518400] | Omit = omit, chunk: bool | Omit = omit, chunk_overlap: int | Omit = omit, chunk_size: int | Omit = omit, @@ -1272,10 +1292,15 @@ async def update( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> InstanceUpdateResponse: - """ - Update instance. + """Update instance. Args: + cache_ttl: Cache entry TTL in seconds. + + Allowed values: 600 (10min), 1800 (30min), 3600 + (1h), 7200 (2h), 21600 (6h), 43200 (12h), 86400 (24h), 172800 (48h), 259200 + (72h), 518400 (6d). + index_method: Controls which storage backends are used during indexing. Defaults to vector-only. @@ -1309,6 +1334,7 @@ async def update( "aisearch_model": aisearch_model, "cache": cache, "cache_threshold": cache_threshold, + "cache_ttl": cache_ttl, "chunk": chunk, "chunk_overlap": chunk_overlap, "chunk_size": chunk_size, diff --git a/src/cloudflare/types/aisearch/instance_create_params.py b/src/cloudflare/types/aisearch/instance_create_params.py index 23246fed684..66b6ae9f39b 100644 --- a/src/cloudflare/types/aisearch/instance_create_params.py +++ b/src/cloudflare/types/aisearch/instance_create_params.py @@ -81,6 +81,13 @@ class InstanceCreateParams(TypedDict, total=False): cache_threshold: Literal["super_strict_match", "close_enough", "flexible_friend", "anything_goes"] + cache_ttl: Literal[600, 1800, 3600, 7200, 21600, 43200, 86400, 172800, 259200, 518400] + """Cache entry TTL in seconds. + + Allowed values: 600 (10min), 1800 (30min), 3600 (1h), 7200 (2h), 21600 (6h), + 43200 (12h), 86400 (24h), 172800 (48h), 259200 (72h), 518400 (6d). + """ + chunk: bool chunk_overlap: int diff --git a/src/cloudflare/types/aisearch/instance_create_response.py b/src/cloudflare/types/aisearch/instance_create_response.py index 9640f00c300..29f8aa3e5a1 100644 --- a/src/cloudflare/types/aisearch/instance_create_response.py +++ b/src/cloudflare/types/aisearch/instance_create_response.py @@ -282,6 +282,13 @@ class InstanceCreateResponse(BaseModel): cache_threshold: Optional[Literal["super_strict_match", "close_enough", "flexible_friend", "anything_goes"]] = None + cache_ttl: Optional[Literal[600, 1800, 3600, 7200, 21600, 43200, 86400, 172800, 259200, 518400]] = None + """Cache entry TTL in seconds. + + Allowed values: 600 (10min), 1800 (30min), 3600 (1h), 7200 (2h), 21600 (6h), + 43200 (12h), 86400 (24h), 172800 (48h), 259200 (72h), 518400 (6d). + """ + chunk_overlap: Optional[int] = None chunk_size: Optional[int] = None diff --git a/src/cloudflare/types/aisearch/instance_delete_response.py b/src/cloudflare/types/aisearch/instance_delete_response.py index d58c218ba08..63b7cc489f8 100644 --- a/src/cloudflare/types/aisearch/instance_delete_response.py +++ b/src/cloudflare/types/aisearch/instance_delete_response.py @@ -282,6 +282,13 @@ class InstanceDeleteResponse(BaseModel): cache_threshold: Optional[Literal["super_strict_match", "close_enough", "flexible_friend", "anything_goes"]] = None + cache_ttl: Optional[Literal[600, 1800, 3600, 7200, 21600, 43200, 86400, 172800, 259200, 518400]] = None + """Cache entry TTL in seconds. + + Allowed values: 600 (10min), 1800 (30min), 3600 (1h), 7200 (2h), 21600 (6h), + 43200 (12h), 86400 (24h), 172800 (48h), 259200 (72h), 518400 (6d). + """ + chunk_overlap: Optional[int] = None chunk_size: Optional[int] = None diff --git a/src/cloudflare/types/aisearch/instance_list_response.py b/src/cloudflare/types/aisearch/instance_list_response.py index 23678ce553e..725f969e08d 100644 --- a/src/cloudflare/types/aisearch/instance_list_response.py +++ b/src/cloudflare/types/aisearch/instance_list_response.py @@ -282,6 +282,13 @@ class InstanceListResponse(BaseModel): cache_threshold: Optional[Literal["super_strict_match", "close_enough", "flexible_friend", "anything_goes"]] = None + cache_ttl: Optional[Literal[600, 1800, 3600, 7200, 21600, 43200, 86400, 172800, 259200, 518400]] = None + """Cache entry TTL in seconds. + + Allowed values: 600 (10min), 1800 (30min), 3600 (1h), 7200 (2h), 21600 (6h), + 43200 (12h), 86400 (24h), 172800 (48h), 259200 (72h), 518400 (6d). + """ + chunk_overlap: Optional[int] = None chunk_size: Optional[int] = None diff --git a/src/cloudflare/types/aisearch/instance_read_response.py b/src/cloudflare/types/aisearch/instance_read_response.py index 45eaeae759e..dc0a8c18c72 100644 --- a/src/cloudflare/types/aisearch/instance_read_response.py +++ b/src/cloudflare/types/aisearch/instance_read_response.py @@ -282,6 +282,13 @@ class InstanceReadResponse(BaseModel): cache_threshold: Optional[Literal["super_strict_match", "close_enough", "flexible_friend", "anything_goes"]] = None + cache_ttl: Optional[Literal[600, 1800, 3600, 7200, 21600, 43200, 86400, 172800, 259200, 518400]] = None + """Cache entry TTL in seconds. + + Allowed values: 600 (10min), 1800 (30min), 3600 (1h), 7200 (2h), 21600 (6h), + 43200 (12h), 86400 (24h), 172800 (48h), 259200 (72h), 518400 (6d). + """ + chunk_overlap: Optional[int] = None chunk_size: Optional[int] = None diff --git a/src/cloudflare/types/aisearch/instance_update_params.py b/src/cloudflare/types/aisearch/instance_update_params.py index 549194bf577..fddda6864f0 100644 --- a/src/cloudflare/types/aisearch/instance_update_params.py +++ b/src/cloudflare/types/aisearch/instance_update_params.py @@ -78,6 +78,13 @@ class InstanceUpdateParams(TypedDict, total=False): cache_threshold: Literal["super_strict_match", "close_enough", "flexible_friend", "anything_goes"] + cache_ttl: Literal[600, 1800, 3600, 7200, 21600, 43200, 86400, 172800, 259200, 518400] + """Cache entry TTL in seconds. + + Allowed values: 600 (10min), 1800 (30min), 3600 (1h), 7200 (2h), 21600 (6h), + 43200 (12h), 86400 (24h), 172800 (48h), 259200 (72h), 518400 (6d). + """ + chunk: bool chunk_overlap: int diff --git a/src/cloudflare/types/aisearch/instance_update_response.py b/src/cloudflare/types/aisearch/instance_update_response.py index 5abc922e677..379e9d7b207 100644 --- a/src/cloudflare/types/aisearch/instance_update_response.py +++ b/src/cloudflare/types/aisearch/instance_update_response.py @@ -282,6 +282,13 @@ class InstanceUpdateResponse(BaseModel): cache_threshold: Optional[Literal["super_strict_match", "close_enough", "flexible_friend", "anything_goes"]] = None + cache_ttl: Optional[Literal[600, 1800, 3600, 7200, 21600, 43200, 86400, 172800, 259200, 518400]] = None + """Cache entry TTL in seconds. + + Allowed values: 600 (10min), 1800 (30min), 3600 (1h), 7200 (2h), 21600 (6h), + 43200 (12h), 86400 (24h), 172800 (48h), 259200 (72h), 518400 (6d). + """ + chunk_overlap: Optional[int] = None chunk_size: Optional[int] = None diff --git a/src/cloudflare/types/aisearch/namespaces/instance_create_params.py b/src/cloudflare/types/aisearch/namespaces/instance_create_params.py index d8f8a70a6cc..10493f5da1a 100644 --- a/src/cloudflare/types/aisearch/namespaces/instance_create_params.py +++ b/src/cloudflare/types/aisearch/namespaces/instance_create_params.py @@ -81,6 +81,13 @@ class InstanceCreateParams(TypedDict, total=False): cache_threshold: Literal["super_strict_match", "close_enough", "flexible_friend", "anything_goes"] + cache_ttl: Literal[600, 1800, 3600, 7200, 21600, 43200, 86400, 172800, 259200, 518400] + """Cache entry TTL in seconds. + + Allowed values: 600 (10min), 1800 (30min), 3600 (1h), 7200 (2h), 21600 (6h), + 43200 (12h), 86400 (24h), 172800 (48h), 259200 (72h), 518400 (6d). + """ + chunk: bool chunk_overlap: int diff --git a/src/cloudflare/types/aisearch/namespaces/instance_create_response.py b/src/cloudflare/types/aisearch/namespaces/instance_create_response.py index 0dee72d00d8..3e320dec61a 100644 --- a/src/cloudflare/types/aisearch/namespaces/instance_create_response.py +++ b/src/cloudflare/types/aisearch/namespaces/instance_create_response.py @@ -282,6 +282,13 @@ class InstanceCreateResponse(BaseModel): cache_threshold: Optional[Literal["super_strict_match", "close_enough", "flexible_friend", "anything_goes"]] = None + cache_ttl: Optional[Literal[600, 1800, 3600, 7200, 21600, 43200, 86400, 172800, 259200, 518400]] = None + """Cache entry TTL in seconds. + + Allowed values: 600 (10min), 1800 (30min), 3600 (1h), 7200 (2h), 21600 (6h), + 43200 (12h), 86400 (24h), 172800 (48h), 259200 (72h), 518400 (6d). + """ + chunk_overlap: Optional[int] = None chunk_size: Optional[int] = None diff --git a/src/cloudflare/types/aisearch/namespaces/instance_delete_response.py b/src/cloudflare/types/aisearch/namespaces/instance_delete_response.py index e870f6fc530..6caf390c7f4 100644 --- a/src/cloudflare/types/aisearch/namespaces/instance_delete_response.py +++ b/src/cloudflare/types/aisearch/namespaces/instance_delete_response.py @@ -282,6 +282,13 @@ class InstanceDeleteResponse(BaseModel): cache_threshold: Optional[Literal["super_strict_match", "close_enough", "flexible_friend", "anything_goes"]] = None + cache_ttl: Optional[Literal[600, 1800, 3600, 7200, 21600, 43200, 86400, 172800, 259200, 518400]] = None + """Cache entry TTL in seconds. + + Allowed values: 600 (10min), 1800 (30min), 3600 (1h), 7200 (2h), 21600 (6h), + 43200 (12h), 86400 (24h), 172800 (48h), 259200 (72h), 518400 (6d). + """ + chunk_overlap: Optional[int] = None chunk_size: Optional[int] = None diff --git a/src/cloudflare/types/aisearch/namespaces/instance_list_response.py b/src/cloudflare/types/aisearch/namespaces/instance_list_response.py index fa59d4b6eaa..70f2d02faf3 100644 --- a/src/cloudflare/types/aisearch/namespaces/instance_list_response.py +++ b/src/cloudflare/types/aisearch/namespaces/instance_list_response.py @@ -282,6 +282,13 @@ class InstanceListResponse(BaseModel): cache_threshold: Optional[Literal["super_strict_match", "close_enough", "flexible_friend", "anything_goes"]] = None + cache_ttl: Optional[Literal[600, 1800, 3600, 7200, 21600, 43200, 86400, 172800, 259200, 518400]] = None + """Cache entry TTL in seconds. + + Allowed values: 600 (10min), 1800 (30min), 3600 (1h), 7200 (2h), 21600 (6h), + 43200 (12h), 86400 (24h), 172800 (48h), 259200 (72h), 518400 (6d). + """ + chunk_overlap: Optional[int] = None chunk_size: Optional[int] = None diff --git a/src/cloudflare/types/aisearch/namespaces/instance_read_response.py b/src/cloudflare/types/aisearch/namespaces/instance_read_response.py index bf2763a2eeb..1c2e469c282 100644 --- a/src/cloudflare/types/aisearch/namespaces/instance_read_response.py +++ b/src/cloudflare/types/aisearch/namespaces/instance_read_response.py @@ -282,6 +282,13 @@ class InstanceReadResponse(BaseModel): cache_threshold: Optional[Literal["super_strict_match", "close_enough", "flexible_friend", "anything_goes"]] = None + cache_ttl: Optional[Literal[600, 1800, 3600, 7200, 21600, 43200, 86400, 172800, 259200, 518400]] = None + """Cache entry TTL in seconds. + + Allowed values: 600 (10min), 1800 (30min), 3600 (1h), 7200 (2h), 21600 (6h), + 43200 (12h), 86400 (24h), 172800 (48h), 259200 (72h), 518400 (6d). + """ + chunk_overlap: Optional[int] = None chunk_size: Optional[int] = None diff --git a/src/cloudflare/types/aisearch/namespaces/instance_update_params.py b/src/cloudflare/types/aisearch/namespaces/instance_update_params.py index 0834d5ab51c..057cd3d1241 100644 --- a/src/cloudflare/types/aisearch/namespaces/instance_update_params.py +++ b/src/cloudflare/types/aisearch/namespaces/instance_update_params.py @@ -80,6 +80,13 @@ class InstanceUpdateParams(TypedDict, total=False): cache_threshold: Literal["super_strict_match", "close_enough", "flexible_friend", "anything_goes"] + cache_ttl: Literal[600, 1800, 3600, 7200, 21600, 43200, 86400, 172800, 259200, 518400] + """Cache entry TTL in seconds. + + Allowed values: 600 (10min), 1800 (30min), 3600 (1h), 7200 (2h), 21600 (6h), + 43200 (12h), 86400 (24h), 172800 (48h), 259200 (72h), 518400 (6d). + """ + chunk: bool chunk_overlap: int diff --git a/src/cloudflare/types/aisearch/namespaces/instance_update_response.py b/src/cloudflare/types/aisearch/namespaces/instance_update_response.py index 6410208a0d7..7de705537a7 100644 --- a/src/cloudflare/types/aisearch/namespaces/instance_update_response.py +++ b/src/cloudflare/types/aisearch/namespaces/instance_update_response.py @@ -282,6 +282,13 @@ class InstanceUpdateResponse(BaseModel): cache_threshold: Optional[Literal["super_strict_match", "close_enough", "flexible_friend", "anything_goes"]] = None + cache_ttl: Optional[Literal[600, 1800, 3600, 7200, 21600, 43200, 86400, 172800, 259200, 518400]] = None + """Cache entry TTL in seconds. + + Allowed values: 600 (10min), 1800 (30min), 3600 (1h), 7200 (2h), 21600 (6h), + 43200 (12h), 86400 (24h), 172800 (48h), 259200 (72h), 518400 (6d). + """ + chunk_overlap: Optional[int] = None chunk_size: Optional[int] = None diff --git a/tests/api_resources/aisearch/namespaces/test_instances.py b/tests/api_resources/aisearch/namespaces/test_instances.py index ceaff00d4be..4190bfaa776 100644 --- a/tests/api_resources/aisearch/namespaces/test_instances.py +++ b/tests/api_resources/aisearch/namespaces/test_instances.py @@ -46,6 +46,7 @@ def test_method_create_with_all_params(self, client: Cloudflare) -> None: aisearch_model="@cf/meta/llama-3.3-70b-instruct-fp8-fast", cache=True, cache_threshold="super_strict_match", + cache_ttl=600, chunk=True, chunk_overlap=0, chunk_size=64, @@ -203,6 +204,7 @@ def test_method_update_with_all_params(self, client: Cloudflare) -> None: aisearch_model="@cf/meta/llama-3.3-70b-instruct-fp8-fast", cache=True, cache_threshold="super_strict_match", + cache_ttl=600, chunk=True, chunk_overlap=0, chunk_size=64, @@ -871,6 +873,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncCloudflare aisearch_model="@cf/meta/llama-3.3-70b-instruct-fp8-fast", cache=True, cache_threshold="super_strict_match", + cache_ttl=600, chunk=True, chunk_overlap=0, chunk_size=64, @@ -1028,6 +1031,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncCloudflare aisearch_model="@cf/meta/llama-3.3-70b-instruct-fp8-fast", cache=True, cache_threshold="super_strict_match", + cache_ttl=600, chunk=True, chunk_overlap=0, chunk_size=64, diff --git a/tests/api_resources/aisearch/test_instances.py b/tests/api_resources/aisearch/test_instances.py index 033ed5e4825..1aaf5fde4e6 100644 --- a/tests/api_resources/aisearch/test_instances.py +++ b/tests/api_resources/aisearch/test_instances.py @@ -44,6 +44,7 @@ def test_method_create_with_all_params(self, client: Cloudflare) -> None: aisearch_model="@cf/meta/llama-3.3-70b-instruct-fp8-fast", cache=True, cache_threshold="super_strict_match", + cache_ttl=600, chunk=True, chunk_overlap=0, chunk_size=64, @@ -189,6 +190,7 @@ def test_method_update_with_all_params(self, client: Cloudflare) -> None: aisearch_model="@cf/meta/llama-3.3-70b-instruct-fp8-fast", cache=True, cache_threshold="super_strict_match", + cache_ttl=600, chunk=True, chunk_overlap=0, chunk_size=64, @@ -765,6 +767,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncCloudflare aisearch_model="@cf/meta/llama-3.3-70b-instruct-fp8-fast", cache=True, cache_threshold="super_strict_match", + cache_ttl=600, chunk=True, chunk_overlap=0, chunk_size=64, @@ -910,6 +913,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncCloudflare aisearch_model="@cf/meta/llama-3.3-70b-instruct-fp8-fast", cache=True, cache_threshold="super_strict_match", + cache_ttl=600, chunk=True, chunk_overlap=0, chunk_size=64, From 2a4624bf4111c8f07c7ce0c58298cc5c961fc47c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 4 May 2026 15:47:02 +0000 Subject: [PATCH 30/45] feat: feat(SCTR): add audit log, classification, and context endpoints to Security Center API * feat(SCTR): add audit log, classification, and context endpoints to Security Center API --- .stats.yml | 4 +- .../resources/security_center/api.md | 40 ++ .../security_center/insights/__init__.py | 42 ++ .../security_center/insights/audit_logs.py | 489 ++++++++++++++++++ .../insights/classification.py | 250 +++++++++ .../security_center/insights/context.py | 197 +++++++ .../security_center/insights/insights.py | 96 ++++ .../security_center/insights/__init__.py | 7 + .../audit_log_list_by_insight_params.py | 43 ++ .../audit_log_list_by_insight_response.py | 44 ++ .../insights/audit_log_list_params.py | 43 ++ .../insights/audit_log_list_response.py | 44 ++ .../insights/classification_update_params.py | 28 + .../classification_update_response.py | 45 ++ .../insights/context_get_response.py | 8 + .../insights/test_audit_logs.py | 281 ++++++++++ .../insights/test_classification.py | 152 ++++++ .../security_center/insights/test_context.py | 120 +++++ 18 files changed, 1931 insertions(+), 2 deletions(-) create mode 100644 src/cloudflare/resources/security_center/insights/audit_logs.py create mode 100644 src/cloudflare/resources/security_center/insights/classification.py create mode 100644 src/cloudflare/resources/security_center/insights/context.py create mode 100644 src/cloudflare/types/security_center/insights/audit_log_list_by_insight_params.py create mode 100644 src/cloudflare/types/security_center/insights/audit_log_list_by_insight_response.py create mode 100644 src/cloudflare/types/security_center/insights/audit_log_list_params.py create mode 100644 src/cloudflare/types/security_center/insights/audit_log_list_response.py create mode 100644 src/cloudflare/types/security_center/insights/classification_update_params.py create mode 100644 src/cloudflare/types/security_center/insights/classification_update_response.py create mode 100644 src/cloudflare/types/security_center/insights/context_get_response.py create mode 100644 tests/api_resources/security_center/insights/test_audit_logs.py create mode 100644 tests/api_resources/security_center/insights/test_classification.py create mode 100644 tests/api_resources/security_center/insights/test_context.py diff --git a/.stats.yml b/.stats.yml index aa55cc098a9..9bf78ffa2c1 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 2200 +configured_endpoints: 2204 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a6c352830d1270d0abb5bb983058ea21815e1bb7d2e163965335dcb0e706f057.yml openapi_spec_hash: 887efce5205bdef9eec55d574113ef5b -config_hash: a6f7ab07cd1fde3ee07c4cae6ed2d568 +config_hash: ff549978909de2badc92845fea964f4b diff --git a/src/cloudflare/resources/security_center/api.md b/src/cloudflare/resources/security_center/api.md index 5ba93b613e2..2fea22c8f78 100644 --- a/src/cloudflare/resources/security_center/api.md +++ b/src/cloudflare/resources/security_center/api.md @@ -48,3 +48,43 @@ from cloudflare.types.security_center.insights import TypeGetResponse Methods: - client.security_center.insights.type.get(\*, account_id, zone_id, \*\*params) -> Optional[TypeGetResponse] + +### AuditLogs + +Types: + +```python +from cloudflare.types.security_center.insights import ( + AuditLogListResponse, + AuditLogListByInsightResponse, +) +``` + +Methods: + +- client.security_center.insights.audit_logs.list(\*, account_id, zone_id, \*\*params) -> SyncCursorPagination[AuditLogListResponse] +- client.security_center.insights.audit_logs.list_by_insight(issue_id, \*, account_id, zone_id, \*\*params) -> SyncCursorPagination[AuditLogListByInsightResponse] + +### Classification + +Types: + +```python +from cloudflare.types.security_center.insights import ClassificationUpdateResponse +``` + +Methods: + +- client.security_center.insights.classification.update(issue_id, \*, account_id, zone_id, \*\*params) -> ClassificationUpdateResponse + +### Context + +Types: + +```python +from cloudflare.types.security_center.insights import ContextGetResponse +``` + +Methods: + +- client.security_center.insights.context.get(issue_id, \*, account_id) -> Optional[ContextGetResponse] diff --git a/src/cloudflare/resources/security_center/insights/__init__.py b/src/cloudflare/resources/security_center/insights/__init__.py index 5818ca6cde6..7048fdf8957 100644 --- a/src/cloudflare/resources/security_center/insights/__init__.py +++ b/src/cloudflare/resources/security_center/insights/__init__.py @@ -16,6 +16,14 @@ ClassResourceWithStreamingResponse, AsyncClassResourceWithStreamingResponse, ) +from .context import ( + ContextResource, + AsyncContextResource, + ContextResourceWithRawResponse, + AsyncContextResourceWithRawResponse, + ContextResourceWithStreamingResponse, + AsyncContextResourceWithStreamingResponse, +) from .insights import ( InsightsResource, AsyncInsightsResource, @@ -32,6 +40,22 @@ SeverityResourceWithStreamingResponse, AsyncSeverityResourceWithStreamingResponse, ) +from .audit_logs import ( + AuditLogsResource, + AsyncAuditLogsResource, + AuditLogsResourceWithRawResponse, + AsyncAuditLogsResourceWithRawResponse, + AuditLogsResourceWithStreamingResponse, + AsyncAuditLogsResourceWithStreamingResponse, +) +from .classification import ( + ClassificationResource, + AsyncClassificationResource, + ClassificationResourceWithRawResponse, + AsyncClassificationResourceWithRawResponse, + ClassificationResourceWithStreamingResponse, + AsyncClassificationResourceWithStreamingResponse, +) __all__ = [ "ClassResource", @@ -52,6 +76,24 @@ "AsyncTypeResourceWithRawResponse", "TypeResourceWithStreamingResponse", "AsyncTypeResourceWithStreamingResponse", + "AuditLogsResource", + "AsyncAuditLogsResource", + "AuditLogsResourceWithRawResponse", + "AsyncAuditLogsResourceWithRawResponse", + "AuditLogsResourceWithStreamingResponse", + "AsyncAuditLogsResourceWithStreamingResponse", + "ClassificationResource", + "AsyncClassificationResource", + "ClassificationResourceWithRawResponse", + "AsyncClassificationResourceWithRawResponse", + "ClassificationResourceWithStreamingResponse", + "AsyncClassificationResourceWithStreamingResponse", + "ContextResource", + "AsyncContextResource", + "ContextResourceWithRawResponse", + "AsyncContextResourceWithRawResponse", + "ContextResourceWithStreamingResponse", + "AsyncContextResourceWithStreamingResponse", "InsightsResource", "AsyncInsightsResource", "InsightsResourceWithRawResponse", diff --git a/src/cloudflare/resources/security_center/insights/audit_logs.py b/src/cloudflare/resources/security_center/insights/audit_logs.py new file mode 100644 index 00000000000..aeb240a3f62 --- /dev/null +++ b/src/cloudflare/resources/security_center/insights/audit_logs.py @@ -0,0 +1,489 @@ +# 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 + +import httpx + +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ...._utils import path_template, 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 ....pagination import SyncCursorPagination, AsyncCursorPagination +from ...._base_client import AsyncPaginator, make_request_options +from ....types.security_center.insights import audit_log_list_params, audit_log_list_by_insight_params +from ....types.security_center.insights.audit_log_list_response import AuditLogListResponse +from ....types.security_center.insights.audit_log_list_by_insight_response import AuditLogListByInsightResponse + +__all__ = ["AuditLogsResource", "AsyncAuditLogsResource"] + + +class AuditLogsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> AuditLogsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 AuditLogsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AuditLogsResourceWithStreamingResponse: + """ + 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 AuditLogsResourceWithStreamingResponse(self) + + def list( + self, + *, + account_id: str | Omit = omit, + zone_id: str | Omit = omit, + before: Union[str, datetime] | Omit = omit, + changed_by: str | Omit = omit, + cursor: str | Omit = omit, + field_changed: Literal["status", "user_classification"] | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + per_page: int | Omit = omit, + since: Union[str, datetime] | Omit = omit, + # 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, + ) -> SyncCursorPagination[AuditLogListResponse]: + """ + Lists audit log entries for all Security Center insights in the account or zone, + showing changes to insight status and classification. + + Args: + account_id: The Account ID to use for this endpoint. Mutually exclusive with the Zone ID. + + zone_id: The Zone ID to use for this endpoint. Mutually exclusive with the Account ID. + + before: Filter entries changed before this timestamp (RFC 3339). + + changed_by: Filter by the actor that made the change. + + cursor: Opaque cursor for pagination. Use the cursor value from result_info of the + previous response. + + field_changed: Filter by the field that was changed. + + order: Sort order for results. Use 'asc' for oldest first or 'desc' for newest first. + + per_page: Number of results per page. + + since: Filter entries changed at or after this timestamp (RFC 3339). + + 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 account_id and zone_id: + raise ValueError("You cannot provide both account_id and zone_id") + + if account_id: + account_or_zone = "accounts" + account_or_zone_id = account_id + else: + if not zone_id: + raise ValueError("You must provide either account_id or zone_id") + + account_or_zone = "zones" + account_or_zone_id = zone_id + return self._get_api_list( + path_template( + "/{account_or_zone}/{account_or_zone_id}/security-center/insights/audit-log", + account_or_zone=account_or_zone, + account_or_zone_id=account_or_zone_id, + ), + page=SyncCursorPagination[AuditLogListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "before": before, + "changed_by": changed_by, + "cursor": cursor, + "field_changed": field_changed, + "order": order, + "per_page": per_page, + "since": since, + }, + audit_log_list_params.AuditLogListParams, + ), + ), + model=AuditLogListResponse, + ) + + def list_by_insight( + self, + issue_id: str, + *, + account_id: str | Omit = omit, + zone_id: str | Omit = omit, + before: Union[str, datetime] | Omit = omit, + changed_by: str | Omit = omit, + cursor: str | Omit = omit, + field_changed: Literal["status", "user_classification"] | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + per_page: int | Omit = omit, + since: Union[str, datetime] | Omit = omit, + # 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, + ) -> SyncCursorPagination[AuditLogListByInsightResponse]: + """ + Lists audit log entries for a specific Security Center insight, showing changes + to its status and classification over time. + + Args: + account_id: The Account ID to use for this endpoint. Mutually exclusive with the Zone ID. + + zone_id: The Zone ID to use for this endpoint. Mutually exclusive with the Account ID. + + before: Filter entries changed before this timestamp (RFC 3339). + + changed_by: Filter by the actor that made the change. + + cursor: Opaque cursor for pagination. Use the cursor value from result_info of the + previous response. + + field_changed: Filter by the field that was changed. + + order: Sort order for results. Use 'asc' for oldest first or 'desc' for newest first. + + per_page: Number of results per page. + + since: Filter entries changed at or after this timestamp (RFC 3339). + + 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 issue_id: + raise ValueError(f"Expected a non-empty value for `issue_id` but received {issue_id!r}") + if account_id and zone_id: + raise ValueError("You cannot provide both account_id and zone_id") + + if account_id: + account_or_zone = "accounts" + account_or_zone_id = account_id + else: + if not zone_id: + raise ValueError("You must provide either account_id or zone_id") + + account_or_zone = "zones" + account_or_zone_id = zone_id + return self._get_api_list( + path_template( + "/{account_or_zone}/{account_or_zone_id}/security-center/insights/{issue_id}/audit-log", + issue_id=issue_id, + account_or_zone=account_or_zone, + account_or_zone_id=account_or_zone_id, + ), + page=SyncCursorPagination[AuditLogListByInsightResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "before": before, + "changed_by": changed_by, + "cursor": cursor, + "field_changed": field_changed, + "order": order, + "per_page": per_page, + "since": since, + }, + audit_log_list_by_insight_params.AuditLogListByInsightParams, + ), + ), + model=AuditLogListByInsightResponse, + ) + + +class AsyncAuditLogsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncAuditLogsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 AsyncAuditLogsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncAuditLogsResourceWithStreamingResponse: + """ + 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 AsyncAuditLogsResourceWithStreamingResponse(self) + + def list( + self, + *, + account_id: str | Omit = omit, + zone_id: str | Omit = omit, + before: Union[str, datetime] | Omit = omit, + changed_by: str | Omit = omit, + cursor: str | Omit = omit, + field_changed: Literal["status", "user_classification"] | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + per_page: int | Omit = omit, + since: Union[str, datetime] | Omit = omit, + # 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[AuditLogListResponse, AsyncCursorPagination[AuditLogListResponse]]: + """ + Lists audit log entries for all Security Center insights in the account or zone, + showing changes to insight status and classification. + + Args: + account_id: The Account ID to use for this endpoint. Mutually exclusive with the Zone ID. + + zone_id: The Zone ID to use for this endpoint. Mutually exclusive with the Account ID. + + before: Filter entries changed before this timestamp (RFC 3339). + + changed_by: Filter by the actor that made the change. + + cursor: Opaque cursor for pagination. Use the cursor value from result_info of the + previous response. + + field_changed: Filter by the field that was changed. + + order: Sort order for results. Use 'asc' for oldest first or 'desc' for newest first. + + per_page: Number of results per page. + + since: Filter entries changed at or after this timestamp (RFC 3339). + + 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 account_id and zone_id: + raise ValueError("You cannot provide both account_id and zone_id") + + if account_id: + account_or_zone = "accounts" + account_or_zone_id = account_id + else: + if not zone_id: + raise ValueError("You must provide either account_id or zone_id") + + account_or_zone = "zones" + account_or_zone_id = zone_id + return self._get_api_list( + path_template( + "/{account_or_zone}/{account_or_zone_id}/security-center/insights/audit-log", + account_or_zone=account_or_zone, + account_or_zone_id=account_or_zone_id, + ), + page=AsyncCursorPagination[AuditLogListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "before": before, + "changed_by": changed_by, + "cursor": cursor, + "field_changed": field_changed, + "order": order, + "per_page": per_page, + "since": since, + }, + audit_log_list_params.AuditLogListParams, + ), + ), + model=AuditLogListResponse, + ) + + def list_by_insight( + self, + issue_id: str, + *, + account_id: str | Omit = omit, + zone_id: str | Omit = omit, + before: Union[str, datetime] | Omit = omit, + changed_by: str | Omit = omit, + cursor: str | Omit = omit, + field_changed: Literal["status", "user_classification"] | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + per_page: int | Omit = omit, + since: Union[str, datetime] | Omit = omit, + # 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[AuditLogListByInsightResponse, AsyncCursorPagination[AuditLogListByInsightResponse]]: + """ + Lists audit log entries for a specific Security Center insight, showing changes + to its status and classification over time. + + Args: + account_id: The Account ID to use for this endpoint. Mutually exclusive with the Zone ID. + + zone_id: The Zone ID to use for this endpoint. Mutually exclusive with the Account ID. + + before: Filter entries changed before this timestamp (RFC 3339). + + changed_by: Filter by the actor that made the change. + + cursor: Opaque cursor for pagination. Use the cursor value from result_info of the + previous response. + + field_changed: Filter by the field that was changed. + + order: Sort order for results. Use 'asc' for oldest first or 'desc' for newest first. + + per_page: Number of results per page. + + since: Filter entries changed at or after this timestamp (RFC 3339). + + 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 issue_id: + raise ValueError(f"Expected a non-empty value for `issue_id` but received {issue_id!r}") + if account_id and zone_id: + raise ValueError("You cannot provide both account_id and zone_id") + + if account_id: + account_or_zone = "accounts" + account_or_zone_id = account_id + else: + if not zone_id: + raise ValueError("You must provide either account_id or zone_id") + + account_or_zone = "zones" + account_or_zone_id = zone_id + return self._get_api_list( + path_template( + "/{account_or_zone}/{account_or_zone_id}/security-center/insights/{issue_id}/audit-log", + issue_id=issue_id, + account_or_zone=account_or_zone, + account_or_zone_id=account_or_zone_id, + ), + page=AsyncCursorPagination[AuditLogListByInsightResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "before": before, + "changed_by": changed_by, + "cursor": cursor, + "field_changed": field_changed, + "order": order, + "per_page": per_page, + "since": since, + }, + audit_log_list_by_insight_params.AuditLogListByInsightParams, + ), + ), + model=AuditLogListByInsightResponse, + ) + + +class AuditLogsResourceWithRawResponse: + def __init__(self, audit_logs: AuditLogsResource) -> None: + self._audit_logs = audit_logs + + self.list = to_raw_response_wrapper( + audit_logs.list, + ) + self.list_by_insight = to_raw_response_wrapper( + audit_logs.list_by_insight, + ) + + +class AsyncAuditLogsResourceWithRawResponse: + def __init__(self, audit_logs: AsyncAuditLogsResource) -> None: + self._audit_logs = audit_logs + + self.list = async_to_raw_response_wrapper( + audit_logs.list, + ) + self.list_by_insight = async_to_raw_response_wrapper( + audit_logs.list_by_insight, + ) + + +class AuditLogsResourceWithStreamingResponse: + def __init__(self, audit_logs: AuditLogsResource) -> None: + self._audit_logs = audit_logs + + self.list = to_streamed_response_wrapper( + audit_logs.list, + ) + self.list_by_insight = to_streamed_response_wrapper( + audit_logs.list_by_insight, + ) + + +class AsyncAuditLogsResourceWithStreamingResponse: + def __init__(self, audit_logs: AsyncAuditLogsResource) -> None: + self._audit_logs = audit_logs + + self.list = async_to_streamed_response_wrapper( + audit_logs.list, + ) + self.list_by_insight = async_to_streamed_response_wrapper( + audit_logs.list_by_insight, + ) diff --git a/src/cloudflare/resources/security_center/insights/classification.py b/src/cloudflare/resources/security_center/insights/classification.py new file mode 100644 index 00000000000..f866cdf9875 --- /dev/null +++ b/src/cloudflare/resources/security_center/insights/classification.py @@ -0,0 +1,250 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal + +import httpx + +from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ...._utils import path_template, 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 ...._base_client import make_request_options +from ....types.security_center.insights import classification_update_params +from ....types.security_center.insights.classification_update_response import ClassificationUpdateResponse + +__all__ = ["ClassificationResource", "AsyncClassificationResource"] + + +class ClassificationResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ClassificationResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 ClassificationResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ClassificationResourceWithStreamingResponse: + """ + 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 ClassificationResourceWithStreamingResponse(self) + + def update( + self, + issue_id: str, + *, + account_id: str | Omit = omit, + zone_id: str | Omit = omit, + classification: Optional[Literal["false_positive", "accept_risk", "other"]] | Omit = omit, + rationale: str | Omit = omit, + # 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, + ) -> ClassificationUpdateResponse: + """Updates the user classification for a Security Center insight. + + Valid values are + 'false_positive' or 'accept_risk'. To reset, set classification to null. Cannot + change directly between classification values - must reset to null first. + + Args: + account_id: The Account ID to use for this endpoint. Mutually exclusive with the Zone ID. + + zone_id: The Zone ID to use for this endpoint. Mutually exclusive with the Account ID. + + classification: User-defined classification for the insight. Can be 'false_positive', + 'accept_risk', 'other', or null. + + rationale: Rationale for the classification change. Required when classification is + 'accept_risk' or 'other'. + + 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 issue_id: + raise ValueError(f"Expected a non-empty value for `issue_id` but received {issue_id!r}") + if account_id and zone_id: + raise ValueError("You cannot provide both account_id and zone_id") + + if account_id: + account_or_zone = "accounts" + account_or_zone_id = account_id + else: + if not zone_id: + raise ValueError("You must provide either account_id or zone_id") + + account_or_zone = "zones" + account_or_zone_id = zone_id + return self._patch( + path_template( + "/{account_or_zone}/{account_or_zone_id}/security-center/insights/{issue_id}/classification", + issue_id=issue_id, + account_or_zone=account_or_zone, + account_or_zone_id=account_or_zone_id, + ), + body=maybe_transform( + { + "classification": classification, + "rationale": rationale, + }, + classification_update_params.ClassificationUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ClassificationUpdateResponse, + ) + + +class AsyncClassificationResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncClassificationResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 AsyncClassificationResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncClassificationResourceWithStreamingResponse: + """ + 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 AsyncClassificationResourceWithStreamingResponse(self) + + async def update( + self, + issue_id: str, + *, + account_id: str | Omit = omit, + zone_id: str | Omit = omit, + classification: Optional[Literal["false_positive", "accept_risk", "other"]] | Omit = omit, + rationale: str | Omit = omit, + # 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, + ) -> ClassificationUpdateResponse: + """Updates the user classification for a Security Center insight. + + Valid values are + 'false_positive' or 'accept_risk'. To reset, set classification to null. Cannot + change directly between classification values - must reset to null first. + + Args: + account_id: The Account ID to use for this endpoint. Mutually exclusive with the Zone ID. + + zone_id: The Zone ID to use for this endpoint. Mutually exclusive with the Account ID. + + classification: User-defined classification for the insight. Can be 'false_positive', + 'accept_risk', 'other', or null. + + rationale: Rationale for the classification change. Required when classification is + 'accept_risk' or 'other'. + + 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 issue_id: + raise ValueError(f"Expected a non-empty value for `issue_id` but received {issue_id!r}") + if account_id and zone_id: + raise ValueError("You cannot provide both account_id and zone_id") + + if account_id: + account_or_zone = "accounts" + account_or_zone_id = account_id + else: + if not zone_id: + raise ValueError("You must provide either account_id or zone_id") + + account_or_zone = "zones" + account_or_zone_id = zone_id + return await self._patch( + path_template( + "/{account_or_zone}/{account_or_zone_id}/security-center/insights/{issue_id}/classification", + issue_id=issue_id, + account_or_zone=account_or_zone, + account_or_zone_id=account_or_zone_id, + ), + body=await async_maybe_transform( + { + "classification": classification, + "rationale": rationale, + }, + classification_update_params.ClassificationUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ClassificationUpdateResponse, + ) + + +class ClassificationResourceWithRawResponse: + def __init__(self, classification: ClassificationResource) -> None: + self._classification = classification + + self.update = to_raw_response_wrapper( + classification.update, + ) + + +class AsyncClassificationResourceWithRawResponse: + def __init__(self, classification: AsyncClassificationResource) -> None: + self._classification = classification + + self.update = async_to_raw_response_wrapper( + classification.update, + ) + + +class ClassificationResourceWithStreamingResponse: + def __init__(self, classification: ClassificationResource) -> None: + self._classification = classification + + self.update = to_streamed_response_wrapper( + classification.update, + ) + + +class AsyncClassificationResourceWithStreamingResponse: + def __init__(self, classification: AsyncClassificationResource) -> None: + self._classification = classification + + self.update = async_to_streamed_response_wrapper( + classification.update, + ) diff --git a/src/cloudflare/resources/security_center/insights/context.py b/src/cloudflare/resources/security_center/insights/context.py new file mode 100644 index 00000000000..cbf4382ffca --- /dev/null +++ b/src/cloudflare/resources/security_center/insights/context.py @@ -0,0 +1,197 @@ +# 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 Body, Query, Headers, NotGiven, not_given +from ...._utils import path_template +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.security_center.insights.context_get_response import ContextGetResponse + +__all__ = ["ContextResource", "AsyncContextResource"] + + +class ContextResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ContextResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 ContextResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ContextResourceWithStreamingResponse: + """ + 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 ContextResourceWithStreamingResponse(self) + + def get( + self, + issue_id: str, + *, + 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[ContextGetResponse]: + """Returns the full context payload for an insight. + + This endpoint is used for + insights with large payloads that are not included inline in the list response. + + Args: + account_id: Identifier. + + 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 issue_id: + raise ValueError(f"Expected a non-empty value for `issue_id` but received {issue_id!r}") + return self._get( + path_template( + "/accounts/{account_id}/security-center/insights/{issue_id}/context", + account_id=account_id, + issue_id=issue_id, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[Optional[ContextGetResponse]]._unwrapper, + ), + cast_to=cast(Type[Optional[ContextGetResponse]], ResultWrapper[ContextGetResponse]), + ) + + +class AsyncContextResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncContextResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 AsyncContextResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncContextResourceWithStreamingResponse: + """ + 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 AsyncContextResourceWithStreamingResponse(self) + + async def get( + self, + issue_id: str, + *, + 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[ContextGetResponse]: + """Returns the full context payload for an insight. + + This endpoint is used for + insights with large payloads that are not included inline in the list response. + + Args: + account_id: Identifier. + + 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 issue_id: + raise ValueError(f"Expected a non-empty value for `issue_id` but received {issue_id!r}") + return await self._get( + path_template( + "/accounts/{account_id}/security-center/insights/{issue_id}/context", + account_id=account_id, + issue_id=issue_id, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[Optional[ContextGetResponse]]._unwrapper, + ), + cast_to=cast(Type[Optional[ContextGetResponse]], ResultWrapper[ContextGetResponse]), + ) + + +class ContextResourceWithRawResponse: + def __init__(self, context: ContextResource) -> None: + self._context = context + + self.get = to_raw_response_wrapper( + context.get, + ) + + +class AsyncContextResourceWithRawResponse: + def __init__(self, context: AsyncContextResource) -> None: + self._context = context + + self.get = async_to_raw_response_wrapper( + context.get, + ) + + +class ContextResourceWithStreamingResponse: + def __init__(self, context: ContextResource) -> None: + self._context = context + + self.get = to_streamed_response_wrapper( + context.get, + ) + + +class AsyncContextResourceWithStreamingResponse: + def __init__(self, context: AsyncContextResource) -> None: + self._context = context + + self.get = async_to_streamed_response_wrapper( + context.get, + ) diff --git a/src/cloudflare/resources/security_center/insights/insights.py b/src/cloudflare/resources/security_center/insights/insights.py index 8ccae5088ef..b797de82013 100644 --- a/src/cloudflare/resources/security_center/insights/insights.py +++ b/src/cloudflare/resources/security_center/insights/insights.py @@ -22,6 +22,14 @@ ClassResourceWithStreamingResponse, AsyncClassResourceWithStreamingResponse, ) +from .context import ( + ContextResource, + AsyncContextResource, + ContextResourceWithRawResponse, + AsyncContextResourceWithRawResponse, + ContextResourceWithStreamingResponse, + AsyncContextResourceWithStreamingResponse, +) from .severity import ( SeverityResource, AsyncSeverityResource, @@ -33,6 +41,14 @@ from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given from ...._utils import path_template, maybe_transform, async_maybe_transform from ...._compat import cached_property +from .audit_logs import ( + AuditLogsResource, + AsyncAuditLogsResource, + AuditLogsResourceWithRawResponse, + AsyncAuditLogsResourceWithRawResponse, + AuditLogsResourceWithStreamingResponse, + AsyncAuditLogsResourceWithStreamingResponse, +) from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import ( to_raw_response_wrapper, @@ -41,6 +57,14 @@ async_to_streamed_response_wrapper, ) from ....pagination import SyncV4PagePagination, AsyncV4PagePagination +from .classification import ( + ClassificationResource, + AsyncClassificationResource, + ClassificationResourceWithRawResponse, + AsyncClassificationResourceWithRawResponse, + ClassificationResourceWithStreamingResponse, + AsyncClassificationResourceWithStreamingResponse, +) from ...._base_client import AsyncPaginator, make_request_options from ....types.security_center import insight_list_params, insight_dismiss_params from ....types.security_center.insight_list_response import InsightListResponse @@ -64,6 +88,18 @@ def severity(self) -> SeverityResource: def type(self) -> TypeResource: return TypeResource(self._client) + @cached_property + def audit_logs(self) -> AuditLogsResource: + return AuditLogsResource(self._client) + + @cached_property + def classification(self) -> ClassificationResource: + return ClassificationResource(self._client) + + @cached_property + def context(self) -> ContextResource: + return ContextResource(self._client) + @cached_property def with_raw_response(self) -> InsightsResourceWithRawResponse: """ @@ -248,6 +284,18 @@ def severity(self) -> AsyncSeverityResource: def type(self) -> AsyncTypeResource: return AsyncTypeResource(self._client) + @cached_property + def audit_logs(self) -> AsyncAuditLogsResource: + return AsyncAuditLogsResource(self._client) + + @cached_property + def classification(self) -> AsyncClassificationResource: + return AsyncClassificationResource(self._client) + + @cached_property + def context(self) -> AsyncContextResource: + return AsyncContextResource(self._client) + @cached_property def with_raw_response(self) -> AsyncInsightsResourceWithRawResponse: """ @@ -442,6 +490,18 @@ def severity(self) -> SeverityResourceWithRawResponse: def type(self) -> TypeResourceWithRawResponse: return TypeResourceWithRawResponse(self._insights.type) + @cached_property + def audit_logs(self) -> AuditLogsResourceWithRawResponse: + return AuditLogsResourceWithRawResponse(self._insights.audit_logs) + + @cached_property + def classification(self) -> ClassificationResourceWithRawResponse: + return ClassificationResourceWithRawResponse(self._insights.classification) + + @cached_property + def context(self) -> ContextResourceWithRawResponse: + return ContextResourceWithRawResponse(self._insights.context) + class AsyncInsightsResourceWithRawResponse: def __init__(self, insights: AsyncInsightsResource) -> None: @@ -466,6 +526,18 @@ def severity(self) -> AsyncSeverityResourceWithRawResponse: def type(self) -> AsyncTypeResourceWithRawResponse: return AsyncTypeResourceWithRawResponse(self._insights.type) + @cached_property + def audit_logs(self) -> AsyncAuditLogsResourceWithRawResponse: + return AsyncAuditLogsResourceWithRawResponse(self._insights.audit_logs) + + @cached_property + def classification(self) -> AsyncClassificationResourceWithRawResponse: + return AsyncClassificationResourceWithRawResponse(self._insights.classification) + + @cached_property + def context(self) -> AsyncContextResourceWithRawResponse: + return AsyncContextResourceWithRawResponse(self._insights.context) + class InsightsResourceWithStreamingResponse: def __init__(self, insights: InsightsResource) -> None: @@ -490,6 +562,18 @@ def severity(self) -> SeverityResourceWithStreamingResponse: def type(self) -> TypeResourceWithStreamingResponse: return TypeResourceWithStreamingResponse(self._insights.type) + @cached_property + def audit_logs(self) -> AuditLogsResourceWithStreamingResponse: + return AuditLogsResourceWithStreamingResponse(self._insights.audit_logs) + + @cached_property + def classification(self) -> ClassificationResourceWithStreamingResponse: + return ClassificationResourceWithStreamingResponse(self._insights.classification) + + @cached_property + def context(self) -> ContextResourceWithStreamingResponse: + return ContextResourceWithStreamingResponse(self._insights.context) + class AsyncInsightsResourceWithStreamingResponse: def __init__(self, insights: AsyncInsightsResource) -> None: @@ -513,3 +597,15 @@ def severity(self) -> AsyncSeverityResourceWithStreamingResponse: @cached_property def type(self) -> AsyncTypeResourceWithStreamingResponse: return AsyncTypeResourceWithStreamingResponse(self._insights.type) + + @cached_property + def audit_logs(self) -> AsyncAuditLogsResourceWithStreamingResponse: + return AsyncAuditLogsResourceWithStreamingResponse(self._insights.audit_logs) + + @cached_property + def classification(self) -> AsyncClassificationResourceWithStreamingResponse: + return AsyncClassificationResourceWithStreamingResponse(self._insights.classification) + + @cached_property + def context(self) -> AsyncContextResourceWithStreamingResponse: + return AsyncContextResourceWithStreamingResponse(self._insights.context) diff --git a/src/cloudflare/types/security_center/insights/__init__.py b/src/cloudflare/types/security_center/insights/__init__.py index adb9484cde5..08a3073ded2 100644 --- a/src/cloudflare/types/security_center/insights/__init__.py +++ b/src/cloudflare/types/security_center/insights/__init__.py @@ -7,4 +7,11 @@ from .type_get_response import TypeGetResponse as TypeGetResponse from .class_get_response import ClassGetResponse as ClassGetResponse from .severity_get_params import SeverityGetParams as SeverityGetParams +from .context_get_response import ContextGetResponse as ContextGetResponse +from .audit_log_list_params import AuditLogListParams as AuditLogListParams from .severity_get_response import SeverityGetResponse as SeverityGetResponse +from .audit_log_list_response import AuditLogListResponse as AuditLogListResponse +from .classification_update_params import ClassificationUpdateParams as ClassificationUpdateParams +from .classification_update_response import ClassificationUpdateResponse as ClassificationUpdateResponse +from .audit_log_list_by_insight_params import AuditLogListByInsightParams as AuditLogListByInsightParams +from .audit_log_list_by_insight_response import AuditLogListByInsightResponse as AuditLogListByInsightResponse diff --git a/src/cloudflare/types/security_center/insights/audit_log_list_by_insight_params.py b/src/cloudflare/types/security_center/insights/audit_log_list_by_insight_params.py new file mode 100644 index 00000000000..7809ec6bcc3 --- /dev/null +++ b/src/cloudflare/types/security_center/insights/audit_log_list_by_insight_params.py @@ -0,0 +1,43 @@ +# 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, Annotated, TypedDict + +from ...._utils import PropertyInfo + +__all__ = ["AuditLogListByInsightParams"] + + +class AuditLogListByInsightParams(TypedDict, total=False): + account_id: str + """The Account ID to use for this endpoint. Mutually exclusive with the Zone ID.""" + + zone_id: str + """The Zone ID to use for this endpoint. Mutually exclusive with the Account ID.""" + + before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] + """Filter entries changed before this timestamp (RFC 3339).""" + + changed_by: str + """Filter by the actor that made the change.""" + + cursor: str + """Opaque cursor for pagination. + + Use the cursor value from result_info of the previous response. + """ + + field_changed: Literal["status", "user_classification"] + """Filter by the field that was changed.""" + + order: Literal["asc", "desc"] + """Sort order for results. Use 'asc' for oldest first or 'desc' for newest first.""" + + per_page: int + """Number of results per page.""" + + since: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] + """Filter entries changed at or after this timestamp (RFC 3339).""" diff --git a/src/cloudflare/types/security_center/insights/audit_log_list_by_insight_response.py b/src/cloudflare/types/security_center/insights/audit_log_list_by_insight_response.py new file mode 100644 index 00000000000..2439e24e31f --- /dev/null +++ b/src/cloudflare/types/security_center/insights/audit_log_list_by_insight_response.py @@ -0,0 +1,44 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["AuditLogListByInsightResponse"] + + +class AuditLogListByInsightResponse(BaseModel): + id: Optional[str] = None + """UUIDv7 identifier for the audit log entry, time-ordered.""" + + changed_at: Optional[datetime] = None + """The timestamp when the change occurred.""" + + changed_by: Optional[str] = None + """The actor that made the change. + + 'system' for automated changes, or a user identifier. + """ + + current_value: Optional[str] = None + """The value of the field after the change. Null if the field was cleared.""" + + field_changed: Optional[Literal["status", "user_classification"]] = None + """The field that was changed.""" + + issue_id: Optional[str] = None + """The ID of the insight this audit log entry relates to.""" + + previous_value: Optional[str] = None + """The value of the field before the change. + + Null if the field was not previously set. + """ + + rationale: Optional[str] = None + """Optional rationale provided for the change.""" + + zone_id: Optional[int] = None + """The zone ID associated with the insight. Only present for zone-level insights.""" diff --git a/src/cloudflare/types/security_center/insights/audit_log_list_params.py b/src/cloudflare/types/security_center/insights/audit_log_list_params.py new file mode 100644 index 00000000000..74e03879e2e --- /dev/null +++ b/src/cloudflare/types/security_center/insights/audit_log_list_params.py @@ -0,0 +1,43 @@ +# 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, Annotated, TypedDict + +from ...._utils import PropertyInfo + +__all__ = ["AuditLogListParams"] + + +class AuditLogListParams(TypedDict, total=False): + account_id: str + """The Account ID to use for this endpoint. Mutually exclusive with the Zone ID.""" + + zone_id: str + """The Zone ID to use for this endpoint. Mutually exclusive with the Account ID.""" + + before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] + """Filter entries changed before this timestamp (RFC 3339).""" + + changed_by: str + """Filter by the actor that made the change.""" + + cursor: str + """Opaque cursor for pagination. + + Use the cursor value from result_info of the previous response. + """ + + field_changed: Literal["status", "user_classification"] + """Filter by the field that was changed.""" + + order: Literal["asc", "desc"] + """Sort order for results. Use 'asc' for oldest first or 'desc' for newest first.""" + + per_page: int + """Number of results per page.""" + + since: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] + """Filter entries changed at or after this timestamp (RFC 3339).""" diff --git a/src/cloudflare/types/security_center/insights/audit_log_list_response.py b/src/cloudflare/types/security_center/insights/audit_log_list_response.py new file mode 100644 index 00000000000..6bc3ac1ffc6 --- /dev/null +++ b/src/cloudflare/types/security_center/insights/audit_log_list_response.py @@ -0,0 +1,44 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["AuditLogListResponse"] + + +class AuditLogListResponse(BaseModel): + id: Optional[str] = None + """UUIDv7 identifier for the audit log entry, time-ordered.""" + + changed_at: Optional[datetime] = None + """The timestamp when the change occurred.""" + + changed_by: Optional[str] = None + """The actor that made the change. + + 'system' for automated changes, or a user identifier. + """ + + current_value: Optional[str] = None + """The value of the field after the change. Null if the field was cleared.""" + + field_changed: Optional[Literal["status", "user_classification"]] = None + """The field that was changed.""" + + issue_id: Optional[str] = None + """The ID of the insight this audit log entry relates to.""" + + previous_value: Optional[str] = None + """The value of the field before the change. + + Null if the field was not previously set. + """ + + rationale: Optional[str] = None + """Optional rationale provided for the change.""" + + zone_id: Optional[int] = None + """The zone ID associated with the insight. Only present for zone-level insights.""" diff --git a/src/cloudflare/types/security_center/insights/classification_update_params.py b/src/cloudflare/types/security_center/insights/classification_update_params.py new file mode 100644 index 00000000000..3575bc2ec72 --- /dev/null +++ b/src/cloudflare/types/security_center/insights/classification_update_params.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, TypedDict + +__all__ = ["ClassificationUpdateParams"] + + +class ClassificationUpdateParams(TypedDict, total=False): + account_id: str + """The Account ID to use for this endpoint. Mutually exclusive with the Zone ID.""" + + zone_id: str + """The Zone ID to use for this endpoint. Mutually exclusive with the Account ID.""" + + classification: Optional[Literal["false_positive", "accept_risk", "other"]] + """User-defined classification for the insight. + + Can be 'false_positive', 'accept_risk', 'other', or null. + """ + + rationale: str + """Rationale for the classification change. + + Required when classification is 'accept_risk' or 'other'. + """ diff --git a/src/cloudflare/types/security_center/insights/classification_update_response.py b/src/cloudflare/types/security_center/insights/classification_update_response.py new file mode 100644 index 00000000000..6718a2732f1 --- /dev/null +++ b/src/cloudflare/types/security_center/insights/classification_update_response.py @@ -0,0 +1,45 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["ClassificationUpdateResponse", "Error", "ErrorSource", "Message", "MessageSource"] + + +class ErrorSource(BaseModel): + pointer: Optional[str] = None + + +class Error(BaseModel): + code: int + + message: str + + documentation_url: Optional[str] = None + + source: Optional[ErrorSource] = None + + +class MessageSource(BaseModel): + pointer: Optional[str] = None + + +class Message(BaseModel): + code: int + + message: str + + documentation_url: Optional[str] = None + + source: Optional[MessageSource] = None + + +class ClassificationUpdateResponse(BaseModel): + errors: List[Error] + + messages: List[Message] + + success: Literal[True] + """Whether the API call was successful.""" diff --git a/src/cloudflare/types/security_center/insights/context_get_response.py b/src/cloudflare/types/security_center/insights/context_get_response.py new file mode 100644 index 00000000000..af39d73b946 --- /dev/null +++ b/src/cloudflare/types/security_center/insights/context_get_response.py @@ -0,0 +1,8 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict +from typing_extensions import TypeAlias + +__all__ = ["ContextGetResponse"] + +ContextGetResponse: TypeAlias = Dict[str, object] diff --git a/tests/api_resources/security_center/insights/test_audit_logs.py b/tests/api_resources/security_center/insights/test_audit_logs.py new file mode 100644 index 00000000000..82e4365f53b --- /dev/null +++ b/tests/api_resources/security_center/insights/test_audit_logs.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, 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 SyncCursorPagination, AsyncCursorPagination +from cloudflare.types.security_center.insights import ( + AuditLogListResponse, + AuditLogListByInsightResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestAuditLogs: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Cloudflare) -> None: + audit_log = client.security_center.insights.audit_logs.list( + account_id="account_id", + ) + assert_matches_type(SyncCursorPagination[AuditLogListResponse], audit_log, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Cloudflare) -> None: + audit_log = client.security_center.insights.audit_logs.list( + account_id="account_id", + before=parse_datetime("2019-12-27T18:11:19.117Z"), + changed_by="changed_by", + cursor="cursor", + field_changed="status", + order="asc", + per_page=1, + since=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + assert_matches_type(SyncCursorPagination[AuditLogListResponse], audit_log, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Cloudflare) -> None: + response = client.security_center.insights.audit_logs.with_raw_response.list( + account_id="account_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + audit_log = response.parse() + assert_matches_type(SyncCursorPagination[AuditLogListResponse], audit_log, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Cloudflare) -> None: + with client.security_center.insights.audit_logs.with_streaming_response.list( + account_id="account_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + audit_log = response.parse() + assert_matches_type(SyncCursorPagination[AuditLogListResponse], audit_log, 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"You must provide either account_id or zone_id"): + client.security_center.insights.audit_logs.with_raw_response.list( + account_id="", + ) + + with pytest.raises(ValueError, match=r"You must provide either account_id or zone_id"): + client.security_center.insights.audit_logs.with_raw_response.list( + account_id="account_id", + ) + + @parametrize + def test_method_list_by_insight(self, client: Cloudflare) -> None: + audit_log = client.security_center.insights.audit_logs.list_by_insight( + issue_id="issue_id", + account_id="account_id", + ) + assert_matches_type(SyncCursorPagination[AuditLogListByInsightResponse], audit_log, path=["response"]) + + @parametrize + def test_method_list_by_insight_with_all_params(self, client: Cloudflare) -> None: + audit_log = client.security_center.insights.audit_logs.list_by_insight( + issue_id="issue_id", + account_id="account_id", + before=parse_datetime("2019-12-27T18:11:19.117Z"), + changed_by="changed_by", + cursor="cursor", + field_changed="status", + order="asc", + per_page=1, + since=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + assert_matches_type(SyncCursorPagination[AuditLogListByInsightResponse], audit_log, path=["response"]) + + @parametrize + def test_raw_response_list_by_insight(self, client: Cloudflare) -> None: + response = client.security_center.insights.audit_logs.with_raw_response.list_by_insight( + issue_id="issue_id", + account_id="account_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + audit_log = response.parse() + assert_matches_type(SyncCursorPagination[AuditLogListByInsightResponse], audit_log, path=["response"]) + + @parametrize + def test_streaming_response_list_by_insight(self, client: Cloudflare) -> None: + with client.security_center.insights.audit_logs.with_streaming_response.list_by_insight( + issue_id="issue_id", + account_id="account_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + audit_log = response.parse() + assert_matches_type(SyncCursorPagination[AuditLogListByInsightResponse], audit_log, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list_by_insight(self, client: Cloudflare) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `issue_id` but received ''"): + client.security_center.insights.audit_logs.with_raw_response.list_by_insight( + issue_id="", + account_id="account_id", + ) + + with pytest.raises(ValueError, match=r"You must provide either account_id or zone_id"): + client.security_center.insights.audit_logs.with_raw_response.list_by_insight( + issue_id="issue_id", + account_id="", + ) + + with pytest.raises(ValueError, match=r"You must provide either account_id or zone_id"): + client.security_center.insights.audit_logs.with_raw_response.list_by_insight( + issue_id="issue_id", + account_id="account_id", + ) + + +class TestAsyncAuditLogs: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncCloudflare) -> None: + audit_log = await async_client.security_center.insights.audit_logs.list( + account_id="account_id", + ) + assert_matches_type(AsyncCursorPagination[AuditLogListResponse], audit_log, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncCloudflare) -> None: + audit_log = await async_client.security_center.insights.audit_logs.list( + account_id="account_id", + before=parse_datetime("2019-12-27T18:11:19.117Z"), + changed_by="changed_by", + cursor="cursor", + field_changed="status", + order="asc", + per_page=1, + since=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + assert_matches_type(AsyncCursorPagination[AuditLogListResponse], audit_log, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncCloudflare) -> None: + response = await async_client.security_center.insights.audit_logs.with_raw_response.list( + account_id="account_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + audit_log = await response.parse() + assert_matches_type(AsyncCursorPagination[AuditLogListResponse], audit_log, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncCloudflare) -> None: + async with async_client.security_center.insights.audit_logs.with_streaming_response.list( + account_id="account_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + audit_log = await response.parse() + assert_matches_type(AsyncCursorPagination[AuditLogListResponse], audit_log, 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"You must provide either account_id or zone_id"): + await async_client.security_center.insights.audit_logs.with_raw_response.list( + account_id="", + ) + + with pytest.raises(ValueError, match=r"You must provide either account_id or zone_id"): + await async_client.security_center.insights.audit_logs.with_raw_response.list( + account_id="account_id", + ) + + @parametrize + async def test_method_list_by_insight(self, async_client: AsyncCloudflare) -> None: + audit_log = await async_client.security_center.insights.audit_logs.list_by_insight( + issue_id="issue_id", + account_id="account_id", + ) + assert_matches_type(AsyncCursorPagination[AuditLogListByInsightResponse], audit_log, path=["response"]) + + @parametrize + async def test_method_list_by_insight_with_all_params(self, async_client: AsyncCloudflare) -> None: + audit_log = await async_client.security_center.insights.audit_logs.list_by_insight( + issue_id="issue_id", + account_id="account_id", + before=parse_datetime("2019-12-27T18:11:19.117Z"), + changed_by="changed_by", + cursor="cursor", + field_changed="status", + order="asc", + per_page=1, + since=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + assert_matches_type(AsyncCursorPagination[AuditLogListByInsightResponse], audit_log, path=["response"]) + + @parametrize + async def test_raw_response_list_by_insight(self, async_client: AsyncCloudflare) -> None: + response = await async_client.security_center.insights.audit_logs.with_raw_response.list_by_insight( + issue_id="issue_id", + account_id="account_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + audit_log = await response.parse() + assert_matches_type(AsyncCursorPagination[AuditLogListByInsightResponse], audit_log, path=["response"]) + + @parametrize + async def test_streaming_response_list_by_insight(self, async_client: AsyncCloudflare) -> None: + async with async_client.security_center.insights.audit_logs.with_streaming_response.list_by_insight( + issue_id="issue_id", + account_id="account_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + audit_log = await response.parse() + assert_matches_type(AsyncCursorPagination[AuditLogListByInsightResponse], audit_log, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list_by_insight(self, async_client: AsyncCloudflare) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `issue_id` but received ''"): + await async_client.security_center.insights.audit_logs.with_raw_response.list_by_insight( + issue_id="", + account_id="account_id", + ) + + with pytest.raises(ValueError, match=r"You must provide either account_id or zone_id"): + await async_client.security_center.insights.audit_logs.with_raw_response.list_by_insight( + issue_id="issue_id", + account_id="", + ) + + with pytest.raises(ValueError, match=r"You must provide either account_id or zone_id"): + await async_client.security_center.insights.audit_logs.with_raw_response.list_by_insight( + issue_id="issue_id", + account_id="account_id", + ) diff --git a/tests/api_resources/security_center/insights/test_classification.py b/tests/api_resources/security_center/insights/test_classification.py new file mode 100644 index 00000000000..86fb4077f4e --- /dev/null +++ b/tests/api_resources/security_center/insights/test_classification.py @@ -0,0 +1,152 @@ +# 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 pytest + +from cloudflare import Cloudflare, AsyncCloudflare +from tests.utils import assert_matches_type +from cloudflare.types.security_center.insights import ClassificationUpdateResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestClassification: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_update(self, client: Cloudflare) -> None: + classification = client.security_center.insights.classification.update( + issue_id="issue_id", + account_id="account_id", + ) + assert_matches_type(ClassificationUpdateResponse, classification, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Cloudflare) -> None: + classification = client.security_center.insights.classification.update( + issue_id="issue_id", + account_id="account_id", + classification="false_positive", + rationale="rationale", + ) + assert_matches_type(ClassificationUpdateResponse, classification, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Cloudflare) -> None: + response = client.security_center.insights.classification.with_raw_response.update( + issue_id="issue_id", + account_id="account_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + classification = response.parse() + assert_matches_type(ClassificationUpdateResponse, classification, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Cloudflare) -> None: + with client.security_center.insights.classification.with_streaming_response.update( + issue_id="issue_id", + account_id="account_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + classification = response.parse() + assert_matches_type(ClassificationUpdateResponse, classification, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: Cloudflare) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `issue_id` but received ''"): + client.security_center.insights.classification.with_raw_response.update( + issue_id="", + account_id="account_id", + ) + + with pytest.raises(ValueError, match=r"You must provide either account_id or zone_id"): + client.security_center.insights.classification.with_raw_response.update( + issue_id="issue_id", + account_id="", + ) + + with pytest.raises(ValueError, match=r"You must provide either account_id or zone_id"): + client.security_center.insights.classification.with_raw_response.update( + issue_id="issue_id", + account_id="account_id", + ) + + +class TestAsyncClassification: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_update(self, async_client: AsyncCloudflare) -> None: + classification = await async_client.security_center.insights.classification.update( + issue_id="issue_id", + account_id="account_id", + ) + assert_matches_type(ClassificationUpdateResponse, classification, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncCloudflare) -> None: + classification = await async_client.security_center.insights.classification.update( + issue_id="issue_id", + account_id="account_id", + classification="false_positive", + rationale="rationale", + ) + assert_matches_type(ClassificationUpdateResponse, classification, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncCloudflare) -> None: + response = await async_client.security_center.insights.classification.with_raw_response.update( + issue_id="issue_id", + account_id="account_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + classification = await response.parse() + assert_matches_type(ClassificationUpdateResponse, classification, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncCloudflare) -> None: + async with async_client.security_center.insights.classification.with_streaming_response.update( + issue_id="issue_id", + account_id="account_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + classification = await response.parse() + assert_matches_type(ClassificationUpdateResponse, classification, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncCloudflare) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `issue_id` but received ''"): + await async_client.security_center.insights.classification.with_raw_response.update( + issue_id="", + account_id="account_id", + ) + + with pytest.raises(ValueError, match=r"You must provide either account_id or zone_id"): + await async_client.security_center.insights.classification.with_raw_response.update( + issue_id="issue_id", + account_id="", + ) + + with pytest.raises(ValueError, match=r"You must provide either account_id or zone_id"): + await async_client.security_center.insights.classification.with_raw_response.update( + issue_id="issue_id", + account_id="account_id", + ) diff --git a/tests/api_resources/security_center/insights/test_context.py b/tests/api_resources/security_center/insights/test_context.py new file mode 100644 index 00000000000..0888ca0b618 --- /dev/null +++ b/tests/api_resources/security_center/insights/test_context.py @@ -0,0 +1,120 @@ +# 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.security_center.insights import ContextGetResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestContext: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_get(self, client: Cloudflare) -> None: + context = client.security_center.insights.context.get( + issue_id="issue_id", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + assert_matches_type(Optional[ContextGetResponse], context, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Cloudflare) -> None: + response = client.security_center.insights.context.with_raw_response.get( + issue_id="issue_id", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + context = response.parse() + assert_matches_type(Optional[ContextGetResponse], context, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Cloudflare) -> None: + with client.security_center.insights.context.with_streaming_response.get( + issue_id="issue_id", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + context = response.parse() + assert_matches_type(Optional[ContextGetResponse], context, 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.security_center.insights.context.with_raw_response.get( + issue_id="issue_id", + account_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `issue_id` but received ''"): + client.security_center.insights.context.with_raw_response.get( + issue_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + +class TestAsyncContext: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_get(self, async_client: AsyncCloudflare) -> None: + context = await async_client.security_center.insights.context.get( + issue_id="issue_id", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + assert_matches_type(Optional[ContextGetResponse], context, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncCloudflare) -> None: + response = await async_client.security_center.insights.context.with_raw_response.get( + issue_id="issue_id", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + context = await response.parse() + assert_matches_type(Optional[ContextGetResponse], context, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncCloudflare) -> None: + async with async_client.security_center.insights.context.with_streaming_response.get( + issue_id="issue_id", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + context = await response.parse() + assert_matches_type(Optional[ContextGetResponse], context, 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.security_center.insights.context.with_raw_response.get( + issue_id="issue_id", + account_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `issue_id` but received ''"): + await async_client.security_center.insights.context.with_raw_response.get( + issue_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) From fff49eecdedf1f9b321b24ac391848418ebe37d3 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 4 May 2026 16:06:43 +0000 Subject: [PATCH 31/45] chore(api): update composite API spec --- .stats.yml | 2 +- .../resources/email_security/submissions.py | 12 ++++++++++++ src/cloudflare/types/billing/usage_paygo_response.py | 6 +++++- .../types/email_security/submission_list_params.py | 7 +++++++ .../api_resources/email_security/test_submissions.py | 2 ++ 5 files changed, 27 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 9bf78ffa2c1..35c47a6df7d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 2204 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a6c352830d1270d0abb5bb983058ea21815e1bb7d2e163965335dcb0e706f057.yml -openapi_spec_hash: 887efce5205bdef9eec55d574113ef5b +openapi_spec_hash: d6aabfab666cd45b35131f8d45cb09aa config_hash: ff549978909de2badc92845fea964f4b diff --git a/src/cloudflare/resources/email_security/submissions.py b/src/cloudflare/resources/email_security/submissions.py index be830a3f4e9..55221b2c05e 100644 --- a/src/cloudflare/resources/email_security/submissions.py +++ b/src/cloudflare/resources/email_security/submissions.py @@ -51,6 +51,7 @@ def list( *, account_id: str, end: Union[str, datetime] | Omit = omit, + escalated_from_user: bool | Omit = omit, original_disposition: Literal["MALICIOUS", "SUSPICIOUS", "SPOOF", "SPAM", "BULK", "NONE"] | Omit = omit, outcome_disposition: Literal["MALICIOUS", "SUSPICIOUS", "SPOOF", "SPAM", "BULK", "NONE"] | Omit = omit, page: int | Omit = omit, @@ -79,6 +80,10 @@ def list( end: The end of the search date range. Defaults to `now`. + escalated_from_user: When true, return only submissions that were escalated by an end user (vs. by + the security team). When false, return only submissions that were not escalated + by an end user. When omitted, no filter is applied. + page: Current page within paginated list of results. per_page: The number of results per page. Maximum value is 1000. @@ -106,6 +111,7 @@ def list( query=maybe_transform( { "end": end, + "escalated_from_user": escalated_from_user, "original_disposition": original_disposition, "outcome_disposition": outcome_disposition, "page": page, @@ -149,6 +155,7 @@ def list( *, account_id: str, end: Union[str, datetime] | Omit = omit, + escalated_from_user: bool | Omit = omit, original_disposition: Literal["MALICIOUS", "SUSPICIOUS", "SPOOF", "SPAM", "BULK", "NONE"] | Omit = omit, outcome_disposition: Literal["MALICIOUS", "SUSPICIOUS", "SPOOF", "SPAM", "BULK", "NONE"] | Omit = omit, page: int | Omit = omit, @@ -177,6 +184,10 @@ def list( end: The end of the search date range. Defaults to `now`. + escalated_from_user: When true, return only submissions that were escalated by an end user (vs. by + the security team). When false, return only submissions that were not escalated + by an end user. When omitted, no filter is applied. + page: Current page within paginated list of results. per_page: The number of results per page. Maximum value is 1000. @@ -204,6 +215,7 @@ def list( query=maybe_transform( { "end": end, + "escalated_from_user": escalated_from_user, "original_disposition": original_disposition, "outcome_disposition": outcome_disposition, "page": page, diff --git a/src/cloudflare/types/billing/usage_paygo_response.py b/src/cloudflare/types/billing/usage_paygo_response.py index 23db8801493..9b5a22770dd 100644 --- a/src/cloudflare/types/billing/usage_paygo_response.py +++ b/src/cloudflare/types/billing/usage_paygo_response.py @@ -30,7 +30,11 @@ class UsagePaygoResponseItem(BaseModel): """Specifies the quantity consumed during this charge period.""" consumed_unit: str = FieldInfo(alias="ConsumedUnit") - """Specifies the unit of measurement for consumed quantity.""" + """ + A display name for the unit of measurement used for the product (for example, + "GB-months", "GB-seconds"). May be empty when the unit is implicit in the + service name. + """ contracted_cost: float = FieldInfo(alias="ContractedCost") """Specifies the cost for this charge period in the billing currency.""" diff --git a/src/cloudflare/types/email_security/submission_list_params.py b/src/cloudflare/types/email_security/submission_list_params.py index b333cbd18b4..05b4f85a5c1 100644 --- a/src/cloudflare/types/email_security/submission_list_params.py +++ b/src/cloudflare/types/email_security/submission_list_params.py @@ -18,6 +18,13 @@ class SubmissionListParams(TypedDict, total=False): end: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] """The end of the search date range. Defaults to `now`.""" + escalated_from_user: bool + """When true, return only submissions that were escalated by an end user (vs. + + by the security team). When false, return only submissions that were not + escalated by an end user. When omitted, no filter is applied. + """ + original_disposition: Literal["MALICIOUS", "SUSPICIOUS", "SPOOF", "SPAM", "BULK", "NONE"] outcome_disposition: Literal["MALICIOUS", "SUSPICIOUS", "SPOOF", "SPAM", "BULK", "NONE"] diff --git a/tests/api_resources/email_security/test_submissions.py b/tests/api_resources/email_security/test_submissions.py index a3ccfcd375d..d5600c91546 100644 --- a/tests/api_resources/email_security/test_submissions.py +++ b/tests/api_resources/email_security/test_submissions.py @@ -31,6 +31,7 @@ def test_method_list_with_all_params(self, client: Cloudflare) -> None: submission = client.email_security.submissions.list( account_id="023e105f4ecef8ad9ca31a8372d0c353", end=parse_datetime("2019-12-27T18:11:19.117Z"), + escalated_from_user=True, original_disposition="MALICIOUS", outcome_disposition="MALICIOUS", page=1, @@ -93,6 +94,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncCloudflare) submission = await async_client.email_security.submissions.list( account_id="023e105f4ecef8ad9ca31a8372d0c353", end=parse_datetime("2019-12-27T18:11:19.117Z"), + escalated_from_user=True, original_disposition="MALICIOUS", outcome_disposition="MALICIOUS", page=1, From 99e3320086fdd1307668ed81eac12ac94b4e913e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 4 May 2026 17:15:40 +0000 Subject: [PATCH 32/45] chore(api): update composite API spec --- .stats.yml | 2 +- src/cloudflare/resources/radar/dns/dns.py | 6 ++++-- src/cloudflare/types/intel/indicator_feed_get_response.py | 2 +- .../types/radar/dns_timeseries_groups_v2_params.py | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.stats.yml b/.stats.yml index 35c47a6df7d..b1e48a0faf2 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 2204 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a6c352830d1270d0abb5bb983058ea21815e1bb7d2e163965335dcb0e706f057.yml -openapi_spec_hash: d6aabfab666cd45b35131f8d45cb09aa +openapi_spec_hash: 52aad06f805e68dbb16da9a73c3a3ee6 config_hash: ff549978909de2badc92845fea964f4b diff --git a/src/cloudflare/resources/radar/dns/dns.py b/src/cloudflare/resources/radar/dns/dns.py index d5dd5c4a307..59c30541a27 100644 --- a/src/cloudflare/resources/radar/dns/dns.py +++ b/src/cloudflare/resources/radar/dns/dns.py @@ -628,6 +628,7 @@ def timeseries_groups_v2( "RESPONSE_CODE", "RESPONSE_TTL", "TLD", + "TLD_DNS_MAGNITUDE", ], *, agg_interval: Literal["15m", "1h", "1d", "1w"] | Omit = omit, @@ -647,7 +648,7 @@ def timeseries_groups_v2( matching_answer: Iterable[bool] | Omit = omit, name: SequenceNotStr[str] | Omit = omit, nodata: Iterable[bool] | Omit = omit, - normalization: Literal["PERCENTAGE", "MIN0_MAX"] | Omit = omit, + normalization: Literal["PERCENTAGE", "MIN0_MAX", "RANK"] | Omit = omit, protocol: List[Literal["UDP", "TCP", "HTTPS", "TLS"]] | Omit = omit, query_type: List[ Optional[ @@ -1473,6 +1474,7 @@ async def timeseries_groups_v2( "RESPONSE_CODE", "RESPONSE_TTL", "TLD", + "TLD_DNS_MAGNITUDE", ], *, agg_interval: Literal["15m", "1h", "1d", "1w"] | Omit = omit, @@ -1492,7 +1494,7 @@ async def timeseries_groups_v2( matching_answer: Iterable[bool] | Omit = omit, name: SequenceNotStr[str] | Omit = omit, nodata: Iterable[bool] | Omit = omit, - normalization: Literal["PERCENTAGE", "MIN0_MAX"] | Omit = omit, + normalization: Literal["PERCENTAGE", "MIN0_MAX", "RANK"] | Omit = omit, protocol: List[Literal["UDP", "TCP", "HTTPS", "TLS"]] | Omit = omit, query_type: List[ Optional[ diff --git a/src/cloudflare/types/intel/indicator_feed_get_response.py b/src/cloudflare/types/intel/indicator_feed_get_response.py index 6373b835d80..3e47a74a68a 100644 --- a/src/cloudflare/types/intel/indicator_feed_get_response.py +++ b/src/cloudflare/types/intel/indicator_feed_get_response.py @@ -39,7 +39,7 @@ class IndicatorFeedGetResponse(BaseModel): name: Optional[str] = None """The name of the indicator feed""" - provider_id: Optional[str] = None + provider_id: Optional[int] = None """The unique identifier for the provider""" provider_name: Optional[str] = None diff --git a/src/cloudflare/types/radar/dns_timeseries_groups_v2_params.py b/src/cloudflare/types/radar/dns_timeseries_groups_v2_params.py index 34262ad0cdd..4afa74b1e66 100644 --- a/src/cloudflare/types/radar/dns_timeseries_groups_v2_params.py +++ b/src/cloudflare/types/radar/dns_timeseries_groups_v2_params.py @@ -94,7 +94,7 @@ class DNSTimeseriesGroupsV2Params(TypedDict, total=False): nodata: Iterable[bool] """Specifies whether the response includes empty DNS responses (NODATA).""" - normalization: Literal["PERCENTAGE", "MIN0_MAX"] + normalization: Literal["PERCENTAGE", "MIN0_MAX", "RANK"] """Normalization method applied to the results. Refer to From a92f9ef92e9f22adfd1626c29d113d04a4f08b05 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 4 May 2026 21:00:37 +0000 Subject: [PATCH 33/45] chore(api): update composite API spec --- .stats.yml | 2 +- .../zero_trust/access/logs/access_requests.py | 54 ++++++--- .../zero_trust/access/logs/scim/updates.py | 56 ++++++--- .../identity_providers/scim/groups.py | 30 +++-- .../identity_providers/scim/users.py | 28 +++-- .../intel/indicator_feed_get_response.py | 108 +++++++++++++++++- .../access/logs/access_request_list_params.py | 35 ++++-- .../access/logs/scim/update_list_params.py | 36 ++++-- .../scim/group_list_params.py | 16 ++- .../scim/user_list_params.py | 15 ++- .../access/logs/scim/test_updates.py | 16 +-- .../identity_providers/scim/test_groups.py | 8 +- .../identity_providers/scim/test_users.py | 8 +- 13 files changed, 323 insertions(+), 89 deletions(-) diff --git a/.stats.yml b/.stats.yml index b1e48a0faf2..1ed9537b832 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 2204 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a6c352830d1270d0abb5bb983058ea21815e1bb7d2e163965335dcb0e706f057.yml -openapi_spec_hash: 52aad06f805e68dbb16da9a73c3a3ee6 +openapi_spec_hash: e722ad1f58e3dfb3a928cf9890d48da4 config_hash: ff549978909de2badc92845fea964f4b diff --git a/src/cloudflare/resources/zero_trust/access/logs/access_requests.py b/src/cloudflare/resources/zero_trust/access/logs/access_requests.py index 06b0f797e51..cd871420c10 100644 --- a/src/cloudflare/resources/zero_trust/access/logs/access_requests.py +++ b/src/cloudflare/resources/zero_trust/access/logs/access_requests.py @@ -57,7 +57,7 @@ def list( direction: Literal["desc", "asc"] | Omit = omit, email: str | Omit = omit, email_exact: bool | Omit = omit, - email_op: Literal["eq", "neq"] | Omit = omit, + email_op: Literal["eq", "neq", "contains"] | Omit = omit, fields: str | Omit = omit, idp_op: Literal["eq", "neq"] | Omit = omit, limit: int | Omit = omit, @@ -92,14 +92,23 @@ def list( direction: The chronological sorting order for the logs. - email: Filter by user email. Defaults to substring matching. To force exact matching, - set `email_exact=true`. Example (default): `email=@example.com` returns all - events with that domain. Example (exact): - `email=user@example.com&email_exact=true` returns only that user. + email: Filter by user email. Match mode is controlled by `emailOp` (preferred) or the + legacy `email_exact` flag. + + - Default (no `emailOp`, `email_exact=false` or unset): substring match — + `email=@example.com` returns all events with that domain. + - Exact match: set `emailOp=eq` (preferred) or `email_exact=true` — e.g. + `email=user@example.com&email_exact=true` returns only that user. + - Explicit substring match: set `emailOp=contains` (without `email_exact=true`). + When both are set, `email_exact=true` takes precedence and the match is exact. + - Exclusion: set `emailOp=neq`. With `email_exact=true` this is an exact-value + exclusion; without it, a fuzzy substring exclusion. email_exact: When true, `email` is matched exactly instead of substring matching. - email_op: Operator for the `email` filter. + email_op: Operator for the `email` filter. `contains` performs a substring + (case-sensitive) match. When `email_exact=true` is also set, `email_exact` takes + precedence and `contains` is ignored. fields: Comma-separated list of fields to include in the response. When omitted, all fields are returned. @@ -120,9 +129,11 @@ def list( until: The latest event timestamp to query. - user_id: Filter by user UUID. + user_id: Deprecated. Accepted for backward compatibility but no longer applied as a + filter. Use `email` instead. - user_id_op: Operator for the `user_id` filter. + user_id_op: Deprecated. Accepted for backward compatibility but no longer applied as a + filter (the `user_id` parameter is itself deprecated). extra_headers: Send extra headers @@ -202,7 +213,7 @@ async def list( direction: Literal["desc", "asc"] | Omit = omit, email: str | Omit = omit, email_exact: bool | Omit = omit, - email_op: Literal["eq", "neq"] | Omit = omit, + email_op: Literal["eq", "neq", "contains"] | Omit = omit, fields: str | Omit = omit, idp_op: Literal["eq", "neq"] | Omit = omit, limit: int | Omit = omit, @@ -237,14 +248,23 @@ async def list( direction: The chronological sorting order for the logs. - email: Filter by user email. Defaults to substring matching. To force exact matching, - set `email_exact=true`. Example (default): `email=@example.com` returns all - events with that domain. Example (exact): - `email=user@example.com&email_exact=true` returns only that user. + email: Filter by user email. Match mode is controlled by `emailOp` (preferred) or the + legacy `email_exact` flag. + + - Default (no `emailOp`, `email_exact=false` or unset): substring match — + `email=@example.com` returns all events with that domain. + - Exact match: set `emailOp=eq` (preferred) or `email_exact=true` — e.g. + `email=user@example.com&email_exact=true` returns only that user. + - Explicit substring match: set `emailOp=contains` (without `email_exact=true`). + When both are set, `email_exact=true` takes precedence and the match is exact. + - Exclusion: set `emailOp=neq`. With `email_exact=true` this is an exact-value + exclusion; without it, a fuzzy substring exclusion. email_exact: When true, `email` is matched exactly instead of substring matching. - email_op: Operator for the `email` filter. + email_op: Operator for the `email` filter. `contains` performs a substring + (case-sensitive) match. When `email_exact=true` is also set, `email_exact` takes + precedence and `contains` is ignored. fields: Comma-separated list of fields to include in the response. When omitted, all fields are returned. @@ -265,9 +285,11 @@ async def list( until: The latest event timestamp to query. - user_id: Filter by user UUID. + user_id: Deprecated. Accepted for backward compatibility but no longer applied as a + filter. Use `email` instead. - user_id_op: Operator for the `user_id` filter. + user_id_op: Deprecated. Accepted for backward compatibility but no longer applied as a + filter (the `user_id` parameter is itself deprecated). extra_headers: Send extra headers diff --git a/src/cloudflare/resources/zero_trust/access/logs/scim/updates.py b/src/cloudflare/resources/zero_trust/access/logs/scim/updates.py index ce98c696427..df4556789ed 100644 --- a/src/cloudflare/resources/zero_trust/access/logs/scim/updates.py +++ b/src/cloudflare/resources/zero_trust/access/logs/scim/updates.py @@ -51,16 +51,16 @@ def list( *, account_id: str, idp_id: SequenceNotStr[str], - cf_resource_id: str | Omit = omit, + cf_resource_id: SequenceNotStr[str] | Omit = omit, direction: Literal["desc", "asc"] | Omit = omit, - idp_resource_id: str | Omit = omit, + idp_resource_id: SequenceNotStr[str] | Omit = omit, limit: int | Omit = omit, page: int | Omit = omit, per_page: int | Omit = omit, request_method: List[Literal["DELETE", "PATCH", "POST", "PUT"]] | Omit = omit, - resource_group_name: str | Omit = omit, + resource_group_name: SequenceNotStr[str] | Omit = omit, resource_type: List[Literal["USER", "GROUP"]] | Omit = omit, - resource_user_email: str | Omit = omit, + resource_user_email: SequenceNotStr[str] | Omit = omit, since: Union[str, datetime] | Omit = omit, status: List[Literal["FAILURE", "SUCCESS"]] | Omit = omit, until: Union[str, datetime] | Omit = omit, @@ -81,11 +81,17 @@ def list( idp_id: The unique Id of the IdP that has SCIM enabled. - cf_resource_id: The unique Cloudflare-generated Id of the SCIM resource. + cf_resource_id: The unique Cloudflare-generated Id of the SCIM resource. Pass once for a single + lookup (`?cf_resource_id=A`) or repeat the parameter + (`?cf_resource_id=A&cf_resource_id=B`) to filter by multiple resources in one + request. direction: The chronological order used to sort the logs. - idp_resource_id: The IdP-generated Id of the SCIM resource. + idp_resource_id: The IdP-generated Id of the SCIM resource. Pass once for a single lookup + (`?idp_resource_id=A`) or repeat the parameter + (`?idp_resource_id=A&idp_resource_id=B`) to filter by multiple resources in one + request. limit: The maximum number of update logs to retrieve. @@ -95,11 +101,17 @@ def list( request_method: The request method of the SCIM request. - resource_group_name: The display name of the SCIM Group resource. + resource_group_name: The display name of the SCIM Group resource. Pass once for a single lookup + (`?resource_group_name=A`) or repeat the parameter + (`?resource_group_name=A&resource_group_name=B`) to filter by multiple group + names in one request. resource_type: The resource type of the SCIM request. - resource_user_email: The email address of the SCIM User resource. + resource_user_email: The email address of the SCIM User resource. Pass once for a single lookup + (`?resource_user_email=A`) or repeat the parameter + (`?resource_user_email=A&resource_user_email=B`) to filter by multiple emails in + one request. since: the timestamp of the earliest update log. @@ -174,16 +186,16 @@ def list( *, account_id: str, idp_id: SequenceNotStr[str], - cf_resource_id: str | Omit = omit, + cf_resource_id: SequenceNotStr[str] | Omit = omit, direction: Literal["desc", "asc"] | Omit = omit, - idp_resource_id: str | Omit = omit, + idp_resource_id: SequenceNotStr[str] | Omit = omit, limit: int | Omit = omit, page: int | Omit = omit, per_page: int | Omit = omit, request_method: List[Literal["DELETE", "PATCH", "POST", "PUT"]] | Omit = omit, - resource_group_name: str | Omit = omit, + resource_group_name: SequenceNotStr[str] | Omit = omit, resource_type: List[Literal["USER", "GROUP"]] | Omit = omit, - resource_user_email: str | Omit = omit, + resource_user_email: SequenceNotStr[str] | Omit = omit, since: Union[str, datetime] | Omit = omit, status: List[Literal["FAILURE", "SUCCESS"]] | Omit = omit, until: Union[str, datetime] | Omit = omit, @@ -204,11 +216,17 @@ def list( idp_id: The unique Id of the IdP that has SCIM enabled. - cf_resource_id: The unique Cloudflare-generated Id of the SCIM resource. + cf_resource_id: The unique Cloudflare-generated Id of the SCIM resource. Pass once for a single + lookup (`?cf_resource_id=A`) or repeat the parameter + (`?cf_resource_id=A&cf_resource_id=B`) to filter by multiple resources in one + request. direction: The chronological order used to sort the logs. - idp_resource_id: The IdP-generated Id of the SCIM resource. + idp_resource_id: The IdP-generated Id of the SCIM resource. Pass once for a single lookup + (`?idp_resource_id=A`) or repeat the parameter + (`?idp_resource_id=A&idp_resource_id=B`) to filter by multiple resources in one + request. limit: The maximum number of update logs to retrieve. @@ -218,11 +236,17 @@ def list( request_method: The request method of the SCIM request. - resource_group_name: The display name of the SCIM Group resource. + resource_group_name: The display name of the SCIM Group resource. Pass once for a single lookup + (`?resource_group_name=A`) or repeat the parameter + (`?resource_group_name=A&resource_group_name=B`) to filter by multiple group + names in one request. resource_type: The resource type of the SCIM request. - resource_user_email: The email address of the SCIM User resource. + resource_user_email: The email address of the SCIM User resource. Pass once for a single lookup + (`?resource_user_email=A`) or repeat the parameter + (`?resource_user_email=A&resource_user_email=B`) to filter by multiple emails in + one request. since: the timestamp of the earliest update log. diff --git a/src/cloudflare/resources/zero_trust/identity_providers/scim/groups.py b/src/cloudflare/resources/zero_trust/identity_providers/scim/groups.py index 4fdf8cb5bea..7bc9fa1f7d6 100644 --- a/src/cloudflare/resources/zero_trust/identity_providers/scim/groups.py +++ b/src/cloudflare/resources/zero_trust/identity_providers/scim/groups.py @@ -4,7 +4,7 @@ import httpx -from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ....._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given from ....._utils import path_template, maybe_transform from ....._compat import cached_property from ....._resource import SyncAPIResource, AsyncAPIResource @@ -47,8 +47,8 @@ def list( identity_provider_id: str, *, account_id: str, - cf_resource_id: str | Omit = omit, - idp_resource_id: str | Omit = omit, + cf_resource_id: SequenceNotStr[str] | Omit = omit, + idp_resource_id: SequenceNotStr[str] | Omit = omit, name: str | Omit = omit, page: int | Omit = omit, per_page: int | Omit = omit, @@ -69,10 +69,16 @@ def list( identity_provider_id: UUID. cf_resource_id: The unique Cloudflare-generated Id of the SCIM Group resource; also known as the - "Id". + "Id". Pass once for a single lookup (`?cf_resource_id=A`) or repeat the + parameter (`?cf_resource_id=A&cf_resource_id=B`) to look up multiple groups in + one request, up to 50 values. Mutually exclusive with `idp_resource_id`, `name`, + `search_contains`, and `search_starts_with`. idp_resource_id: The IdP-generated Id of the SCIM Group resource; also known as the "external - Id". + Id". Pass once for a single lookup (`?idp_resource_id=A`) or repeat the + parameter (`?idp_resource_id=A&idp_resource_id=B`) to look up multiple groups in + one request, up to 50 values. Mutually exclusive with `cf_resource_id`, `name`, + `search_contains`, and `search_starts_with`. name: The display name of the SCIM Group resource. @@ -146,8 +152,8 @@ def list( identity_provider_id: str, *, account_id: str, - cf_resource_id: str | Omit = omit, - idp_resource_id: str | Omit = omit, + cf_resource_id: SequenceNotStr[str] | Omit = omit, + idp_resource_id: SequenceNotStr[str] | Omit = omit, name: str | Omit = omit, page: int | Omit = omit, per_page: int | Omit = omit, @@ -168,10 +174,16 @@ def list( identity_provider_id: UUID. cf_resource_id: The unique Cloudflare-generated Id of the SCIM Group resource; also known as the - "Id". + "Id". Pass once for a single lookup (`?cf_resource_id=A`) or repeat the + parameter (`?cf_resource_id=A&cf_resource_id=B`) to look up multiple groups in + one request, up to 50 values. Mutually exclusive with `idp_resource_id`, `name`, + `search_contains`, and `search_starts_with`. idp_resource_id: The IdP-generated Id of the SCIM Group resource; also known as the "external - Id". + Id". Pass once for a single lookup (`?idp_resource_id=A`) or repeat the + parameter (`?idp_resource_id=A&idp_resource_id=B`) to look up multiple groups in + one request, up to 50 values. Mutually exclusive with `cf_resource_id`, `name`, + `search_contains`, and `search_starts_with`. name: The display name of the SCIM Group resource. diff --git a/src/cloudflare/resources/zero_trust/identity_providers/scim/users.py b/src/cloudflare/resources/zero_trust/identity_providers/scim/users.py index e746cce4ace..e2f59069361 100644 --- a/src/cloudflare/resources/zero_trust/identity_providers/scim/users.py +++ b/src/cloudflare/resources/zero_trust/identity_providers/scim/users.py @@ -4,7 +4,7 @@ import httpx -from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ....._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given from ....._utils import path_template, maybe_transform from ....._compat import cached_property from ....._resource import SyncAPIResource, AsyncAPIResource @@ -47,9 +47,9 @@ def list( identity_provider_id: str, *, account_id: str, - cf_resource_id: str | Omit = omit, + cf_resource_id: SequenceNotStr[str] | Omit = omit, email: str | Omit = omit, - idp_resource_id: str | Omit = omit, + idp_resource_id: SequenceNotStr[str] | Omit = omit, name: str | Omit = omit, page: int | Omit = omit, per_page: int | Omit = omit, @@ -71,11 +71,18 @@ def list( identity_provider_id: UUID. cf_resource_id: The unique Cloudflare-generated Id of the SCIM User resource; also known as the - "Id". + "Id". Pass once for a single lookup (`?cf_resource_id=A`) or repeat the + parameter (`?cf_resource_id=A&cf_resource_id=B`) to look up multiple users in + one request, up to 50 values. Mutually exclusive with `idp_resource_id`, + `username`, `email`, `name`, `search_contains`, and `search_starts_with`. email: The email address of the SCIM User resource. idp_resource_id: The IdP-generated Id of the SCIM User resource; also known as the "external Id". + Pass once for a single lookup (`?idp_resource_id=A`) or repeat the parameter + (`?idp_resource_id=A&idp_resource_id=B`) to look up multiple users in one + request, up to 50 values. Mutually exclusive with `cf_resource_id`, `username`, + `email`, `name`, `search_contains`, and `search_starts_with`. name: The name of the SCIM User resource. @@ -153,9 +160,9 @@ def list( identity_provider_id: str, *, account_id: str, - cf_resource_id: str | Omit = omit, + cf_resource_id: SequenceNotStr[str] | Omit = omit, email: str | Omit = omit, - idp_resource_id: str | Omit = omit, + idp_resource_id: SequenceNotStr[str] | Omit = omit, name: str | Omit = omit, page: int | Omit = omit, per_page: int | Omit = omit, @@ -177,11 +184,18 @@ def list( identity_provider_id: UUID. cf_resource_id: The unique Cloudflare-generated Id of the SCIM User resource; also known as the - "Id". + "Id". Pass once for a single lookup (`?cf_resource_id=A`) or repeat the + parameter (`?cf_resource_id=A&cf_resource_id=B`) to look up multiple users in + one request, up to 50 values. Mutually exclusive with `idp_resource_id`, + `username`, `email`, `name`, `search_contains`, and `search_starts_with`. email: The email address of the SCIM User resource. idp_resource_id: The IdP-generated Id of the SCIM User resource; also known as the "external Id". + Pass once for a single lookup (`?idp_resource_id=A`) or repeat the parameter + (`?idp_resource_id=A&idp_resource_id=B`) to look up multiple users in one + request, up to 50 values. Mutually exclusive with `cf_resource_id`, `username`, + `email`, `name`, `search_contains`, and `search_starts_with`. name: The name of the SCIM User resource. diff --git a/src/cloudflare/types/intel/indicator_feed_get_response.py b/src/cloudflare/types/intel/indicator_feed_get_response.py index 3e47a74a68a..654460a6802 100644 --- a/src/cloudflare/types/intel/indicator_feed_get_response.py +++ b/src/cloudflare/types/intel/indicator_feed_get_response.py @@ -6,7 +6,103 @@ from ..._models import BaseModel -__all__ = ["IndicatorFeedGetResponse"] +__all__ = [ + "IndicatorFeedGetResponse", + "LastUploadSummary", + "LastUploadSummaryPersisted", + "LastUploadSummarySkipped", + "LastUploadSummaryUploaded", +] + + +class LastUploadSummaryPersisted(BaseModel): + """Net delta applied to feed indicators by this upload. + + Snapshot + uploads emit both *_added and *_removed; delta-add emits only + *_added; delta-remove emits only *_removed. + """ + + domains_added: Optional[int] = None + + domains_removed: Optional[int] = None + + ips_added: Optional[int] = None + + ips_removed: Optional[int] = None + + urls_added: Optional[int] = None + + urls_removed: Optional[int] = None + + +class LastUploadSummarySkipped(BaseModel): + """ + Counts of indicators that were uploaded but did not reach + QuickSilver, broken down by reason. + """ + + allowlisted_domains: Optional[int] = None + """Domains filtered by the global popularity allowlist at QS provisioning time. + + Popular domains (bing.com, naver.com, etc.) are protected from + custom-threat-feed enforcement. + """ + + expired_indicators: Optional[int] = None + """Indicators in the upload whose valid_until is already in the past. + + These are not added to QS; the expiration cron handles cleanup. + """ + + invalid_indicators: Optional[int] = None + """Reserved for future use. + + Currently always 0 — the unifier aborts the entire upload on a single bad + indicator. + """ + + +class LastUploadSummaryUploaded(BaseModel): + """Indicator counts from the unified file the loader received""" + + domains: Optional[int] = None + """Number of domain indicators in the upload""" + + ips: Optional[int] = None + """Number of IP indicators in the upload""" + + urls: Optional[int] = None + """Number of URL indicators in the upload""" + + +class LastUploadSummary(BaseModel): + """Summary of indicator counts from the last successful upload to this + feed. + + Populated by the custom-threat-feeds loader at the end of each + successful load. Absent (omitted) when no upload has completed + successfully or the upload errored before the summary write. + Surfaces silent-failure paths so operators can see when their + indicators were dropped (popularity allowlist, expired valid_until, + etc.) without reading loader logs. + """ + + persisted: Optional[LastUploadSummaryPersisted] = None + """Net delta applied to feed indicators by this upload. + + Snapshot uploads emit both _\\__added and _\\__removed; delta-add emits only + _\\__added; delta-remove emits only _\\__removed. + """ + + skipped: Optional[LastUploadSummarySkipped] = None + """ + Counts of indicators that were uploaded but did not reach QuickSilver, broken + down by reason. + """ + + uploaded: Optional[LastUploadSummaryUploaded] = None + """Indicator counts from the unified file the loader received""" class IndicatorFeedGetResponse(BaseModel): @@ -28,6 +124,16 @@ class IndicatorFeedGetResponse(BaseModel): is_public: Optional[bool] = None """Whether the indicator feed is exposed to customers""" + last_upload_summary: Optional[LastUploadSummary] = None + """Summary of indicator counts from the last successful upload to this feed. + + Populated by the custom-threat-feeds loader at the end of each successful load. + Absent (omitted) when no upload has completed successfully or the upload errored + before the summary write. Surfaces silent-failure paths so operators can see + when their indicators were dropped (popularity allowlist, expired valid_until, + etc.) without reading loader logs. + """ + latest_upload_status: Optional[Literal["Mirroring", "Unifying", "Loading", "Provisioning", "Complete", "Error"]] = ( None ) diff --git a/src/cloudflare/types/zero_trust/access/logs/access_request_list_params.py b/src/cloudflare/types/zero_trust/access/logs/access_request_list_params.py index c22b8ff0793..93d82bced7e 100644 --- a/src/cloudflare/types/zero_trust/access/logs/access_request_list_params.py +++ b/src/cloudflare/types/zero_trust/access/logs/access_request_list_params.py @@ -33,17 +33,28 @@ class AccessRequestListParams(TypedDict, total=False): email: str """Filter by user email. - Defaults to substring matching. To force exact matching, set `email_exact=true`. - Example (default): `email=@example.com` returns all events with that domain. - Example (exact): `email=user@example.com&email_exact=true` returns only that - user. + Match mode is controlled by `emailOp` (preferred) or the legacy `email_exact` + flag. + + - Default (no `emailOp`, `email_exact=false` or unset): substring match — + `email=@example.com` returns all events with that domain. + - Exact match: set `emailOp=eq` (preferred) or `email_exact=true` — e.g. + `email=user@example.com&email_exact=true` returns only that user. + - Explicit substring match: set `emailOp=contains` (without `email_exact=true`). + When both are set, `email_exact=true` takes precedence and the match is exact. + - Exclusion: set `emailOp=neq`. With `email_exact=true` this is an exact-value + exclusion; without it, a fuzzy substring exclusion. """ email_exact: bool """When true, `email` is matched exactly instead of substring matching.""" - email_op: Annotated[Literal["eq", "neq"], PropertyInfo(alias="emailOp")] - """Operator for the `email` filter.""" + email_op: Annotated[Literal["eq", "neq", "contains"], PropertyInfo(alias="emailOp")] + """ + Operator for the `email` filter. `contains` performs a substring + (case-sensitive) match. When `email_exact=true` is also set, `email_exact` takes + precedence and `contains` is ignored. + """ fields: str """ @@ -76,7 +87,15 @@ class AccessRequestListParams(TypedDict, total=False): """The latest event timestamp to query.""" user_id: str - """Filter by user UUID.""" + """Deprecated. + + Accepted for backward compatibility but no longer applied as a filter. Use + `email` instead. + """ user_id_op: Annotated[Literal["eq", "neq"], PropertyInfo(alias="user_idOp")] - """Operator for the `user_id` filter.""" + """Deprecated. + + Accepted for backward compatibility but no longer applied as a filter (the + `user_id` parameter is itself deprecated). + """ diff --git a/src/cloudflare/types/zero_trust/access/logs/scim/update_list_params.py b/src/cloudflare/types/zero_trust/access/logs/scim/update_list_params.py index 6ef5bb55bb5..f5dce87349e 100644 --- a/src/cloudflare/types/zero_trust/access/logs/scim/update_list_params.py +++ b/src/cloudflare/types/zero_trust/access/logs/scim/update_list_params.py @@ -19,14 +19,24 @@ class UpdateListParams(TypedDict, total=False): idp_id: Required[SequenceNotStr[str]] """The unique Id of the IdP that has SCIM enabled.""" - cf_resource_id: str - """The unique Cloudflare-generated Id of the SCIM resource.""" + cf_resource_id: SequenceNotStr[str] + """The unique Cloudflare-generated Id of the SCIM resource. + + Pass once for a single lookup (`?cf_resource_id=A`) or repeat the parameter + (`?cf_resource_id=A&cf_resource_id=B`) to filter by multiple resources in one + request. + """ direction: Literal["desc", "asc"] """The chronological order used to sort the logs.""" - idp_resource_id: str - """The IdP-generated Id of the SCIM resource.""" + idp_resource_id: SequenceNotStr[str] + """The IdP-generated Id of the SCIM resource. + + Pass once for a single lookup (`?idp_resource_id=A`) or repeat the parameter + (`?idp_resource_id=A&idp_resource_id=B`) to filter by multiple resources in one + request. + """ limit: int """The maximum number of update logs to retrieve.""" @@ -40,14 +50,24 @@ class UpdateListParams(TypedDict, total=False): request_method: List[Literal["DELETE", "PATCH", "POST", "PUT"]] """The request method of the SCIM request.""" - resource_group_name: str - """The display name of the SCIM Group resource.""" + resource_group_name: SequenceNotStr[str] + """The display name of the SCIM Group resource. + + Pass once for a single lookup (`?resource_group_name=A`) or repeat the parameter + (`?resource_group_name=A&resource_group_name=B`) to filter by multiple group + names in one request. + """ resource_type: List[Literal["USER", "GROUP"]] """The resource type of the SCIM request.""" - resource_user_email: str - """The email address of the SCIM User resource.""" + resource_user_email: SequenceNotStr[str] + """The email address of the SCIM User resource. + + Pass once for a single lookup (`?resource_user_email=A`) or repeat the parameter + (`?resource_user_email=A&resource_user_email=B`) to filter by multiple emails in + one request. + """ since: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] """the timestamp of the earliest update log.""" diff --git a/src/cloudflare/types/zero_trust/identity_providers/scim/group_list_params.py b/src/cloudflare/types/zero_trust/identity_providers/scim/group_list_params.py index c94b4b175b1..370c558493a 100644 --- a/src/cloudflare/types/zero_trust/identity_providers/scim/group_list_params.py +++ b/src/cloudflare/types/zero_trust/identity_providers/scim/group_list_params.py @@ -4,6 +4,8 @@ from typing_extensions import Required, TypedDict +from ....._types import SequenceNotStr + __all__ = ["GroupListParams"] @@ -11,16 +13,22 @@ class GroupListParams(TypedDict, total=False): account_id: Required[str] """Identifier.""" - cf_resource_id: str + cf_resource_id: SequenceNotStr[str] """ The unique Cloudflare-generated Id of the SCIM Group resource; also known as the - "Id". + "Id". Pass once for a single lookup (`?cf_resource_id=A`) or repeat the + parameter (`?cf_resource_id=A&cf_resource_id=B`) to look up multiple groups in + one request, up to 50 values. Mutually exclusive with `idp_resource_id`, `name`, + `search_contains`, and `search_starts_with`. """ - idp_resource_id: str + idp_resource_id: SequenceNotStr[str] """ The IdP-generated Id of the SCIM Group resource; also known as the "external - Id". + Id". Pass once for a single lookup (`?idp_resource_id=A`) or repeat the + parameter (`?idp_resource_id=A&idp_resource_id=B`) to look up multiple groups in + one request, up to 50 values. Mutually exclusive with `cf_resource_id`, `name`, + `search_contains`, and `search_starts_with`. """ name: str diff --git a/src/cloudflare/types/zero_trust/identity_providers/scim/user_list_params.py b/src/cloudflare/types/zero_trust/identity_providers/scim/user_list_params.py index 6ce2445eec1..f87694d9bd9 100644 --- a/src/cloudflare/types/zero_trust/identity_providers/scim/user_list_params.py +++ b/src/cloudflare/types/zero_trust/identity_providers/scim/user_list_params.py @@ -4,6 +4,8 @@ from typing_extensions import Required, TypedDict +from ....._types import SequenceNotStr + __all__ = ["UserListParams"] @@ -11,18 +13,25 @@ class UserListParams(TypedDict, total=False): account_id: Required[str] """Identifier.""" - cf_resource_id: str + cf_resource_id: SequenceNotStr[str] """ The unique Cloudflare-generated Id of the SCIM User resource; also known as the - "Id". + "Id". Pass once for a single lookup (`?cf_resource_id=A`) or repeat the + parameter (`?cf_resource_id=A&cf_resource_id=B`) to look up multiple users in + one request, up to 50 values. Mutually exclusive with `idp_resource_id`, + `username`, `email`, `name`, `search_contains`, and `search_starts_with`. """ email: str """The email address of the SCIM User resource.""" - idp_resource_id: str + idp_resource_id: SequenceNotStr[str] """ The IdP-generated Id of the SCIM User resource; also known as the "external Id". + Pass once for a single lookup (`?idp_resource_id=A`) or repeat the parameter + (`?idp_resource_id=A&idp_resource_id=B`) to look up multiple users in one + request, up to 50 values. Mutually exclusive with `cf_resource_id`, `username`, + `email`, `name`, `search_contains`, and `search_starts_with`. """ name: str diff --git a/tests/api_resources/zero_trust/access/logs/scim/test_updates.py b/tests/api_resources/zero_trust/access/logs/scim/test_updates.py index 8c4f2fd02e5..28f3ed97e00 100644 --- a/tests/api_resources/zero_trust/access/logs/scim/test_updates.py +++ b/tests/api_resources/zero_trust/access/logs/scim/test_updates.py @@ -32,16 +32,16 @@ def test_method_list_with_all_params(self, client: Cloudflare) -> None: update = client.zero_trust.access.logs.scim.updates.list( account_id="023e105f4ecef8ad9ca31a8372d0c353", idp_id=["df7e2w5f-02b7-4d9d-af26-8d1988fca630", "0194ae2c-efcf-7cfb-8884-055f1a161fa5"], - cf_resource_id="bd97ef8d-7986-43e3-9ee0-c25dda33e4b0", + cf_resource_id=["bd97ef8d-7986-43e3-9ee0-c25dda33e4b0"], direction="desc", - idp_resource_id="idp_resource_id", + idp_resource_id=["all_employees"], limit=10, page=0, per_page=0, request_method=["DELETE", "PATCH"], - resource_group_name="ALL_EMPLOYEES", + resource_group_name=["ALL_EMPLOYEES"], resource_type=["USER", "GROUP"], - resource_user_email="john.smith@example.com", + resource_user_email=["john.smith@example.com"], since=parse_datetime("2025-01-01T00:00:00Z"), status=["FAILURE", "SUCCESS"], until=parse_datetime("2025-01-02T00:00:00Z"), @@ -101,16 +101,16 @@ async def test_method_list_with_all_params(self, async_client: AsyncCloudflare) update = await async_client.zero_trust.access.logs.scim.updates.list( account_id="023e105f4ecef8ad9ca31a8372d0c353", idp_id=["df7e2w5f-02b7-4d9d-af26-8d1988fca630", "0194ae2c-efcf-7cfb-8884-055f1a161fa5"], - cf_resource_id="bd97ef8d-7986-43e3-9ee0-c25dda33e4b0", + cf_resource_id=["bd97ef8d-7986-43e3-9ee0-c25dda33e4b0"], direction="desc", - idp_resource_id="idp_resource_id", + idp_resource_id=["all_employees"], limit=10, page=0, per_page=0, request_method=["DELETE", "PATCH"], - resource_group_name="ALL_EMPLOYEES", + resource_group_name=["ALL_EMPLOYEES"], resource_type=["USER", "GROUP"], - resource_user_email="john.smith@example.com", + resource_user_email=["john.smith@example.com"], since=parse_datetime("2025-01-01T00:00:00Z"), status=["FAILURE", "SUCCESS"], until=parse_datetime("2025-01-02T00:00:00Z"), diff --git a/tests/api_resources/zero_trust/identity_providers/scim/test_groups.py b/tests/api_resources/zero_trust/identity_providers/scim/test_groups.py index c19dce42b04..170f83a0043 100644 --- a/tests/api_resources/zero_trust/identity_providers/scim/test_groups.py +++ b/tests/api_resources/zero_trust/identity_providers/scim/test_groups.py @@ -31,8 +31,8 @@ def test_method_list_with_all_params(self, client: Cloudflare) -> None: group = client.zero_trust.identity_providers.scim.groups.list( identity_provider_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", - cf_resource_id="a2abeb50-59c9-4c01-8c5c-963d3bf5700f", - idp_resource_id="all_employees", + cf_resource_id=["a2abeb50-59c9-4c01-8c5c-963d3bf5700f"], + idp_resource_id=["all_employees"], name="ALL_EMPLOYEES", page=0, per_page=0, @@ -98,8 +98,8 @@ async def test_method_list_with_all_params(self, async_client: AsyncCloudflare) group = await async_client.zero_trust.identity_providers.scim.groups.list( identity_provider_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", - cf_resource_id="a2abeb50-59c9-4c01-8c5c-963d3bf5700f", - idp_resource_id="all_employees", + cf_resource_id=["a2abeb50-59c9-4c01-8c5c-963d3bf5700f"], + idp_resource_id=["all_employees"], name="ALL_EMPLOYEES", page=0, per_page=0, diff --git a/tests/api_resources/zero_trust/identity_providers/scim/test_users.py b/tests/api_resources/zero_trust/identity_providers/scim/test_users.py index 8d1eebe0ccf..a3f57d24030 100644 --- a/tests/api_resources/zero_trust/identity_providers/scim/test_users.py +++ b/tests/api_resources/zero_trust/identity_providers/scim/test_users.py @@ -31,9 +31,9 @@ def test_method_list_with_all_params(self, client: Cloudflare) -> None: user = client.zero_trust.identity_providers.scim.users.list( identity_provider_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", - cf_resource_id="bd97ef8d-7986-43e3-9ee0-c25dda33e4b0", + cf_resource_id=["bd97ef8d-7986-43e3-9ee0-c25dda33e4b0"], email="john.smith@example.com", - idp_resource_id="john_smith_01", + idp_resource_id=["john_smith_01"], name="John Smith", page=0, per_page=0, @@ -100,9 +100,9 @@ async def test_method_list_with_all_params(self, async_client: AsyncCloudflare) user = await async_client.zero_trust.identity_providers.scim.users.list( identity_provider_id="f174e90a-fafe-4643-bbbc-4a0ed4fc8415", account_id="023e105f4ecef8ad9ca31a8372d0c353", - cf_resource_id="bd97ef8d-7986-43e3-9ee0-c25dda33e4b0", + cf_resource_id=["bd97ef8d-7986-43e3-9ee0-c25dda33e4b0"], email="john.smith@example.com", - idp_resource_id="john_smith_01", + idp_resource_id=["john_smith_01"], name="John Smith", page=0, per_page=0, From 46898b8d3192ff1f087d021db6ff3cd9219eccb5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 5 May 2026 14:24:50 +0000 Subject: [PATCH 34/45] feat: feat: add resource library endpoints inside zero trust * feat: add resource library endpoints inside zero trust * fix: configure resource library endpoints as data sources only in terraform * feat: add terraform resource names for zero trust resource library endpoints * feat: restructure resource library endpoints to nest applications under subresources * fix: standardize account_id parameter naming in resource library endpoints * feat: add resource library endpoints inside zero trust --- .stats.yml | 4 +- .../resources/zero_trust/__init__.py | 14 + src/cloudflare/resources/zero_trust/api.md | 31 ++ .../zero_trust/resource_library/__init__.py | 47 +++ .../resource_library/applications.py | 336 ++++++++++++++++++ .../zero_trust/resource_library/categories.py | 296 +++++++++++++++ .../resource_library/resource_library.py | 134 +++++++ .../resources/zero_trust/zero_trust.py | 32 ++ .../zero_trust/resource_library/__init__.py | 10 + .../application_get_response.py | 60 ++++ .../application_list_params.py | 35 ++ .../application_list_response.py | 60 ++++ .../resource_library/category_get_response.py | 19 + .../resource_library/category_list_params.py | 17 + .../category_list_response.py | 19 + .../zero_trust/resource_library/__init__.py | 1 + .../resource_library/test_applications.py | 222 ++++++++++++ .../resource_library/test_categories.py | 215 +++++++++++ 18 files changed, 1550 insertions(+), 2 deletions(-) create mode 100644 src/cloudflare/resources/zero_trust/resource_library/__init__.py create mode 100644 src/cloudflare/resources/zero_trust/resource_library/applications.py create mode 100644 src/cloudflare/resources/zero_trust/resource_library/categories.py create mode 100644 src/cloudflare/resources/zero_trust/resource_library/resource_library.py create mode 100644 src/cloudflare/types/zero_trust/resource_library/__init__.py create mode 100644 src/cloudflare/types/zero_trust/resource_library/application_get_response.py create mode 100644 src/cloudflare/types/zero_trust/resource_library/application_list_params.py create mode 100644 src/cloudflare/types/zero_trust/resource_library/application_list_response.py create mode 100644 src/cloudflare/types/zero_trust/resource_library/category_get_response.py create mode 100644 src/cloudflare/types/zero_trust/resource_library/category_list_params.py create mode 100644 src/cloudflare/types/zero_trust/resource_library/category_list_response.py create mode 100644 tests/api_resources/zero_trust/resource_library/__init__.py create mode 100644 tests/api_resources/zero_trust/resource_library/test_applications.py create mode 100644 tests/api_resources/zero_trust/resource_library/test_categories.py diff --git a/.stats.yml b/.stats.yml index 1ed9537b832..df149afa657 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 2204 +configured_endpoints: 2208 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a6c352830d1270d0abb5bb983058ea21815e1bb7d2e163965335dcb0e706f057.yml openapi_spec_hash: e722ad1f58e3dfb3a928cf9890d48da4 -config_hash: ff549978909de2badc92845fea964f4b +config_hash: 20574d7a53e0349a3337a121a46638d4 diff --git a/src/cloudflare/resources/zero_trust/__init__.py b/src/cloudflare/resources/zero_trust/__init__.py index 7703df18c9b..7a42ce26500 100644 --- a/src/cloudflare/resources/zero_trust/__init__.py +++ b/src/cloudflare/resources/zero_trust/__init__.py @@ -88,6 +88,14 @@ OrganizationsResourceWithStreamingResponse, AsyncOrganizationsResourceWithStreamingResponse, ) +from .resource_library import ( + ResourceLibraryResource, + AsyncResourceLibraryResource, + ResourceLibraryResourceWithRawResponse, + AsyncResourceLibraryResourceWithRawResponse, + ResourceLibraryResourceWithStreamingResponse, + AsyncResourceLibraryResourceWithStreamingResponse, +) from .identity_providers import ( IdentityProvidersResource, AsyncIdentityProvidersResource, @@ -178,6 +186,12 @@ "AsyncRiskScoringResourceWithRawResponse", "RiskScoringResourceWithStreamingResponse", "AsyncRiskScoringResourceWithStreamingResponse", + "ResourceLibraryResource", + "AsyncResourceLibraryResource", + "ResourceLibraryResourceWithRawResponse", + "AsyncResourceLibraryResourceWithRawResponse", + "ResourceLibraryResourceWithStreamingResponse", + "AsyncResourceLibraryResourceWithStreamingResponse", "ZeroTrustResource", "AsyncZeroTrustResource", "ZeroTrustResourceWithRawResponse", diff --git a/src/cloudflare/resources/zero_trust/api.md b/src/cloudflare/resources/zero_trust/api.md index 35c0c1fd0d3..ac40770aada 100644 --- a/src/cloudflare/resources/zero_trust/api.md +++ b/src/cloudflare/resources/zero_trust/api.md @@ -1978,3 +1978,34 @@ from cloudflare.types.zero_trust.risk_scoring.integrations import ReferenceGetRe Methods: - client.zero_trust.risk_scoring.integrations.references.get(reference_id, \*, account_id) -> Optional[ReferenceGetResponse] + +## ResourceLibrary + +### Applications + +Types: + +```python +from cloudflare.types.zero_trust.resource_library import ( + ApplicationListResponse, + ApplicationGetResponse, +) +``` + +Methods: + +- client.zero_trust.resource_library.applications.list(\*, account_id, \*\*params) -> SyncSinglePage[ApplicationListResponse] +- client.zero_trust.resource_library.applications.get(id, \*, account_id) -> Optional[ApplicationGetResponse] + +### Categories + +Types: + +```python +from cloudflare.types.zero_trust.resource_library import CategoryListResponse, CategoryGetResponse +``` + +Methods: + +- client.zero_trust.resource_library.categories.list(\*, account_id, \*\*params) -> SyncSinglePage[CategoryListResponse] +- client.zero_trust.resource_library.categories.get(id, \*, account_id) -> Optional[CategoryGetResponse] diff --git a/src/cloudflare/resources/zero_trust/resource_library/__init__.py b/src/cloudflare/resources/zero_trust/resource_library/__init__.py new file mode 100644 index 00000000000..d110503ebed --- /dev/null +++ b/src/cloudflare/resources/zero_trust/resource_library/__init__.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .categories import ( + CategoriesResource, + AsyncCategoriesResource, + CategoriesResourceWithRawResponse, + AsyncCategoriesResourceWithRawResponse, + CategoriesResourceWithStreamingResponse, + AsyncCategoriesResourceWithStreamingResponse, +) +from .applications import ( + ApplicationsResource, + AsyncApplicationsResource, + ApplicationsResourceWithRawResponse, + AsyncApplicationsResourceWithRawResponse, + ApplicationsResourceWithStreamingResponse, + AsyncApplicationsResourceWithStreamingResponse, +) +from .resource_library import ( + ResourceLibraryResource, + AsyncResourceLibraryResource, + ResourceLibraryResourceWithRawResponse, + AsyncResourceLibraryResourceWithRawResponse, + ResourceLibraryResourceWithStreamingResponse, + AsyncResourceLibraryResourceWithStreamingResponse, +) + +__all__ = [ + "ApplicationsResource", + "AsyncApplicationsResource", + "ApplicationsResourceWithRawResponse", + "AsyncApplicationsResourceWithRawResponse", + "ApplicationsResourceWithStreamingResponse", + "AsyncApplicationsResourceWithStreamingResponse", + "CategoriesResource", + "AsyncCategoriesResource", + "CategoriesResourceWithRawResponse", + "AsyncCategoriesResourceWithRawResponse", + "CategoriesResourceWithStreamingResponse", + "AsyncCategoriesResourceWithStreamingResponse", + "ResourceLibraryResource", + "AsyncResourceLibraryResource", + "ResourceLibraryResourceWithRawResponse", + "AsyncResourceLibraryResourceWithRawResponse", + "ResourceLibraryResourceWithStreamingResponse", + "AsyncResourceLibraryResourceWithStreamingResponse", +] diff --git a/src/cloudflare/resources/zero_trust/resource_library/applications.py b/src/cloudflare/resources/zero_trust/resource_library/applications.py new file mode 100644 index 00000000000..bfc94f9b3c0 --- /dev/null +++ b/src/cloudflare/resources/zero_trust/resource_library/applications.py @@ -0,0 +1,336 @@ +# 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 Body, Omit, Query, Headers, NotGiven, omit, not_given +from ...._utils import path_template, 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 SyncSinglePage, AsyncSinglePage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.zero_trust.resource_library import application_list_params +from ....types.zero_trust.resource_library.application_get_response import ApplicationGetResponse +from ....types.zero_trust.resource_library.application_list_response import ApplicationListResponse + +__all__ = ["ApplicationsResource", "AsyncApplicationsResource"] + + +class ApplicationsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ApplicationsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 ApplicationsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ApplicationsResourceWithStreamingResponse: + """ + 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 ApplicationsResourceWithStreamingResponse(self) + + def list( + self, + *, + account_id: str, + filter: str | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + order_by: str | Omit = omit, + # 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, + ) -> SyncSinglePage[ApplicationListResponse]: + """ + List applications with different filters. + + Args: + filter: + Filter applications using key:value format. Supported filter keys: + + - name: Filter by application name (e.g., name:HR) + - id: Filter by application ID (e.g., id:0b63249c-95bf-4cc0-a7cc-d7faaaf1dac0) + - human_id: Filter by human-readable ID (e.g., human_id:HR) + - hostname: Filter by hostname or support domain (e.g., + hostname:portal.example.com) + - source: Filter by application source name (e.g., source:cloudflare) + - ip_subnet: Filter by IP subnet using CIDR containment — returns applications + where any stored subnet contains the search value (e.g., ip_subnet:10.0.1.5/32 + matches apps with 10.0.0.0/16) + - intel_id: Filter by Intel API ID (e.g., intel_id:498). . + + limit: Limit of number of results to return (max 250). + + offset: Offset of results to return. + + order_by: Order by result by field name and order (e.g., name:asc). + + 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( + path_template("/accounts/{account_id}/resource-library/applications", account_id=account_id), + page=SyncSinglePage[ApplicationListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "filter": filter, + "limit": limit, + "offset": offset, + "order_by": order_by, + }, + application_list_params.ApplicationListParams, + ), + ), + model=ApplicationListResponse, + ) + + def get( + self, + id: str, + *, + 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[ApplicationGetResponse]: + """ + Get application by ID. + + 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}") + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._get( + path_template("/accounts/{account_id}/resource-library/applications/{id}", account_id=account_id, id=id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[Optional[ApplicationGetResponse]]._unwrapper, + ), + cast_to=cast(Type[Optional[ApplicationGetResponse]], ResultWrapper[ApplicationGetResponse]), + ) + + +class AsyncApplicationsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncApplicationsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 AsyncApplicationsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncApplicationsResourceWithStreamingResponse: + """ + 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 AsyncApplicationsResourceWithStreamingResponse(self) + + def list( + self, + *, + account_id: str, + filter: str | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + order_by: str | Omit = omit, + # 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[ApplicationListResponse, AsyncSinglePage[ApplicationListResponse]]: + """ + List applications with different filters. + + Args: + filter: + Filter applications using key:value format. Supported filter keys: + + - name: Filter by application name (e.g., name:HR) + - id: Filter by application ID (e.g., id:0b63249c-95bf-4cc0-a7cc-d7faaaf1dac0) + - human_id: Filter by human-readable ID (e.g., human_id:HR) + - hostname: Filter by hostname or support domain (e.g., + hostname:portal.example.com) + - source: Filter by application source name (e.g., source:cloudflare) + - ip_subnet: Filter by IP subnet using CIDR containment — returns applications + where any stored subnet contains the search value (e.g., ip_subnet:10.0.1.5/32 + matches apps with 10.0.0.0/16) + - intel_id: Filter by Intel API ID (e.g., intel_id:498). . + + limit: Limit of number of results to return (max 250). + + offset: Offset of results to return. + + order_by: Order by result by field name and order (e.g., name:asc). + + 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( + path_template("/accounts/{account_id}/resource-library/applications", account_id=account_id), + page=AsyncSinglePage[ApplicationListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "filter": filter, + "limit": limit, + "offset": offset, + "order_by": order_by, + }, + application_list_params.ApplicationListParams, + ), + ), + model=ApplicationListResponse, + ) + + async def get( + self, + id: str, + *, + 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[ApplicationGetResponse]: + """ + Get application by ID. + + 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}") + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._get( + path_template("/accounts/{account_id}/resource-library/applications/{id}", account_id=account_id, id=id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[Optional[ApplicationGetResponse]]._unwrapper, + ), + cast_to=cast(Type[Optional[ApplicationGetResponse]], ResultWrapper[ApplicationGetResponse]), + ) + + +class ApplicationsResourceWithRawResponse: + def __init__(self, applications: ApplicationsResource) -> None: + self._applications = applications + + self.list = to_raw_response_wrapper( + applications.list, + ) + self.get = to_raw_response_wrapper( + applications.get, + ) + + +class AsyncApplicationsResourceWithRawResponse: + def __init__(self, applications: AsyncApplicationsResource) -> None: + self._applications = applications + + self.list = async_to_raw_response_wrapper( + applications.list, + ) + self.get = async_to_raw_response_wrapper( + applications.get, + ) + + +class ApplicationsResourceWithStreamingResponse: + def __init__(self, applications: ApplicationsResource) -> None: + self._applications = applications + + self.list = to_streamed_response_wrapper( + applications.list, + ) + self.get = to_streamed_response_wrapper( + applications.get, + ) + + +class AsyncApplicationsResourceWithStreamingResponse: + def __init__(self, applications: AsyncApplicationsResource) -> None: + self._applications = applications + + self.list = async_to_streamed_response_wrapper( + applications.list, + ) + self.get = async_to_streamed_response_wrapper( + applications.get, + ) diff --git a/src/cloudflare/resources/zero_trust/resource_library/categories.py b/src/cloudflare/resources/zero_trust/resource_library/categories.py new file mode 100644 index 00000000000..69101048506 --- /dev/null +++ b/src/cloudflare/resources/zero_trust/resource_library/categories.py @@ -0,0 +1,296 @@ +# 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 Body, Omit, Query, Headers, NotGiven, omit, not_given +from ...._utils import path_template, 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 SyncSinglePage, AsyncSinglePage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.zero_trust.resource_library import category_list_params +from ....types.zero_trust.resource_library.category_get_response import CategoryGetResponse +from ....types.zero_trust.resource_library.category_list_response import CategoryListResponse + +__all__ = ["CategoriesResource", "AsyncCategoriesResource"] + + +class CategoriesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> CategoriesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 CategoriesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> CategoriesResourceWithStreamingResponse: + """ + 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 CategoriesResourceWithStreamingResponse(self) + + def list( + self, + *, + account_id: str, + limit: int | Omit = omit, + offset: int | Omit = omit, + # 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, + ) -> SyncSinglePage[CategoryListResponse]: + """ + List application categories. + + Args: + limit: Limit of number of results to return. + + offset: Offset of results to return. + + 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( + path_template("/accounts/{account_id}/resource-library/categories", account_id=account_id), + page=SyncSinglePage[CategoryListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + category_list_params.CategoryListParams, + ), + ), + model=CategoryListResponse, + ) + + def get( + self, + id: str, + *, + 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[CategoryGetResponse]: + """ + Get application category by ID. + + 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}") + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._get( + path_template("/accounts/{account_id}/resource-library/categories/{id}", account_id=account_id, id=id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[Optional[CategoryGetResponse]]._unwrapper, + ), + cast_to=cast(Type[Optional[CategoryGetResponse]], ResultWrapper[CategoryGetResponse]), + ) + + +class AsyncCategoriesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncCategoriesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 AsyncCategoriesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncCategoriesResourceWithStreamingResponse: + """ + 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 AsyncCategoriesResourceWithStreamingResponse(self) + + def list( + self, + *, + account_id: str, + limit: int | Omit = omit, + offset: int | Omit = omit, + # 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[CategoryListResponse, AsyncSinglePage[CategoryListResponse]]: + """ + List application categories. + + Args: + limit: Limit of number of results to return. + + offset: Offset of results to return. + + 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( + path_template("/accounts/{account_id}/resource-library/categories", account_id=account_id), + page=AsyncSinglePage[CategoryListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + category_list_params.CategoryListParams, + ), + ), + model=CategoryListResponse, + ) + + async def get( + self, + id: str, + *, + 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[CategoryGetResponse]: + """ + Get application category by ID. + + 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}") + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._get( + path_template("/accounts/{account_id}/resource-library/categories/{id}", account_id=account_id, id=id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[Optional[CategoryGetResponse]]._unwrapper, + ), + cast_to=cast(Type[Optional[CategoryGetResponse]], ResultWrapper[CategoryGetResponse]), + ) + + +class CategoriesResourceWithRawResponse: + def __init__(self, categories: CategoriesResource) -> None: + self._categories = categories + + self.list = to_raw_response_wrapper( + categories.list, + ) + self.get = to_raw_response_wrapper( + categories.get, + ) + + +class AsyncCategoriesResourceWithRawResponse: + def __init__(self, categories: AsyncCategoriesResource) -> None: + self._categories = categories + + self.list = async_to_raw_response_wrapper( + categories.list, + ) + self.get = async_to_raw_response_wrapper( + categories.get, + ) + + +class CategoriesResourceWithStreamingResponse: + def __init__(self, categories: CategoriesResource) -> None: + self._categories = categories + + self.list = to_streamed_response_wrapper( + categories.list, + ) + self.get = to_streamed_response_wrapper( + categories.get, + ) + + +class AsyncCategoriesResourceWithStreamingResponse: + def __init__(self, categories: AsyncCategoriesResource) -> None: + self._categories = categories + + self.list = async_to_streamed_response_wrapper( + categories.list, + ) + self.get = async_to_streamed_response_wrapper( + categories.get, + ) diff --git a/src/cloudflare/resources/zero_trust/resource_library/resource_library.py b/src/cloudflare/resources/zero_trust/resource_library/resource_library.py new file mode 100644 index 00000000000..45085b0e456 --- /dev/null +++ b/src/cloudflare/resources/zero_trust/resource_library/resource_library.py @@ -0,0 +1,134 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from ...._compat import cached_property +from .categories import ( + CategoriesResource, + AsyncCategoriesResource, + CategoriesResourceWithRawResponse, + AsyncCategoriesResourceWithRawResponse, + CategoriesResourceWithStreamingResponse, + AsyncCategoriesResourceWithStreamingResponse, +) +from ...._resource import SyncAPIResource, AsyncAPIResource +from .applications import ( + ApplicationsResource, + AsyncApplicationsResource, + ApplicationsResourceWithRawResponse, + AsyncApplicationsResourceWithRawResponse, + ApplicationsResourceWithStreamingResponse, + AsyncApplicationsResourceWithStreamingResponse, +) + +__all__ = ["ResourceLibraryResource", "AsyncResourceLibraryResource"] + + +class ResourceLibraryResource(SyncAPIResource): + @cached_property + def applications(self) -> ApplicationsResource: + return ApplicationsResource(self._client) + + @cached_property + def categories(self) -> CategoriesResource: + return CategoriesResource(self._client) + + @cached_property + def with_raw_response(self) -> ResourceLibraryResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 ResourceLibraryResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ResourceLibraryResourceWithStreamingResponse: + """ + 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 ResourceLibraryResourceWithStreamingResponse(self) + + +class AsyncResourceLibraryResource(AsyncAPIResource): + @cached_property + def applications(self) -> AsyncApplicationsResource: + return AsyncApplicationsResource(self._client) + + @cached_property + def categories(self) -> AsyncCategoriesResource: + return AsyncCategoriesResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncResourceLibraryResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 AsyncResourceLibraryResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncResourceLibraryResourceWithStreamingResponse: + """ + 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 AsyncResourceLibraryResourceWithStreamingResponse(self) + + +class ResourceLibraryResourceWithRawResponse: + def __init__(self, resource_library: ResourceLibraryResource) -> None: + self._resource_library = resource_library + + @cached_property + def applications(self) -> ApplicationsResourceWithRawResponse: + return ApplicationsResourceWithRawResponse(self._resource_library.applications) + + @cached_property + def categories(self) -> CategoriesResourceWithRawResponse: + return CategoriesResourceWithRawResponse(self._resource_library.categories) + + +class AsyncResourceLibraryResourceWithRawResponse: + def __init__(self, resource_library: AsyncResourceLibraryResource) -> None: + self._resource_library = resource_library + + @cached_property + def applications(self) -> AsyncApplicationsResourceWithRawResponse: + return AsyncApplicationsResourceWithRawResponse(self._resource_library.applications) + + @cached_property + def categories(self) -> AsyncCategoriesResourceWithRawResponse: + return AsyncCategoriesResourceWithRawResponse(self._resource_library.categories) + + +class ResourceLibraryResourceWithStreamingResponse: + def __init__(self, resource_library: ResourceLibraryResource) -> None: + self._resource_library = resource_library + + @cached_property + def applications(self) -> ApplicationsResourceWithStreamingResponse: + return ApplicationsResourceWithStreamingResponse(self._resource_library.applications) + + @cached_property + def categories(self) -> CategoriesResourceWithStreamingResponse: + return CategoriesResourceWithStreamingResponse(self._resource_library.categories) + + +class AsyncResourceLibraryResourceWithStreamingResponse: + def __init__(self, resource_library: AsyncResourceLibraryResource) -> None: + self._resource_library = resource_library + + @cached_property + def applications(self) -> AsyncApplicationsResourceWithStreamingResponse: + return AsyncApplicationsResourceWithStreamingResponse(self._resource_library.applications) + + @cached_property + def categories(self) -> AsyncCategoriesResourceWithStreamingResponse: + return AsyncCategoriesResourceWithStreamingResponse(self._resource_library.categories) diff --git a/src/cloudflare/resources/zero_trust/zero_trust.py b/src/cloudflare/resources/zero_trust/zero_trust.py index a8de3d6cb8b..b144dc88569 100644 --- a/src/cloudflare/resources/zero_trust/zero_trust.py +++ b/src/cloudflare/resources/zero_trust/zero_trust.py @@ -92,6 +92,14 @@ OrganizationsResourceWithStreamingResponse, AsyncOrganizationsResourceWithStreamingResponse, ) +from .resource_library.resource_library import ( + ResourceLibraryResource, + AsyncResourceLibraryResource, + ResourceLibraryResourceWithRawResponse, + AsyncResourceLibraryResourceWithRawResponse, + ResourceLibraryResourceWithStreamingResponse, + AsyncResourceLibraryResourceWithStreamingResponse, +) from .identity_providers.identity_providers import ( IdentityProvidersResource, AsyncIdentityProvidersResource, @@ -153,6 +161,10 @@ def networks(self) -> NetworksResource: def risk_scoring(self) -> RiskScoringResource: return RiskScoringResource(self._client) + @cached_property + def resource_library(self) -> ResourceLibraryResource: + return ResourceLibraryResource(self._client) + @cached_property def with_raw_response(self) -> ZeroTrustResourceWithRawResponse: """ @@ -222,6 +234,10 @@ def networks(self) -> AsyncNetworksResource: def risk_scoring(self) -> AsyncRiskScoringResource: return AsyncRiskScoringResource(self._client) + @cached_property + def resource_library(self) -> AsyncResourceLibraryResource: + return AsyncResourceLibraryResource(self._client) + @cached_property def with_raw_response(self) -> AsyncZeroTrustResourceWithRawResponse: """ @@ -294,6 +310,10 @@ def networks(self) -> NetworksResourceWithRawResponse: def risk_scoring(self) -> RiskScoringResourceWithRawResponse: return RiskScoringResourceWithRawResponse(self._zero_trust.risk_scoring) + @cached_property + def resource_library(self) -> ResourceLibraryResourceWithRawResponse: + return ResourceLibraryResourceWithRawResponse(self._zero_trust.resource_library) + class AsyncZeroTrustResourceWithRawResponse: def __init__(self, zero_trust: AsyncZeroTrustResource) -> None: @@ -347,6 +367,10 @@ def networks(self) -> AsyncNetworksResourceWithRawResponse: def risk_scoring(self) -> AsyncRiskScoringResourceWithRawResponse: return AsyncRiskScoringResourceWithRawResponse(self._zero_trust.risk_scoring) + @cached_property + def resource_library(self) -> AsyncResourceLibraryResourceWithRawResponse: + return AsyncResourceLibraryResourceWithRawResponse(self._zero_trust.resource_library) + class ZeroTrustResourceWithStreamingResponse: def __init__(self, zero_trust: ZeroTrustResource) -> None: @@ -400,6 +424,10 @@ def networks(self) -> NetworksResourceWithStreamingResponse: def risk_scoring(self) -> RiskScoringResourceWithStreamingResponse: return RiskScoringResourceWithStreamingResponse(self._zero_trust.risk_scoring) + @cached_property + def resource_library(self) -> ResourceLibraryResourceWithStreamingResponse: + return ResourceLibraryResourceWithStreamingResponse(self._zero_trust.resource_library) + class AsyncZeroTrustResourceWithStreamingResponse: def __init__(self, zero_trust: AsyncZeroTrustResource) -> None: @@ -452,3 +480,7 @@ def networks(self) -> AsyncNetworksResourceWithStreamingResponse: @cached_property def risk_scoring(self) -> AsyncRiskScoringResourceWithStreamingResponse: return AsyncRiskScoringResourceWithStreamingResponse(self._zero_trust.risk_scoring) + + @cached_property + def resource_library(self) -> AsyncResourceLibraryResourceWithStreamingResponse: + return AsyncResourceLibraryResourceWithStreamingResponse(self._zero_trust.resource_library) diff --git a/src/cloudflare/types/zero_trust/resource_library/__init__.py b/src/cloudflare/types/zero_trust/resource_library/__init__.py new file mode 100644 index 00000000000..a7887df737c --- /dev/null +++ b/src/cloudflare/types/zero_trust/resource_library/__init__.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .category_list_params import CategoryListParams as CategoryListParams +from .category_get_response import CategoryGetResponse as CategoryGetResponse +from .category_list_response import CategoryListResponse as CategoryListResponse +from .application_list_params import ApplicationListParams as ApplicationListParams +from .application_get_response import ApplicationGetResponse as ApplicationGetResponse +from .application_list_response import ApplicationListResponse as ApplicationListResponse diff --git a/src/cloudflare/types/zero_trust/resource_library/application_get_response.py b/src/cloudflare/types/zero_trust/resource_library/application_get_response.py new file mode 100644 index 00000000000..9ea9afcb16f --- /dev/null +++ b/src/cloudflare/types/zero_trust/resource_library/application_get_response.py @@ -0,0 +1,60 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ...._models import BaseModel + +__all__ = ["ApplicationGetResponse"] + + +class ApplicationGetResponse(BaseModel): + id: str + """Returns the application ID.""" + + application_confidence_score: float + """Confidence score for the application. Returns -1 when no score is available.""" + + application_source: str + """Returns the application source.""" + + application_type: str + """Returns the application type.""" + + application_type_description: str + """Returns the application type description.""" + + created_at: str + """Returns the application creation time.""" + + gen_ai_score: float + """GenAI score for the application. Returns -1 when no score is available.""" + + hostnames: List[str] + """Returns the list of hostnames for the application.""" + + human_id: str + """Returns the human readable ID.""" + + ip_subnets: List[str] + """Returns the list of IP subnets for the application.""" + + name: str + """Returns the application name.""" + + port_protocols: List[str] + """Returns the list of port protocols for the application.""" + + support_domains: List[str] + """Returns the list of support domains for the application.""" + + updated_at: str + """Returns the application update time.""" + + version: str + """Returns the application version.""" + + application_score_composition: Optional[object] = None + """Returns the score composition breakdown for the application.""" + + intel_id: Optional[int] = None + """Returns the Intel API ID for the application.""" diff --git a/src/cloudflare/types/zero_trust/resource_library/application_list_params.py b/src/cloudflare/types/zero_trust/resource_library/application_list_params.py new file mode 100644 index 00000000000..1bb20e369d0 --- /dev/null +++ b/src/cloudflare/types/zero_trust/resource_library/application_list_params.py @@ -0,0 +1,35 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["ApplicationListParams"] + + +class ApplicationListParams(TypedDict, total=False): + account_id: Required[str] + + filter: str + """Filter applications using key:value format. Supported filter keys: + + - name: Filter by application name (e.g., name:HR) + - id: Filter by application ID (e.g., id:0b63249c-95bf-4cc0-a7cc-d7faaaf1dac0) + - human_id: Filter by human-readable ID (e.g., human_id:HR) + - hostname: Filter by hostname or support domain (e.g., + hostname:portal.example.com) + - source: Filter by application source name (e.g., source:cloudflare) + - ip_subnet: Filter by IP subnet using CIDR containment — returns applications + where any stored subnet contains the search value (e.g., ip_subnet:10.0.1.5/32 + matches apps with 10.0.0.0/16) + - intel_id: Filter by Intel API ID (e.g., intel_id:498). . + """ + + limit: int + """Limit of number of results to return (max 250).""" + + offset: int + """Offset of results to return.""" + + order_by: str + """Order by result by field name and order (e.g., name:asc).""" diff --git a/src/cloudflare/types/zero_trust/resource_library/application_list_response.py b/src/cloudflare/types/zero_trust/resource_library/application_list_response.py new file mode 100644 index 00000000000..1edc959cc18 --- /dev/null +++ b/src/cloudflare/types/zero_trust/resource_library/application_list_response.py @@ -0,0 +1,60 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ...._models import BaseModel + +__all__ = ["ApplicationListResponse"] + + +class ApplicationListResponse(BaseModel): + id: str + """Returns the application ID.""" + + application_confidence_score: float + """Confidence score for the application. Returns -1 when no score is available.""" + + application_source: str + """Returns the application source.""" + + application_type: str + """Returns the application type.""" + + application_type_description: str + """Returns the application type description.""" + + created_at: str + """Returns the application creation time.""" + + gen_ai_score: float + """GenAI score for the application. Returns -1 when no score is available.""" + + hostnames: List[str] + """Returns the list of hostnames for the application.""" + + human_id: str + """Returns the human readable ID.""" + + ip_subnets: List[str] + """Returns the list of IP subnets for the application.""" + + name: str + """Returns the application name.""" + + port_protocols: List[str] + """Returns the list of port protocols for the application.""" + + support_domains: List[str] + """Returns the list of support domains for the application.""" + + updated_at: str + """Returns the application update time.""" + + version: str + """Returns the application version.""" + + application_score_composition: Optional[object] = None + """Returns the score composition breakdown for the application.""" + + intel_id: Optional[int] = None + """Returns the Intel API ID for the application.""" diff --git a/src/cloudflare/types/zero_trust/resource_library/category_get_response.py b/src/cloudflare/types/zero_trust/resource_library/category_get_response.py new file mode 100644 index 00000000000..ee8be02c33e --- /dev/null +++ b/src/cloudflare/types/zero_trust/resource_library/category_get_response.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ...._models import BaseModel + +__all__ = ["CategoryGetResponse"] + + +class CategoryGetResponse(BaseModel): + id: str + """Returns the category ID.""" + + created_at: str + """Returns the category creation time.""" + + description: str + """Returns the category description.""" + + name: str + """Returns the category name.""" diff --git a/src/cloudflare/types/zero_trust/resource_library/category_list_params.py b/src/cloudflare/types/zero_trust/resource_library/category_list_params.py new file mode 100644 index 00000000000..5d80d7606f3 --- /dev/null +++ b/src/cloudflare/types/zero_trust/resource_library/category_list_params.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["CategoryListParams"] + + +class CategoryListParams(TypedDict, total=False): + account_id: Required[str] + + limit: int + """Limit of number of results to return.""" + + offset: int + """Offset of results to return.""" diff --git a/src/cloudflare/types/zero_trust/resource_library/category_list_response.py b/src/cloudflare/types/zero_trust/resource_library/category_list_response.py new file mode 100644 index 00000000000..38b891339bf --- /dev/null +++ b/src/cloudflare/types/zero_trust/resource_library/category_list_response.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ...._models import BaseModel + +__all__ = ["CategoryListResponse"] + + +class CategoryListResponse(BaseModel): + id: str + """Returns the category ID.""" + + created_at: str + """Returns the category creation time.""" + + description: str + """Returns the category description.""" + + name: str + """Returns the category name.""" diff --git a/tests/api_resources/zero_trust/resource_library/__init__.py b/tests/api_resources/zero_trust/resource_library/__init__.py new file mode 100644 index 00000000000..fd8019a9a1a --- /dev/null +++ b/tests/api_resources/zero_trust/resource_library/__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/resource_library/test_applications.py b/tests/api_resources/zero_trust/resource_library/test_applications.py new file mode 100644 index 00000000000..1ef91b84596 --- /dev/null +++ b/tests/api_resources/zero_trust/resource_library/test_applications.py @@ -0,0 +1,222 @@ +# 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.pagination import SyncSinglePage, AsyncSinglePage +from cloudflare.types.zero_trust.resource_library import ( + ApplicationGetResponse, + ApplicationListResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestApplications: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Cloudflare) -> None: + application = client.zero_trust.resource_library.applications.list( + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + assert_matches_type(SyncSinglePage[ApplicationListResponse], application, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Cloudflare) -> None: + application = client.zero_trust.resource_library.applications.list( + account_id="023e105f4ecef8ad9ca31a8372d0c353", + filter="filter", + limit=0, + offset=0, + order_by="order_by", + ) + assert_matches_type(SyncSinglePage[ApplicationListResponse], application, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Cloudflare) -> None: + response = client.zero_trust.resource_library.applications.with_raw_response.list( + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + application = response.parse() + assert_matches_type(SyncSinglePage[ApplicationListResponse], application, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Cloudflare) -> None: + with client.zero_trust.resource_library.applications.with_streaming_response.list( + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + application = response.parse() + assert_matches_type(SyncSinglePage[ApplicationListResponse], application, 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.resource_library.applications.with_raw_response.list( + account_id="", + ) + + @parametrize + def test_method_get(self, client: Cloudflare) -> None: + application = client.zero_trust.resource_library.applications.get( + id="0b63249c-95bf-4cc0-a7cc-d7faaaf1dac0", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + assert_matches_type(Optional[ApplicationGetResponse], application, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Cloudflare) -> None: + response = client.zero_trust.resource_library.applications.with_raw_response.get( + id="0b63249c-95bf-4cc0-a7cc-d7faaaf1dac0", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + application = response.parse() + assert_matches_type(Optional[ApplicationGetResponse], application, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Cloudflare) -> None: + with client.zero_trust.resource_library.applications.with_streaming_response.get( + id="0b63249c-95bf-4cc0-a7cc-d7faaaf1dac0", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + application = response.parse() + assert_matches_type(Optional[ApplicationGetResponse], application, 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.resource_library.applications.with_raw_response.get( + id="0b63249c-95bf-4cc0-a7cc-d7faaaf1dac0", + account_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.zero_trust.resource_library.applications.with_raw_response.get( + id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + +class TestAsyncApplications: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncCloudflare) -> None: + application = await async_client.zero_trust.resource_library.applications.list( + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + assert_matches_type(AsyncSinglePage[ApplicationListResponse], application, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncCloudflare) -> None: + application = await async_client.zero_trust.resource_library.applications.list( + account_id="023e105f4ecef8ad9ca31a8372d0c353", + filter="filter", + limit=0, + offset=0, + order_by="order_by", + ) + assert_matches_type(AsyncSinglePage[ApplicationListResponse], application, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncCloudflare) -> None: + response = await async_client.zero_trust.resource_library.applications.with_raw_response.list( + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + application = await response.parse() + assert_matches_type(AsyncSinglePage[ApplicationListResponse], application, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncCloudflare) -> None: + async with async_client.zero_trust.resource_library.applications.with_streaming_response.list( + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + application = await response.parse() + assert_matches_type(AsyncSinglePage[ApplicationListResponse], application, 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.resource_library.applications.with_raw_response.list( + account_id="", + ) + + @parametrize + async def test_method_get(self, async_client: AsyncCloudflare) -> None: + application = await async_client.zero_trust.resource_library.applications.get( + id="0b63249c-95bf-4cc0-a7cc-d7faaaf1dac0", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + assert_matches_type(Optional[ApplicationGetResponse], application, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncCloudflare) -> None: + response = await async_client.zero_trust.resource_library.applications.with_raw_response.get( + id="0b63249c-95bf-4cc0-a7cc-d7faaaf1dac0", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + application = await response.parse() + assert_matches_type(Optional[ApplicationGetResponse], application, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncCloudflare) -> None: + async with async_client.zero_trust.resource_library.applications.with_streaming_response.get( + id="0b63249c-95bf-4cc0-a7cc-d7faaaf1dac0", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + application = await response.parse() + assert_matches_type(Optional[ApplicationGetResponse], application, 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.resource_library.applications.with_raw_response.get( + id="0b63249c-95bf-4cc0-a7cc-d7faaaf1dac0", + account_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.zero_trust.resource_library.applications.with_raw_response.get( + id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) diff --git a/tests/api_resources/zero_trust/resource_library/test_categories.py b/tests/api_resources/zero_trust/resource_library/test_categories.py new file mode 100644 index 00000000000..5d084bd3e21 --- /dev/null +++ b/tests/api_resources/zero_trust/resource_library/test_categories.py @@ -0,0 +1,215 @@ +# 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.pagination import SyncSinglePage, AsyncSinglePage +from cloudflare.types.zero_trust.resource_library import CategoryGetResponse, CategoryListResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestCategories: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Cloudflare) -> None: + category = client.zero_trust.resource_library.categories.list( + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + assert_matches_type(SyncSinglePage[CategoryListResponse], category, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Cloudflare) -> None: + category = client.zero_trust.resource_library.categories.list( + account_id="023e105f4ecef8ad9ca31a8372d0c353", + limit=0, + offset=0, + ) + assert_matches_type(SyncSinglePage[CategoryListResponse], category, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Cloudflare) -> None: + response = client.zero_trust.resource_library.categories.with_raw_response.list( + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + category = response.parse() + assert_matches_type(SyncSinglePage[CategoryListResponse], category, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Cloudflare) -> None: + with client.zero_trust.resource_library.categories.with_streaming_response.list( + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + category = response.parse() + assert_matches_type(SyncSinglePage[CategoryListResponse], category, 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.resource_library.categories.with_raw_response.list( + account_id="", + ) + + @parametrize + def test_method_get(self, client: Cloudflare) -> None: + category = client.zero_trust.resource_library.categories.get( + id="0b63249c-95bf-4cc0-a7cc-d7faaaf1dac0", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + assert_matches_type(Optional[CategoryGetResponse], category, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Cloudflare) -> None: + response = client.zero_trust.resource_library.categories.with_raw_response.get( + id="0b63249c-95bf-4cc0-a7cc-d7faaaf1dac0", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + category = response.parse() + assert_matches_type(Optional[CategoryGetResponse], category, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Cloudflare) -> None: + with client.zero_trust.resource_library.categories.with_streaming_response.get( + id="0b63249c-95bf-4cc0-a7cc-d7faaaf1dac0", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + category = response.parse() + assert_matches_type(Optional[CategoryGetResponse], category, 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.resource_library.categories.with_raw_response.get( + id="0b63249c-95bf-4cc0-a7cc-d7faaaf1dac0", + account_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.zero_trust.resource_library.categories.with_raw_response.get( + id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + +class TestAsyncCategories: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncCloudflare) -> None: + category = await async_client.zero_trust.resource_library.categories.list( + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + assert_matches_type(AsyncSinglePage[CategoryListResponse], category, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncCloudflare) -> None: + category = await async_client.zero_trust.resource_library.categories.list( + account_id="023e105f4ecef8ad9ca31a8372d0c353", + limit=0, + offset=0, + ) + assert_matches_type(AsyncSinglePage[CategoryListResponse], category, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncCloudflare) -> None: + response = await async_client.zero_trust.resource_library.categories.with_raw_response.list( + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + category = await response.parse() + assert_matches_type(AsyncSinglePage[CategoryListResponse], category, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncCloudflare) -> None: + async with async_client.zero_trust.resource_library.categories.with_streaming_response.list( + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + category = await response.parse() + assert_matches_type(AsyncSinglePage[CategoryListResponse], category, 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.resource_library.categories.with_raw_response.list( + account_id="", + ) + + @parametrize + async def test_method_get(self, async_client: AsyncCloudflare) -> None: + category = await async_client.zero_trust.resource_library.categories.get( + id="0b63249c-95bf-4cc0-a7cc-d7faaaf1dac0", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + assert_matches_type(Optional[CategoryGetResponse], category, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncCloudflare) -> None: + response = await async_client.zero_trust.resource_library.categories.with_raw_response.get( + id="0b63249c-95bf-4cc0-a7cc-d7faaaf1dac0", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + category = await response.parse() + assert_matches_type(Optional[CategoryGetResponse], category, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncCloudflare) -> None: + async with async_client.zero_trust.resource_library.categories.with_streaming_response.get( + id="0b63249c-95bf-4cc0-a7cc-d7faaaf1dac0", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + category = await response.parse() + assert_matches_type(Optional[CategoryGetResponse], category, 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.resource_library.categories.with_raw_response.get( + id="0b63249c-95bf-4cc0-a7cc-d7faaaf1dac0", + account_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.zero_trust.resource_library.categories.with_raw_response.get( + id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) From d2a5686244e2bf2ab3f0310e45bde109eab923ea Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 5 May 2026 14:30:34 +0000 Subject: [PATCH 35/45] chore(api): update composite API spec --- .stats.yml | 2 +- .../types/aisearch/instance_create_params.py | 13 ++++-- .../aisearch/instance_create_response.py | 13 ++++-- .../aisearch/instance_delete_response.py | 13 ++++-- .../types/aisearch/instance_list_response.py | 13 ++++-- .../types/aisearch/instance_read_response.py | 13 ++++-- .../types/aisearch/instance_update_params.py | 13 ++++-- .../aisearch/instance_update_response.py | 13 ++++-- .../namespaces/instance_create_params.py | 13 ++++-- .../namespaces/instance_create_response.py | 13 ++++-- .../namespaces/instance_delete_response.py | 13 ++++-- .../namespaces/instance_list_response.py | 13 ++++-- .../namespaces/instance_read_response.py | 13 ++++-- .../namespaces/instance_update_params.py | 13 ++++-- .../namespaces/instance_update_response.py | 13 ++++-- .../aisearch/namespaces/test_instances.py | 40 +++++++++++++------ .../api_resources/aisearch/test_instances.py | 40 +++++++++++++------ 17 files changed, 197 insertions(+), 67 deletions(-) diff --git a/.stats.yml b/.stats.yml index df149afa657..a8050a9279b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 2208 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a6c352830d1270d0abb5bb983058ea21815e1bb7d2e163965335dcb0e706f057.yml -openapi_spec_hash: e722ad1f58e3dfb3a928cf9890d48da4 +openapi_spec_hash: 42dd4ac0ac3f5c00bbe80e26fed2fa51 config_hash: 20574d7a53e0349a3337a121a46638d4 diff --git a/src/cloudflare/types/aisearch/instance_create_params.py b/src/cloudflare/types/aisearch/instance_create_params.py index 66b6ae9f39b..bd94ee3086c 100644 --- a/src/cloudflare/types/aisearch/instance_create_params.py +++ b/src/cloudflare/types/aisearch/instance_create_params.py @@ -325,8 +325,9 @@ class SourceParamsWebCrawlerParseOptionsContentSelector(TypedDict, total=False): selector: Required[str] """CSS selector to extract content from pages matching the path pattern. - Supports standard CSS selectors including class, ID, element, and attribute - selectors. + Must not contain disallowed characters (;, `, $, {, }, \\)). Must target a single + element; if multiple elements match, the selector is ignored and the full page + is used. """ @@ -335,10 +336,16 @@ class SourceParamsWebCrawlerParseOptions(TypedDict, total=False): """ List of path-to-selector mappings for extracting specific content from crawled pages. Each entry pairs a URL glob pattern with a CSS selector. The first - matching path wins. Only the matched HTML fragment is stored and indexed. + matching path wins. Only the matched HTML fragment is stored and indexed. Omit + the field to disable content selection — empty arrays are rejected. """ include_headers: Dict[str, str] + """Up to 5 custom HTTP headers sent with each crawl request. + + Names must be RFC-7230 token characters (no spaces, colons, or control + characters); values must be HTAB + printable ASCII (no CR/LF). + """ include_images: bool diff --git a/src/cloudflare/types/aisearch/instance_create_response.py b/src/cloudflare/types/aisearch/instance_create_response.py index 29f8aa3e5a1..46e1dbe5507 100644 --- a/src/cloudflare/types/aisearch/instance_create_response.py +++ b/src/cloudflare/types/aisearch/instance_create_response.py @@ -166,8 +166,9 @@ class SourceParamsWebCrawlerParseOptionsContentSelector(BaseModel): selector: str """CSS selector to extract content from pages matching the path pattern. - Supports standard CSS selectors including class, ID, element, and attribute - selectors. + Must not contain disallowed characters (;, `, $, {, }, \\)). Must target a single + element; if multiple elements match, the selector is ignored and the full page + is used. """ @@ -176,10 +177,16 @@ class SourceParamsWebCrawlerParseOptions(BaseModel): """ List of path-to-selector mappings for extracting specific content from crawled pages. Each entry pairs a URL glob pattern with a CSS selector. The first - matching path wins. Only the matched HTML fragment is stored and indexed. + matching path wins. Only the matched HTML fragment is stored and indexed. Omit + the field to disable content selection — empty arrays are rejected. """ include_headers: Optional[Dict[str, str]] = None + """Up to 5 custom HTTP headers sent with each crawl request. + + Names must be RFC-7230 token characters (no spaces, colons, or control + characters); values must be HTAB + printable ASCII (no CR/LF). + """ include_images: Optional[bool] = None diff --git a/src/cloudflare/types/aisearch/instance_delete_response.py b/src/cloudflare/types/aisearch/instance_delete_response.py index 63b7cc489f8..5fa4b6aec7b 100644 --- a/src/cloudflare/types/aisearch/instance_delete_response.py +++ b/src/cloudflare/types/aisearch/instance_delete_response.py @@ -166,8 +166,9 @@ class SourceParamsWebCrawlerParseOptionsContentSelector(BaseModel): selector: str """CSS selector to extract content from pages matching the path pattern. - Supports standard CSS selectors including class, ID, element, and attribute - selectors. + Must not contain disallowed characters (;, `, $, {, }, \\)). Must target a single + element; if multiple elements match, the selector is ignored and the full page + is used. """ @@ -176,10 +177,16 @@ class SourceParamsWebCrawlerParseOptions(BaseModel): """ List of path-to-selector mappings for extracting specific content from crawled pages. Each entry pairs a URL glob pattern with a CSS selector. The first - matching path wins. Only the matched HTML fragment is stored and indexed. + matching path wins. Only the matched HTML fragment is stored and indexed. Omit + the field to disable content selection — empty arrays are rejected. """ include_headers: Optional[Dict[str, str]] = None + """Up to 5 custom HTTP headers sent with each crawl request. + + Names must be RFC-7230 token characters (no spaces, colons, or control + characters); values must be HTAB + printable ASCII (no CR/LF). + """ include_images: Optional[bool] = None diff --git a/src/cloudflare/types/aisearch/instance_list_response.py b/src/cloudflare/types/aisearch/instance_list_response.py index 725f969e08d..672411cfd4a 100644 --- a/src/cloudflare/types/aisearch/instance_list_response.py +++ b/src/cloudflare/types/aisearch/instance_list_response.py @@ -166,8 +166,9 @@ class SourceParamsWebCrawlerParseOptionsContentSelector(BaseModel): selector: str """CSS selector to extract content from pages matching the path pattern. - Supports standard CSS selectors including class, ID, element, and attribute - selectors. + Must not contain disallowed characters (;, `, $, {, }, \\)). Must target a single + element; if multiple elements match, the selector is ignored and the full page + is used. """ @@ -176,10 +177,16 @@ class SourceParamsWebCrawlerParseOptions(BaseModel): """ List of path-to-selector mappings for extracting specific content from crawled pages. Each entry pairs a URL glob pattern with a CSS selector. The first - matching path wins. Only the matched HTML fragment is stored and indexed. + matching path wins. Only the matched HTML fragment is stored and indexed. Omit + the field to disable content selection — empty arrays are rejected. """ include_headers: Optional[Dict[str, str]] = None + """Up to 5 custom HTTP headers sent with each crawl request. + + Names must be RFC-7230 token characters (no spaces, colons, or control + characters); values must be HTAB + printable ASCII (no CR/LF). + """ include_images: Optional[bool] = None diff --git a/src/cloudflare/types/aisearch/instance_read_response.py b/src/cloudflare/types/aisearch/instance_read_response.py index dc0a8c18c72..fe5412fa35d 100644 --- a/src/cloudflare/types/aisearch/instance_read_response.py +++ b/src/cloudflare/types/aisearch/instance_read_response.py @@ -166,8 +166,9 @@ class SourceParamsWebCrawlerParseOptionsContentSelector(BaseModel): selector: str """CSS selector to extract content from pages matching the path pattern. - Supports standard CSS selectors including class, ID, element, and attribute - selectors. + Must not contain disallowed characters (;, `, $, {, }, \\)). Must target a single + element; if multiple elements match, the selector is ignored and the full page + is used. """ @@ -176,10 +177,16 @@ class SourceParamsWebCrawlerParseOptions(BaseModel): """ List of path-to-selector mappings for extracting specific content from crawled pages. Each entry pairs a URL glob pattern with a CSS selector. The first - matching path wins. Only the matched HTML fragment is stored and indexed. + matching path wins. Only the matched HTML fragment is stored and indexed. Omit + the field to disable content selection — empty arrays are rejected. """ include_headers: Optional[Dict[str, str]] = None + """Up to 5 custom HTTP headers sent with each crawl request. + + Names must be RFC-7230 token characters (no spaces, colons, or control + characters); values must be HTAB + printable ASCII (no CR/LF). + """ include_images: Optional[bool] = None diff --git a/src/cloudflare/types/aisearch/instance_update_params.py b/src/cloudflare/types/aisearch/instance_update_params.py index fddda6864f0..bcbf19cb3bb 100644 --- a/src/cloudflare/types/aisearch/instance_update_params.py +++ b/src/cloudflare/types/aisearch/instance_update_params.py @@ -360,8 +360,9 @@ class SourceParamsWebCrawlerParseOptionsContentSelector(TypedDict, total=False): selector: Required[str] """CSS selector to extract content from pages matching the path pattern. - Supports standard CSS selectors including class, ID, element, and attribute - selectors. + Must not contain disallowed characters (;, `, $, {, }, \\)). Must target a single + element; if multiple elements match, the selector is ignored and the full page + is used. """ @@ -370,10 +371,16 @@ class SourceParamsWebCrawlerParseOptions(TypedDict, total=False): """ List of path-to-selector mappings for extracting specific content from crawled pages. Each entry pairs a URL glob pattern with a CSS selector. The first - matching path wins. Only the matched HTML fragment is stored and indexed. + matching path wins. Only the matched HTML fragment is stored and indexed. Omit + the field to disable content selection — empty arrays are rejected. """ include_headers: Dict[str, str] + """Up to 5 custom HTTP headers sent with each crawl request. + + Names must be RFC-7230 token characters (no spaces, colons, or control + characters); values must be HTAB + printable ASCII (no CR/LF). + """ include_images: bool diff --git a/src/cloudflare/types/aisearch/instance_update_response.py b/src/cloudflare/types/aisearch/instance_update_response.py index 379e9d7b207..31a820e5e8e 100644 --- a/src/cloudflare/types/aisearch/instance_update_response.py +++ b/src/cloudflare/types/aisearch/instance_update_response.py @@ -166,8 +166,9 @@ class SourceParamsWebCrawlerParseOptionsContentSelector(BaseModel): selector: str """CSS selector to extract content from pages matching the path pattern. - Supports standard CSS selectors including class, ID, element, and attribute - selectors. + Must not contain disallowed characters (;, `, $, {, }, \\)). Must target a single + element; if multiple elements match, the selector is ignored and the full page + is used. """ @@ -176,10 +177,16 @@ class SourceParamsWebCrawlerParseOptions(BaseModel): """ List of path-to-selector mappings for extracting specific content from crawled pages. Each entry pairs a URL glob pattern with a CSS selector. The first - matching path wins. Only the matched HTML fragment is stored and indexed. + matching path wins. Only the matched HTML fragment is stored and indexed. Omit + the field to disable content selection — empty arrays are rejected. """ include_headers: Optional[Dict[str, str]] = None + """Up to 5 custom HTTP headers sent with each crawl request. + + Names must be RFC-7230 token characters (no spaces, colons, or control + characters); values must be HTAB + printable ASCII (no CR/LF). + """ include_images: Optional[bool] = None diff --git a/src/cloudflare/types/aisearch/namespaces/instance_create_params.py b/src/cloudflare/types/aisearch/namespaces/instance_create_params.py index 10493f5da1a..81c6ac6303e 100644 --- a/src/cloudflare/types/aisearch/namespaces/instance_create_params.py +++ b/src/cloudflare/types/aisearch/namespaces/instance_create_params.py @@ -325,8 +325,9 @@ class SourceParamsWebCrawlerParseOptionsContentSelector(TypedDict, total=False): selector: Required[str] """CSS selector to extract content from pages matching the path pattern. - Supports standard CSS selectors including class, ID, element, and attribute - selectors. + Must not contain disallowed characters (;, `, $, {, }, \\)). Must target a single + element; if multiple elements match, the selector is ignored and the full page + is used. """ @@ -335,10 +336,16 @@ class SourceParamsWebCrawlerParseOptions(TypedDict, total=False): """ List of path-to-selector mappings for extracting specific content from crawled pages. Each entry pairs a URL glob pattern with a CSS selector. The first - matching path wins. Only the matched HTML fragment is stored and indexed. + matching path wins. Only the matched HTML fragment is stored and indexed. Omit + the field to disable content selection — empty arrays are rejected. """ include_headers: Dict[str, str] + """Up to 5 custom HTTP headers sent with each crawl request. + + Names must be RFC-7230 token characters (no spaces, colons, or control + characters); values must be HTAB + printable ASCII (no CR/LF). + """ include_images: bool diff --git a/src/cloudflare/types/aisearch/namespaces/instance_create_response.py b/src/cloudflare/types/aisearch/namespaces/instance_create_response.py index 3e320dec61a..b25271799ea 100644 --- a/src/cloudflare/types/aisearch/namespaces/instance_create_response.py +++ b/src/cloudflare/types/aisearch/namespaces/instance_create_response.py @@ -166,8 +166,9 @@ class SourceParamsWebCrawlerParseOptionsContentSelector(BaseModel): selector: str """CSS selector to extract content from pages matching the path pattern. - Supports standard CSS selectors including class, ID, element, and attribute - selectors. + Must not contain disallowed characters (;, `, $, {, }, \\)). Must target a single + element; if multiple elements match, the selector is ignored and the full page + is used. """ @@ -176,10 +177,16 @@ class SourceParamsWebCrawlerParseOptions(BaseModel): """ List of path-to-selector mappings for extracting specific content from crawled pages. Each entry pairs a URL glob pattern with a CSS selector. The first - matching path wins. Only the matched HTML fragment is stored and indexed. + matching path wins. Only the matched HTML fragment is stored and indexed. Omit + the field to disable content selection — empty arrays are rejected. """ include_headers: Optional[Dict[str, str]] = None + """Up to 5 custom HTTP headers sent with each crawl request. + + Names must be RFC-7230 token characters (no spaces, colons, or control + characters); values must be HTAB + printable ASCII (no CR/LF). + """ include_images: Optional[bool] = None diff --git a/src/cloudflare/types/aisearch/namespaces/instance_delete_response.py b/src/cloudflare/types/aisearch/namespaces/instance_delete_response.py index 6caf390c7f4..31331886982 100644 --- a/src/cloudflare/types/aisearch/namespaces/instance_delete_response.py +++ b/src/cloudflare/types/aisearch/namespaces/instance_delete_response.py @@ -166,8 +166,9 @@ class SourceParamsWebCrawlerParseOptionsContentSelector(BaseModel): selector: str """CSS selector to extract content from pages matching the path pattern. - Supports standard CSS selectors including class, ID, element, and attribute - selectors. + Must not contain disallowed characters (;, `, $, {, }, \\)). Must target a single + element; if multiple elements match, the selector is ignored and the full page + is used. """ @@ -176,10 +177,16 @@ class SourceParamsWebCrawlerParseOptions(BaseModel): """ List of path-to-selector mappings for extracting specific content from crawled pages. Each entry pairs a URL glob pattern with a CSS selector. The first - matching path wins. Only the matched HTML fragment is stored and indexed. + matching path wins. Only the matched HTML fragment is stored and indexed. Omit + the field to disable content selection — empty arrays are rejected. """ include_headers: Optional[Dict[str, str]] = None + """Up to 5 custom HTTP headers sent with each crawl request. + + Names must be RFC-7230 token characters (no spaces, colons, or control + characters); values must be HTAB + printable ASCII (no CR/LF). + """ include_images: Optional[bool] = None diff --git a/src/cloudflare/types/aisearch/namespaces/instance_list_response.py b/src/cloudflare/types/aisearch/namespaces/instance_list_response.py index 70f2d02faf3..568d389a7ec 100644 --- a/src/cloudflare/types/aisearch/namespaces/instance_list_response.py +++ b/src/cloudflare/types/aisearch/namespaces/instance_list_response.py @@ -166,8 +166,9 @@ class SourceParamsWebCrawlerParseOptionsContentSelector(BaseModel): selector: str """CSS selector to extract content from pages matching the path pattern. - Supports standard CSS selectors including class, ID, element, and attribute - selectors. + Must not contain disallowed characters (;, `, $, {, }, \\)). Must target a single + element; if multiple elements match, the selector is ignored and the full page + is used. """ @@ -176,10 +177,16 @@ class SourceParamsWebCrawlerParseOptions(BaseModel): """ List of path-to-selector mappings for extracting specific content from crawled pages. Each entry pairs a URL glob pattern with a CSS selector. The first - matching path wins. Only the matched HTML fragment is stored and indexed. + matching path wins. Only the matched HTML fragment is stored and indexed. Omit + the field to disable content selection — empty arrays are rejected. """ include_headers: Optional[Dict[str, str]] = None + """Up to 5 custom HTTP headers sent with each crawl request. + + Names must be RFC-7230 token characters (no spaces, colons, or control + characters); values must be HTAB + printable ASCII (no CR/LF). + """ include_images: Optional[bool] = None diff --git a/src/cloudflare/types/aisearch/namespaces/instance_read_response.py b/src/cloudflare/types/aisearch/namespaces/instance_read_response.py index 1c2e469c282..1f0f6568691 100644 --- a/src/cloudflare/types/aisearch/namespaces/instance_read_response.py +++ b/src/cloudflare/types/aisearch/namespaces/instance_read_response.py @@ -166,8 +166,9 @@ class SourceParamsWebCrawlerParseOptionsContentSelector(BaseModel): selector: str """CSS selector to extract content from pages matching the path pattern. - Supports standard CSS selectors including class, ID, element, and attribute - selectors. + Must not contain disallowed characters (;, `, $, {, }, \\)). Must target a single + element; if multiple elements match, the selector is ignored and the full page + is used. """ @@ -176,10 +177,16 @@ class SourceParamsWebCrawlerParseOptions(BaseModel): """ List of path-to-selector mappings for extracting specific content from crawled pages. Each entry pairs a URL glob pattern with a CSS selector. The first - matching path wins. Only the matched HTML fragment is stored and indexed. + matching path wins. Only the matched HTML fragment is stored and indexed. Omit + the field to disable content selection — empty arrays are rejected. """ include_headers: Optional[Dict[str, str]] = None + """Up to 5 custom HTTP headers sent with each crawl request. + + Names must be RFC-7230 token characters (no spaces, colons, or control + characters); values must be HTAB + printable ASCII (no CR/LF). + """ include_images: Optional[bool] = None diff --git a/src/cloudflare/types/aisearch/namespaces/instance_update_params.py b/src/cloudflare/types/aisearch/namespaces/instance_update_params.py index 057cd3d1241..b23aae86afd 100644 --- a/src/cloudflare/types/aisearch/namespaces/instance_update_params.py +++ b/src/cloudflare/types/aisearch/namespaces/instance_update_params.py @@ -362,8 +362,9 @@ class SourceParamsWebCrawlerParseOptionsContentSelector(TypedDict, total=False): selector: Required[str] """CSS selector to extract content from pages matching the path pattern. - Supports standard CSS selectors including class, ID, element, and attribute - selectors. + Must not contain disallowed characters (;, `, $, {, }, \\)). Must target a single + element; if multiple elements match, the selector is ignored and the full page + is used. """ @@ -372,10 +373,16 @@ class SourceParamsWebCrawlerParseOptions(TypedDict, total=False): """ List of path-to-selector mappings for extracting specific content from crawled pages. Each entry pairs a URL glob pattern with a CSS selector. The first - matching path wins. Only the matched HTML fragment is stored and indexed. + matching path wins. Only the matched HTML fragment is stored and indexed. Omit + the field to disable content selection — empty arrays are rejected. """ include_headers: Dict[str, str] + """Up to 5 custom HTTP headers sent with each crawl request. + + Names must be RFC-7230 token characters (no spaces, colons, or control + characters); values must be HTAB + printable ASCII (no CR/LF). + """ include_images: bool diff --git a/src/cloudflare/types/aisearch/namespaces/instance_update_response.py b/src/cloudflare/types/aisearch/namespaces/instance_update_response.py index 7de705537a7..ca593a5cf2a 100644 --- a/src/cloudflare/types/aisearch/namespaces/instance_update_response.py +++ b/src/cloudflare/types/aisearch/namespaces/instance_update_response.py @@ -166,8 +166,9 @@ class SourceParamsWebCrawlerParseOptionsContentSelector(BaseModel): selector: str """CSS selector to extract content from pages matching the path pattern. - Supports standard CSS selectors including class, ID, element, and attribute - selectors. + Must not contain disallowed characters (;, `, $, {, }, \\)). Must target a single + element; if multiple elements match, the selector is ignored and the full page + is used. """ @@ -176,10 +177,16 @@ class SourceParamsWebCrawlerParseOptions(BaseModel): """ List of path-to-selector mappings for extracting specific content from crawled pages. Each entry pairs a URL glob pattern with a CSS selector. The first - matching path wins. Only the matched HTML fragment is stored and indexed. + matching path wins. Only the matched HTML fragment is stored and indexed. Omit + the field to disable content selection — empty arrays are rejected. """ include_headers: Optional[Dict[str, str]] = None + """Up to 5 custom HTTP headers sent with each crawl request. + + Names must be RFC-7230 token characters (no spaces, colons, or control + characters); values must be HTAB + printable ASCII (no CR/LF). + """ include_images: Optional[bool] = None diff --git a/tests/api_resources/aisearch/namespaces/test_instances.py b/tests/api_resources/aisearch/namespaces/test_instances.py index 4190bfaa776..fd694678253 100644 --- a/tests/api_resources/aisearch/namespaces/test_instances.py +++ b/tests/api_resources/aisearch/namespaces/test_instances.py @@ -116,10 +116,14 @@ def test_method_create_with_all_params(self, client: Cloudflare) -> None: "content_selector": [ { "path": "**/blog/**", - "selector": "article .post-body", - } + "selector": "article div.post-body", + }, + { + "path": "**/docs/**", + "selector": "main", + }, ], - "include_headers": {"foo": "string"}, + "include_headers": {"cache-control": "no-cache, no-store"}, "include_images": True, "specific_sitemaps": [ "https://example.com/sitemap.xml", @@ -273,10 +277,14 @@ def test_method_update_with_all_params(self, client: Cloudflare) -> None: "content_selector": [ { "path": "**/blog/**", - "selector": "article .post-body", - } + "selector": "article div.post-body", + }, + { + "path": "**/docs/**", + "selector": "main", + }, ], - "include_headers": {"foo": "string"}, + "include_headers": {"cache-control": "no-cache, no-store"}, "include_images": True, "specific_sitemaps": [ "https://example.com/sitemap.xml", @@ -943,10 +951,14 @@ async def test_method_create_with_all_params(self, async_client: AsyncCloudflare "content_selector": [ { "path": "**/blog/**", - "selector": "article .post-body", - } + "selector": "article div.post-body", + }, + { + "path": "**/docs/**", + "selector": "main", + }, ], - "include_headers": {"foo": "string"}, + "include_headers": {"cache-control": "no-cache, no-store"}, "include_images": True, "specific_sitemaps": [ "https://example.com/sitemap.xml", @@ -1100,10 +1112,14 @@ async def test_method_update_with_all_params(self, async_client: AsyncCloudflare "content_selector": [ { "path": "**/blog/**", - "selector": "article .post-body", - } + "selector": "article div.post-body", + }, + { + "path": "**/docs/**", + "selector": "main", + }, ], - "include_headers": {"foo": "string"}, + "include_headers": {"cache-control": "no-cache, no-store"}, "include_images": True, "specific_sitemaps": [ "https://example.com/sitemap.xml", diff --git a/tests/api_resources/aisearch/test_instances.py b/tests/api_resources/aisearch/test_instances.py index 1aaf5fde4e6..fcb88148c66 100644 --- a/tests/api_resources/aisearch/test_instances.py +++ b/tests/api_resources/aisearch/test_instances.py @@ -114,10 +114,14 @@ def test_method_create_with_all_params(self, client: Cloudflare) -> None: "content_selector": [ { "path": "**/blog/**", - "selector": "article .post-body", - } + "selector": "article div.post-body", + }, + { + "path": "**/docs/**", + "selector": "main", + }, ], - "include_headers": {"foo": "string"}, + "include_headers": {"cache-control": "no-cache, no-store"}, "include_images": True, "specific_sitemaps": [ "https://example.com/sitemap.xml", @@ -259,10 +263,14 @@ def test_method_update_with_all_params(self, client: Cloudflare) -> None: "content_selector": [ { "path": "**/blog/**", - "selector": "article .post-body", - } + "selector": "article div.post-body", + }, + { + "path": "**/docs/**", + "selector": "main", + }, ], - "include_headers": {"foo": "string"}, + "include_headers": {"cache-control": "no-cache, no-store"}, "include_images": True, "specific_sitemaps": [ "https://example.com/sitemap.xml", @@ -837,10 +845,14 @@ async def test_method_create_with_all_params(self, async_client: AsyncCloudflare "content_selector": [ { "path": "**/blog/**", - "selector": "article .post-body", - } + "selector": "article div.post-body", + }, + { + "path": "**/docs/**", + "selector": "main", + }, ], - "include_headers": {"foo": "string"}, + "include_headers": {"cache-control": "no-cache, no-store"}, "include_images": True, "specific_sitemaps": [ "https://example.com/sitemap.xml", @@ -982,10 +994,14 @@ async def test_method_update_with_all_params(self, async_client: AsyncCloudflare "content_selector": [ { "path": "**/blog/**", - "selector": "article .post-body", - } + "selector": "article div.post-body", + }, + { + "path": "**/docs/**", + "selector": "main", + }, ], - "include_headers": {"foo": "string"}, + "include_headers": {"cache-control": "no-cache, no-store"}, "include_images": True, "specific_sitemaps": [ "https://example.com/sitemap.xml", From cc614b12c38ac9fa10e42bfdc48c0ee84abece60 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 5 May 2026 14:37:52 +0000 Subject: [PATCH 36/45] feat: feat(load_balancer_monitor_group): promote load_balancer_monitor_group config to main * feat(load_balancers): promote monitor group Stainless config to main Add monitor group references endpoint and set terraform resource name to load_balancer_monitor_group. Cherry-picked from staging. --- .stats.yml | 4 +- .../resources/load_balancers/api.md | 24 ++- .../load_balancers/load_balancers.py | 16 +- .../load_balancers/monitor_groups/__init__.py | 33 ++++ .../{ => monitor_groups}/monitor_groups.py | 52 ++++- .../monitor_groups/references.py | 185 ++++++++++++++++++ .../load_balancers/monitor_groups/__init__.py | 5 + .../monitor_groups/reference_get_response.py | 18 ++ .../load_balancers/monitor_groups/__init__.py | 1 + .../monitor_groups/test_references.py | 121 ++++++++++++ 10 files changed, 433 insertions(+), 26 deletions(-) create mode 100644 src/cloudflare/resources/load_balancers/monitor_groups/__init__.py rename src/cloudflare/resources/load_balancers/{ => monitor_groups}/monitor_groups.py (94%) create mode 100644 src/cloudflare/resources/load_balancers/monitor_groups/references.py create mode 100644 src/cloudflare/types/load_balancers/monitor_groups/__init__.py create mode 100644 src/cloudflare/types/load_balancers/monitor_groups/reference_get_response.py create mode 100644 tests/api_resources/load_balancers/monitor_groups/__init__.py create mode 100644 tests/api_resources/load_balancers/monitor_groups/test_references.py diff --git a/.stats.yml b/.stats.yml index a8050a9279b..8157b0e4551 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 2208 +configured_endpoints: 2209 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a6c352830d1270d0abb5bb983058ea21815e1bb7d2e163965335dcb0e706f057.yml openapi_spec_hash: 42dd4ac0ac3f5c00bbe80e26fed2fa51 -config_hash: 20574d7a53e0349a3337a121a46638d4 +config_hash: 8ff9a61d85e7bdc4cb1a445d27d8173e diff --git a/src/cloudflare/resources/load_balancers/api.md b/src/cloudflare/resources/load_balancers/api.md index 947746e3fe6..58bd01c5f43 100644 --- a/src/cloudflare/resources/load_balancers/api.md +++ b/src/cloudflare/resources/load_balancers/api.md @@ -85,12 +85,24 @@ from cloudflare.types.load_balancers import MonitorGroup Methods: -- client.load_balancers.monitor_groups.create(\*, account_id, \*\*params) -> MonitorGroup -- client.load_balancers.monitor_groups.update(monitor_group_id, \*, account_id, \*\*params) -> MonitorGroup -- client.load_balancers.monitor_groups.list(\*, account_id) -> SyncSinglePage[MonitorGroup] -- client.load_balancers.monitor_groups.delete(monitor_group_id, \*, account_id) -> MonitorGroup -- client.load_balancers.monitor_groups.edit(monitor_group_id, \*, account_id, \*\*params) -> MonitorGroup -- client.load_balancers.monitor_groups.get(monitor_group_id, \*, account_id) -> MonitorGroup +- client.load_balancers.monitor_groups.create(\*, account_id, \*\*params) -> MonitorGroup +- client.load_balancers.monitor_groups.update(monitor_group_id, \*, account_id, \*\*params) -> MonitorGroup +- client.load_balancers.monitor_groups.list(\*, account_id) -> SyncSinglePage[MonitorGroup] +- client.load_balancers.monitor_groups.delete(monitor_group_id, \*, account_id) -> MonitorGroup +- client.load_balancers.monitor_groups.edit(monitor_group_id, \*, account_id, \*\*params) -> MonitorGroup +- client.load_balancers.monitor_groups.get(monitor_group_id, \*, account_id) -> MonitorGroup + +### References + +Types: + +```python +from cloudflare.types.load_balancers.monitor_groups import ReferenceGetResponse +``` + +Methods: + +- client.load_balancers.monitor_groups.references.get(monitor_group_id, \*, account_id) -> SyncSinglePage[ReferenceGetResponse] ## Pools diff --git a/src/cloudflare/resources/load_balancers/load_balancers.py b/src/cloudflare/resources/load_balancers/load_balancers.py index 83f2ac5dd7c..277f7a5c7fe 100644 --- a/src/cloudflare/resources/load_balancers/load_balancers.py +++ b/src/cloudflare/resources/load_balancers/load_balancers.py @@ -51,14 +51,6 @@ ) from ...pagination import SyncSinglePage, AsyncSinglePage from ..._base_client import AsyncPaginator, make_request_options -from .monitor_groups import ( - MonitorGroupsResource, - AsyncMonitorGroupsResource, - MonitorGroupsResourceWithRawResponse, - AsyncMonitorGroupsResourceWithRawResponse, - MonitorGroupsResourceWithStreamingResponse, - AsyncMonitorGroupsResourceWithStreamingResponse, -) from .monitors.monitors import ( MonitorsResource, AsyncMonitorsResource, @@ -74,6 +66,14 @@ load_balancer_create_params, load_balancer_update_params, ) +from .monitor_groups.monitor_groups import ( + MonitorGroupsResource, + AsyncMonitorGroupsResource, + MonitorGroupsResourceWithRawResponse, + AsyncMonitorGroupsResourceWithRawResponse, + MonitorGroupsResourceWithStreamingResponse, + AsyncMonitorGroupsResourceWithStreamingResponse, +) from ...types.load_balancers.rules_param import RulesParam from ...types.load_balancers.default_pools import DefaultPools from ...types.load_balancers.load_balancer import LoadBalancer diff --git a/src/cloudflare/resources/load_balancers/monitor_groups/__init__.py b/src/cloudflare/resources/load_balancers/monitor_groups/__init__.py new file mode 100644 index 00000000000..f7790874f1c --- /dev/null +++ b/src/cloudflare/resources/load_balancers/monitor_groups/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .references import ( + ReferencesResource, + AsyncReferencesResource, + ReferencesResourceWithRawResponse, + AsyncReferencesResourceWithRawResponse, + ReferencesResourceWithStreamingResponse, + AsyncReferencesResourceWithStreamingResponse, +) +from .monitor_groups import ( + MonitorGroupsResource, + AsyncMonitorGroupsResource, + MonitorGroupsResourceWithRawResponse, + AsyncMonitorGroupsResourceWithRawResponse, + MonitorGroupsResourceWithStreamingResponse, + AsyncMonitorGroupsResourceWithStreamingResponse, +) + +__all__ = [ + "ReferencesResource", + "AsyncReferencesResource", + "ReferencesResourceWithRawResponse", + "AsyncReferencesResourceWithRawResponse", + "ReferencesResourceWithStreamingResponse", + "AsyncReferencesResourceWithStreamingResponse", + "MonitorGroupsResource", + "AsyncMonitorGroupsResource", + "MonitorGroupsResourceWithRawResponse", + "AsyncMonitorGroupsResourceWithRawResponse", + "MonitorGroupsResourceWithStreamingResponse", + "AsyncMonitorGroupsResourceWithStreamingResponse", +] diff --git a/src/cloudflare/resources/load_balancers/monitor_groups.py b/src/cloudflare/resources/load_balancers/monitor_groups/monitor_groups.py similarity index 94% rename from src/cloudflare/resources/load_balancers/monitor_groups.py rename to src/cloudflare/resources/load_balancers/monitor_groups/monitor_groups.py index 97990a78f5c..f62ad18ac48 100644 --- a/src/cloudflare/resources/load_balancers/monitor_groups.py +++ b/src/cloudflare/resources/load_balancers/monitor_groups/monitor_groups.py @@ -6,26 +6,38 @@ import httpx -from ..._types import Body, Query, Headers, NotGiven, not_given -from ..._utils import path_template, maybe_transform, async_maybe_transform -from ..._compat import cached_property -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import ( +from ...._types import Body, Query, Headers, NotGiven, not_given +from ...._utils import path_template, maybe_transform, async_maybe_transform +from ...._compat import cached_property +from .references import ( + ReferencesResource, + AsyncReferencesResource, + ReferencesResourceWithRawResponse, + AsyncReferencesResourceWithRawResponse, + ReferencesResourceWithStreamingResponse, + AsyncReferencesResourceWithStreamingResponse, +) +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 SyncSinglePage, AsyncSinglePage -from ..._base_client import AsyncPaginator, make_request_options -from ...types.load_balancers import monitor_group_edit_params, monitor_group_create_params, monitor_group_update_params -from ...types.load_balancers.monitor_group import MonitorGroup +from ...._wrappers import ResultWrapper +from ....pagination import SyncSinglePage, AsyncSinglePage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.load_balancers import monitor_group_edit_params, monitor_group_create_params, monitor_group_update_params +from ....types.load_balancers.monitor_group import MonitorGroup __all__ = ["MonitorGroupsResource", "AsyncMonitorGroupsResource"] class MonitorGroupsResource(SyncAPIResource): + @cached_property + def references(self) -> ReferencesResource: + return ReferencesResource(self._client) + @cached_property def with_raw_response(self) -> MonitorGroupsResourceWithRawResponse: """ @@ -360,6 +372,10 @@ def get( class AsyncMonitorGroupsResource(AsyncAPIResource): + @cached_property + def references(self) -> AsyncReferencesResource: + return AsyncReferencesResource(self._client) + @cached_property def with_raw_response(self) -> AsyncMonitorGroupsResourceWithRawResponse: """ @@ -716,6 +732,10 @@ def __init__(self, monitor_groups: MonitorGroupsResource) -> None: monitor_groups.get, ) + @cached_property + def references(self) -> ReferencesResourceWithRawResponse: + return ReferencesResourceWithRawResponse(self._monitor_groups.references) + class AsyncMonitorGroupsResourceWithRawResponse: def __init__(self, monitor_groups: AsyncMonitorGroupsResource) -> None: @@ -740,6 +760,10 @@ def __init__(self, monitor_groups: AsyncMonitorGroupsResource) -> None: monitor_groups.get, ) + @cached_property + def references(self) -> AsyncReferencesResourceWithRawResponse: + return AsyncReferencesResourceWithRawResponse(self._monitor_groups.references) + class MonitorGroupsResourceWithStreamingResponse: def __init__(self, monitor_groups: MonitorGroupsResource) -> None: @@ -764,6 +788,10 @@ def __init__(self, monitor_groups: MonitorGroupsResource) -> None: monitor_groups.get, ) + @cached_property + def references(self) -> ReferencesResourceWithStreamingResponse: + return ReferencesResourceWithStreamingResponse(self._monitor_groups.references) + class AsyncMonitorGroupsResourceWithStreamingResponse: def __init__(self, monitor_groups: AsyncMonitorGroupsResource) -> None: @@ -787,3 +815,7 @@ def __init__(self, monitor_groups: AsyncMonitorGroupsResource) -> None: self.get = async_to_streamed_response_wrapper( monitor_groups.get, ) + + @cached_property + def references(self) -> AsyncReferencesResourceWithStreamingResponse: + return AsyncReferencesResourceWithStreamingResponse(self._monitor_groups.references) diff --git a/src/cloudflare/resources/load_balancers/monitor_groups/references.py b/src/cloudflare/resources/load_balancers/monitor_groups/references.py new file mode 100644 index 00000000000..8e0f97f4fef --- /dev/null +++ b/src/cloudflare/resources/load_balancers/monitor_groups/references.py @@ -0,0 +1,185 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ...._types import Body, Query, Headers, NotGiven, not_given +from ...._utils import path_template +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 ....pagination import SyncSinglePage, AsyncSinglePage +from ...._base_client import AsyncPaginator, make_request_options +from ....types.load_balancers.monitor_groups.reference_get_response import ReferenceGetResponse + +__all__ = ["ReferencesResource", "AsyncReferencesResource"] + + +class ReferencesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ReferencesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 ReferencesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ReferencesResourceWithStreamingResponse: + """ + 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 ReferencesResourceWithStreamingResponse(self) + + def get( + self, + monitor_group_id: str, + *, + 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, + ) -> SyncSinglePage[ReferenceGetResponse]: + """ + Get the list of resources that reference the provided monitor group. + + Args: + account_id: Identifier. + + 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 monitor_group_id: + raise ValueError(f"Expected a non-empty value for `monitor_group_id` but received {monitor_group_id!r}") + return self._get_api_list( + path_template( + "/accounts/{account_id}/load_balancers/monitor_groups/{monitor_group_id}/references", + account_id=account_id, + monitor_group_id=monitor_group_id, + ), + page=SyncSinglePage[ReferenceGetResponse], + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + model=ReferenceGetResponse, + ) + + +class AsyncReferencesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncReferencesResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 AsyncReferencesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncReferencesResourceWithStreamingResponse: + """ + 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 AsyncReferencesResourceWithStreamingResponse(self) + + def get( + self, + monitor_group_id: str, + *, + 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, + ) -> AsyncPaginator[ReferenceGetResponse, AsyncSinglePage[ReferenceGetResponse]]: + """ + Get the list of resources that reference the provided monitor group. + + Args: + account_id: Identifier. + + 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 monitor_group_id: + raise ValueError(f"Expected a non-empty value for `monitor_group_id` but received {monitor_group_id!r}") + return self._get_api_list( + path_template( + "/accounts/{account_id}/load_balancers/monitor_groups/{monitor_group_id}/references", + account_id=account_id, + monitor_group_id=monitor_group_id, + ), + page=AsyncSinglePage[ReferenceGetResponse], + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + model=ReferenceGetResponse, + ) + + +class ReferencesResourceWithRawResponse: + def __init__(self, references: ReferencesResource) -> None: + self._references = references + + self.get = to_raw_response_wrapper( + references.get, + ) + + +class AsyncReferencesResourceWithRawResponse: + def __init__(self, references: AsyncReferencesResource) -> None: + self._references = references + + self.get = async_to_raw_response_wrapper( + references.get, + ) + + +class ReferencesResourceWithStreamingResponse: + def __init__(self, references: ReferencesResource) -> None: + self._references = references + + self.get = to_streamed_response_wrapper( + references.get, + ) + + +class AsyncReferencesResourceWithStreamingResponse: + def __init__(self, references: AsyncReferencesResource) -> None: + self._references = references + + self.get = async_to_streamed_response_wrapper( + references.get, + ) diff --git a/src/cloudflare/types/load_balancers/monitor_groups/__init__.py b/src/cloudflare/types/load_balancers/monitor_groups/__init__.py new file mode 100644 index 00000000000..9a9f7de1c68 --- /dev/null +++ b/src/cloudflare/types/load_balancers/monitor_groups/__init__.py @@ -0,0 +1,5 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .reference_get_response import ReferenceGetResponse as ReferenceGetResponse diff --git a/src/cloudflare/types/load_balancers/monitor_groups/reference_get_response.py b/src/cloudflare/types/load_balancers/monitor_groups/reference_get_response.py new file mode 100644 index 00000000000..91f6725f1c8 --- /dev/null +++ b/src/cloudflare/types/load_balancers/monitor_groups/reference_get_response.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["ReferenceGetResponse"] + + +class ReferenceGetResponse(BaseModel): + reference_type: Optional[Literal["*", "referral", "referrer"]] = None + + resource_id: Optional[str] = None + + resource_name: Optional[str] = None + + resource_type: Optional[str] = None diff --git a/tests/api_resources/load_balancers/monitor_groups/__init__.py b/tests/api_resources/load_balancers/monitor_groups/__init__.py new file mode 100644 index 00000000000..fd8019a9a1a --- /dev/null +++ b/tests/api_resources/load_balancers/monitor_groups/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/load_balancers/monitor_groups/test_references.py b/tests/api_resources/load_balancers/monitor_groups/test_references.py new file mode 100644 index 00000000000..5185de60184 --- /dev/null +++ b/tests/api_resources/load_balancers/monitor_groups/test_references.py @@ -0,0 +1,121 @@ +# 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 pytest + +from cloudflare import Cloudflare, AsyncCloudflare +from tests.utils import assert_matches_type +from cloudflare.pagination import SyncSinglePage, AsyncSinglePage +from cloudflare.types.load_balancers.monitor_groups import ReferenceGetResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestReferences: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_get(self, client: Cloudflare) -> None: + reference = client.load_balancers.monitor_groups.references.get( + monitor_group_id="f1aba936b94213e5b8dca0c0dbf1f9cc", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + assert_matches_type(SyncSinglePage[ReferenceGetResponse], reference, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Cloudflare) -> None: + response = client.load_balancers.monitor_groups.references.with_raw_response.get( + monitor_group_id="f1aba936b94213e5b8dca0c0dbf1f9cc", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + reference = response.parse() + assert_matches_type(SyncSinglePage[ReferenceGetResponse], reference, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Cloudflare) -> None: + with client.load_balancers.monitor_groups.references.with_streaming_response.get( + monitor_group_id="f1aba936b94213e5b8dca0c0dbf1f9cc", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + reference = response.parse() + assert_matches_type(SyncSinglePage[ReferenceGetResponse], reference, 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.load_balancers.monitor_groups.references.with_raw_response.get( + monitor_group_id="f1aba936b94213e5b8dca0c0dbf1f9cc", + account_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `monitor_group_id` but received ''"): + client.load_balancers.monitor_groups.references.with_raw_response.get( + monitor_group_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + +class TestAsyncReferences: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_get(self, async_client: AsyncCloudflare) -> None: + reference = await async_client.load_balancers.monitor_groups.references.get( + monitor_group_id="f1aba936b94213e5b8dca0c0dbf1f9cc", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + assert_matches_type(AsyncSinglePage[ReferenceGetResponse], reference, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncCloudflare) -> None: + response = await async_client.load_balancers.monitor_groups.references.with_raw_response.get( + monitor_group_id="f1aba936b94213e5b8dca0c0dbf1f9cc", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + reference = await response.parse() + assert_matches_type(AsyncSinglePage[ReferenceGetResponse], reference, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncCloudflare) -> None: + async with async_client.load_balancers.monitor_groups.references.with_streaming_response.get( + monitor_group_id="f1aba936b94213e5b8dca0c0dbf1f9cc", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + reference = await response.parse() + assert_matches_type(AsyncSinglePage[ReferenceGetResponse], reference, 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.load_balancers.monitor_groups.references.with_raw_response.get( + monitor_group_id="f1aba936b94213e5b8dca0c0dbf1f9cc", + account_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `monitor_group_id` but received ''"): + await async_client.load_balancers.monitor_groups.references.with_raw_response.get( + monitor_group_id="", + account_id="023e105f4ecef8ad9ca31a8372d0c353", + ) From 7e0de28e6ff4326181e4855b07a90ec5b96a195f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 5 May 2026 15:21:00 +0000 Subject: [PATCH 37/45] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 8157b0e4551..19dfa7530fd 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 2209 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a6c352830d1270d0abb5bb983058ea21815e1bb7d2e163965335dcb0e706f057.yml openapi_spec_hash: 42dd4ac0ac3f5c00bbe80e26fed2fa51 -config_hash: 8ff9a61d85e7bdc4cb1a445d27d8173e +config_hash: 33ec2cdb453b26c2d3b3a8447bff4595 From 8d7e2c86ef6bc40281bfea2eade2e6827ceec006 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 5 May 2026 16:23:13 +0000 Subject: [PATCH 38/45] feat: feat(cache): Update OPCR config to v2 endpoints (CACHE-13523) * feat(cache): Update OPCR config to v2 endpoints (CACHE-13523) Promote OPCR (origin public cloud region) Stainless config from staging to main: - v2 endpoints under /origin/cloud_regions (PUT-only, no POST), with upsert + ImportState support via id_path_param + id_property. - Deprecated v1 methods (/cache/origin_cloud_regions/*) retained as *_v1 with deprecated annotation; skipped for all SDK/Terraform targets so only the docs site consumes them. v1 was never published to SDKs/Terraform historically, and v1 endpoints remain functional during the deprecation period. - Resource model points to cache-rules_origin_cloud_region_v2_entry. Combines staging-branch commits 7e22620f (MR 762) and 1c1ece32 (MR 795). --- .stats.yml | 4 +- src/cloudflare/resources/cache/api.md | 21 +- .../resources/cache/origin_cloud_regions.py | 472 +++++++----------- src/cloudflare/types/cache/__init__.py | 16 +- .../types/cache/origin_cloud_region.py | 9 +- ...rigin_cloud_region_bulk_delete_response.py | 53 +- .../origin_cloud_region_bulk_edit_response.py | 74 --- ...origin_cloud_region_bulk_update_params.py} | 13 +- ...rigin_cloud_region_bulk_update_response.py | 65 +++ .../origin_cloud_region_create_params.py | 28 -- .../origin_cloud_region_create_response.py | 25 - .../origin_cloud_region_delete_response.py | 19 +- .../origin_cloud_region_edit_response.py | 24 - .../cache/origin_cloud_region_get_response.py | 25 - .../cache/origin_cloud_region_list_params.py | 18 + .../origin_cloud_region_list_response.py | 24 - ...y => origin_cloud_region_update_params.py} | 15 +- .../cache/test_origin_cloud_regions.py | 312 +++++------- 18 files changed, 458 insertions(+), 759 deletions(-) delete mode 100644 src/cloudflare/types/cache/origin_cloud_region_bulk_edit_response.py rename src/cloudflare/types/cache/{origin_cloud_region_bulk_edit_params.py => origin_cloud_region_bulk_update_params.py} (59%) create mode 100644 src/cloudflare/types/cache/origin_cloud_region_bulk_update_response.py delete mode 100644 src/cloudflare/types/cache/origin_cloud_region_create_params.py delete mode 100644 src/cloudflare/types/cache/origin_cloud_region_create_response.py delete mode 100644 src/cloudflare/types/cache/origin_cloud_region_edit_response.py delete mode 100644 src/cloudflare/types/cache/origin_cloud_region_get_response.py create mode 100644 src/cloudflare/types/cache/origin_cloud_region_list_params.py delete mode 100644 src/cloudflare/types/cache/origin_cloud_region_list_response.py rename src/cloudflare/types/cache/{origin_cloud_region_edit_params.py => origin_cloud_region_update_params.py} (50%) diff --git a/.stats.yml b/.stats.yml index 19dfa7530fd..518292c201d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 2209 +configured_endpoints: 2208 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a6c352830d1270d0abb5bb983058ea21815e1bb7d2e163965335dcb0e706f057.yml openapi_spec_hash: 42dd4ac0ac3f5c00bbe80e26fed2fa51 -config_hash: 33ec2cdb453b26c2d3b3a8447bff4595 +config_hash: 0c33107d28fc9d1d5726d8ac8459421a diff --git a/src/cloudflare/resources/cache/api.md b/src/cloudflare/resources/cache/api.md index 3bbb74056ef..8b743a99a82 100644 --- a/src/cloudflare/resources/cache/api.md +++ b/src/cloudflare/resources/cache/api.md @@ -94,24 +94,19 @@ Types: ```python from cloudflare.types.cache import ( OriginCloudRegion, - OriginCloudRegionCreateResponse, - OriginCloudRegionListResponse, OriginCloudRegionDeleteResponse, OriginCloudRegionBulkDeleteResponse, - OriginCloudRegionBulkEditResponse, - OriginCloudRegionEditResponse, - OriginCloudRegionGetResponse, + OriginCloudRegionBulkUpdateResponse, OriginCloudRegionSupportedRegionsResponse, ) ``` Methods: -- client.cache.origin_cloud_regions.create(\*, zone_id, \*\*params) -> Optional[OriginCloudRegionCreateResponse] -- client.cache.origin_cloud_regions.list(\*, zone_id) -> Optional[OriginCloudRegionListResponse] -- client.cache.origin_cloud_regions.delete(origin_ip, \*, zone_id) -> Optional[OriginCloudRegionDeleteResponse] -- client.cache.origin_cloud_regions.bulk_delete(\*, zone_id) -> Optional[OriginCloudRegionBulkDeleteResponse] -- client.cache.origin_cloud_regions.bulk_edit(\*, zone_id, \*\*params) -> Optional[OriginCloudRegionBulkEditResponse] -- client.cache.origin_cloud_regions.edit(\*, zone_id, \*\*params) -> Optional[OriginCloudRegionEditResponse] -- client.cache.origin_cloud_regions.get(origin_ip, \*, zone_id) -> Optional[OriginCloudRegionGetResponse] -- client.cache.origin_cloud_regions.supported_regions(\*, zone_id) -> Optional[OriginCloudRegionSupportedRegionsResponse] +- client.cache.origin_cloud_regions.update(path_origin_ip, \*, zone_id, \*\*params) -> Optional[OriginCloudRegion] +- client.cache.origin_cloud_regions.list(\*, zone_id, \*\*params) -> SyncV4PagePaginationArray[OriginCloudRegion] +- client.cache.origin_cloud_regions.delete(origin_ip, \*, zone_id) -> Optional[OriginCloudRegionDeleteResponse] +- client.cache.origin_cloud_regions.bulk_delete(\*, zone_id) -> Optional[OriginCloudRegionBulkDeleteResponse] +- client.cache.origin_cloud_regions.bulk_update(\*, zone_id, \*\*params) -> Optional[OriginCloudRegionBulkUpdateResponse] +- client.cache.origin_cloud_regions.get(origin_ip, \*, zone_id) -> Optional[OriginCloudRegion] +- client.cache.origin_cloud_regions.supported_regions(\*, zone_id) -> Optional[OriginCloudRegionSupportedRegionsResponse] diff --git a/src/cloudflare/resources/cache/origin_cloud_regions.py b/src/cloudflare/resources/cache/origin_cloud_regions.py index a961eecd1d0..e56f7d4f63b 100644 --- a/src/cloudflare/resources/cache/origin_cloud_regions.py +++ b/src/cloudflare/resources/cache/origin_cloud_regions.py @@ -7,7 +7,7 @@ import httpx -from ..._types import Body, Query, Headers, NotGiven, not_given +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given from ..._utils import path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource @@ -18,19 +18,17 @@ async_to_streamed_response_wrapper, ) from ..._wrappers import ResultWrapper +from ...pagination import SyncV4PagePaginationArray, AsyncV4PagePaginationArray from ...types.cache import ( - origin_cloud_region_edit_params, - origin_cloud_region_create_params, - origin_cloud_region_bulk_edit_params, + origin_cloud_region_list_params, + origin_cloud_region_update_params, + origin_cloud_region_bulk_update_params, ) -from ..._base_client import make_request_options -from ...types.cache.origin_cloud_region_get_response import OriginCloudRegionGetResponse -from ...types.cache.origin_cloud_region_edit_response import OriginCloudRegionEditResponse -from ...types.cache.origin_cloud_region_list_response import OriginCloudRegionListResponse -from ...types.cache.origin_cloud_region_create_response import OriginCloudRegionCreateResponse +from ..._base_client import AsyncPaginator, make_request_options +from ...types.cache.origin_cloud_region import OriginCloudRegion from ...types.cache.origin_cloud_region_delete_response import OriginCloudRegionDeleteResponse -from ...types.cache.origin_cloud_region_bulk_edit_response import OriginCloudRegionBulkEditResponse from ...types.cache.origin_cloud_region_bulk_delete_response import OriginCloudRegionBulkDeleteResponse +from ...types.cache.origin_cloud_region_bulk_update_response import OriginCloudRegionBulkUpdateResponse from ...types.cache.origin_cloud_region_supported_regions_response import OriginCloudRegionSupportedRegionsResponse __all__ = ["OriginCloudRegionsResource", "AsyncOriginCloudRegionsResource"] @@ -56,11 +54,12 @@ def with_streaming_response(self) -> OriginCloudRegionsResourceWithStreamingResp """ return OriginCloudRegionsResourceWithStreamingResponse(self) - def create( + def update( self, + path_origin_ip: str, *, zone_id: str, - ip: str, + body_origin_ip: str, region: str, vendor: Literal["aws", "azure", "gcp", "oci"], # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -69,21 +68,24 @@ def create( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Optional[OriginCloudRegionCreateResponse]: - """Adds a single IP-to-cloud-region mapping for the zone. - - The IP must be a valid - IPv4 or IPv6 address and is normalized to canonical form before storage (RFC - 5952 for IPv6). Returns 400 (code 1145) if a mapping for that IP already exists - — use PATCH to update an existing entry. The vendor and region are validated - against the list from - `GET /zones/{zone_id}/cache/origin_cloud_regions/supported_regions`. + ) -> Optional[OriginCloudRegion]: + """ + Creates a new IP-to-cloud-region mapping or replaces the existing mapping for + the specified IP. PUT is idempotent — calling it repeatedly with the same body + produces the same result. The IP path parameter is normalized to canonical form + (RFC 5952 for IPv6) before storage. The vendor and region are validated against + the list from `GET /zones/{zone_id}/origin/cloud_regions/supported_regions`. + Returns 400 if the `origin_ip` in the body does not match the URL path + parameter. Returns 403 (code 1164) when the zone has reached the limit of 3,500 + IP mappings. Args: zone_id: Identifier. - ip: Origin IP address (IPv4 or IPv6). Normalized to canonical form before storage - (RFC 5952 for IPv6). + body_origin_ip: Origin IP address (IPv4 or IPv6). For the single PUT endpoint + (`PUT /origin/cloud_regions/{origin_ip}`), this field must match the path + parameter or the request will be rejected with a 400 error. For the batch PUT + endpoint, this field identifies which mapping to upsert. region: Cloud vendor region identifier. Must be a valid region for the specified vendor as returned by the supported_regions endpoint. @@ -100,49 +102,57 @@ def create( """ if not zone_id: raise ValueError(f"Expected a non-empty value for `zone_id` but received {zone_id!r}") - return self._post( - path_template("/zones/{zone_id}/cache/origin_cloud_regions", zone_id=zone_id), + if not path_origin_ip: + raise ValueError(f"Expected a non-empty value for `path_origin_ip` but received {path_origin_ip!r}") + return self._put( + path_template( + "/zones/{zone_id}/origin/cloud_regions/{path_origin_ip}", zone_id=zone_id, path_origin_ip=path_origin_ip + ), body=maybe_transform( { - "ip": ip, + "body_origin_ip": body_origin_ip, "region": region, "vendor": vendor, }, - origin_cloud_region_create_params.OriginCloudRegionCreateParams, + origin_cloud_region_update_params.OriginCloudRegionUpdateParams, ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[Optional[OriginCloudRegionCreateResponse]]._unwrapper, - ), - cast_to=cast( - Type[Optional[OriginCloudRegionCreateResponse]], ResultWrapper[OriginCloudRegionCreateResponse] + post_parser=ResultWrapper[Optional[OriginCloudRegion]]._unwrapper, ), + cast_to=cast(Type[Optional[OriginCloudRegion]], ResultWrapper[OriginCloudRegion]), ) def list( self, *, zone_id: str, + page: int | Omit = omit, + per_page: int | Omit = omit, # 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[OriginCloudRegionListResponse]: - """Returns all IP-to-cloud-region mappings configured for the zone. - - Each mapping - tells Cloudflare which cloud vendor and region hosts the origin at that IP, - enabling the edge to route via the nearest Tiered Cache upper-tier co-located - with that cloud provider. Returns an empty array when no mappings exist. + ) -> SyncV4PagePaginationArray[OriginCloudRegion]: + """ + Returns all IP-to-cloud-region mappings configured for the zone with pagination + support. Each mapping tells Cloudflare which cloud vendor and region hosts the + origin at that IP, enabling the edge to route via the nearest Tiered Cache + upper-tier co-located with that cloud provider. Returns an empty array when no + mappings exist. Args: zone_id: Identifier. + page: Page number of paginated results. + + per_page: Number of items per page. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -153,16 +163,23 @@ def list( """ if not zone_id: raise ValueError(f"Expected a non-empty value for `zone_id` but received {zone_id!r}") - return self._get( - path_template("/zones/{zone_id}/cache/origin_cloud_regions", zone_id=zone_id), + return self._get_api_list( + path_template("/zones/{zone_id}/origin/cloud_regions", zone_id=zone_id), + page=SyncV4PagePaginationArray[OriginCloudRegion], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[Optional[OriginCloudRegionListResponse]]._unwrapper, + query=maybe_transform( + { + "page": page, + "per_page": per_page, + }, + origin_cloud_region_list_params.OriginCloudRegionListParams, + ), ), - cast_to=cast(Type[Optional[OriginCloudRegionListResponse]], ResultWrapper[OriginCloudRegionListResponse]), + model=OriginCloudRegion, ) def delete( @@ -180,9 +197,9 @@ def delete( """Removes the cloud region mapping for a single origin IP address. The IP path - parameter is normalized before lookup. Returns the deleted entry on success. - Returns 404 (code 1163) if no mapping exists for the specified IP. When the last - mapping for the zone is removed the underlying rule record is also deleted. + parameter is normalized before lookup. Returns the deleted IP on success. + Returns 404 if no mapping exists for the specified IP. When the last mapping for + the zone is removed the underlying rule record is also deleted. Args: zone_id: Identifier. @@ -200,9 +217,7 @@ def delete( if not origin_ip: raise ValueError(f"Expected a non-empty value for `origin_ip` but received {origin_ip!r}") return self._delete( - path_template( - "/zones/{zone_id}/cache/origin_cloud_regions/{origin_ip}", zone_id=zone_id, origin_ip=origin_ip - ), + path_template("/zones/{zone_id}/origin/cloud_regions/{origin_ip}", zone_id=zone_id, origin_ip=origin_ip), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -247,7 +262,7 @@ def bulk_delete( if not zone_id: raise ValueError(f"Expected a non-empty value for `zone_id` but received {zone_id!r}") return self._delete( - path_template("/zones/{zone_id}/cache/origin_cloud_regions/batch", zone_id=zone_id), + path_template("/zones/{zone_id}/origin/cloud_regions/batch", zone_id=zone_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -260,25 +275,27 @@ def bulk_delete( ), ) - def bulk_edit( + def bulk_update( self, *, zone_id: str, - body: Iterable[origin_cloud_region_bulk_edit_params.Body], + body: Iterable[origin_cloud_region_bulk_update_params.Body], # 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[OriginCloudRegionBulkEditResponse]: - """Adds or updates up to 100 IP-to-cloud-region mappings in a single request. + ) -> Optional[OriginCloudRegionBulkUpdateResponse]: + """Upserts up to 100 IP-to-cloud-region mappings in a single request. - Each - item is validated independently — valid items are applied and invalid items are - returned in the `failed` array. The vendor and region for every item are - validated against the list from - `GET /zones/{zone_id}/cache/origin_cloud_regions/supported_regions`. + Items in the + request body are created or replaced; mappings not included in the request body + are preserved unchanged (this is a merge operation, not a full collection + replacement). Each item is validated independently — valid items are applied and + invalid items are returned in the `failed` array. The vendor and region for + every item are validated against the list from + `GET /zones/{zone_id}/origin/cloud_regions/supported_regions`. Args: zone_id: Identifier. @@ -293,82 +310,19 @@ def bulk_edit( """ if not zone_id: raise ValueError(f"Expected a non-empty value for `zone_id` but received {zone_id!r}") - return self._patch( - path_template("/zones/{zone_id}/cache/origin_cloud_regions/batch", zone_id=zone_id), - body=maybe_transform(body, Iterable[origin_cloud_region_bulk_edit_params.Body]), + return self._put( + path_template("/zones/{zone_id}/origin/cloud_regions/batch", zone_id=zone_id), + body=maybe_transform(body, Iterable[origin_cloud_region_bulk_update_params.Body]), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[Optional[OriginCloudRegionBulkEditResponse]]._unwrapper, + post_parser=ResultWrapper[Optional[OriginCloudRegionBulkUpdateResponse]]._unwrapper, ), cast_to=cast( - Type[Optional[OriginCloudRegionBulkEditResponse]], ResultWrapper[OriginCloudRegionBulkEditResponse] - ), - ) - - def edit( - self, - *, - zone_id: str, - ip: str, - region: str, - vendor: Literal["aws", "azure", "gcp", "oci"], - # 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[OriginCloudRegionEditResponse]: - """Adds or updates a single IP-to-cloud-region mapping for the zone. - - Unlike POST, - this operation is idempotent — if a mapping for the IP already exists it is - overwritten. Returns the complete updated list of all mappings for the zone. - Returns 403 (code 1164) when the zone has reached the limit of 3,500 IP - mappings. - - Args: - zone_id: Identifier. - - ip: Origin IP address (IPv4 or IPv6). Normalized to canonical form before storage - (RFC 5952 for IPv6). - - region: Cloud vendor region identifier. Must be a valid region for the specified vendor - as returned by the supported_regions endpoint. - - vendor: Cloud vendor hosting the origin. Must be one of the supported vendors. - - 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 zone_id: - raise ValueError(f"Expected a non-empty value for `zone_id` but received {zone_id!r}") - return self._patch( - path_template("/zones/{zone_id}/cache/origin_cloud_regions", zone_id=zone_id), - body=maybe_transform( - { - "ip": ip, - "region": region, - "vendor": vendor, - }, - origin_cloud_region_edit_params.OriginCloudRegionEditParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - post_parser=ResultWrapper[Optional[OriginCloudRegionEditResponse]]._unwrapper, + Type[Optional[OriginCloudRegionBulkUpdateResponse]], ResultWrapper[OriginCloudRegionBulkUpdateResponse] ), - cast_to=cast(Type[Optional[OriginCloudRegionEditResponse]], ResultWrapper[OriginCloudRegionEditResponse]), ) def get( @@ -382,12 +336,12 @@ def get( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Optional[OriginCloudRegionGetResponse]: + ) -> Optional[OriginCloudRegion]: """Returns the cloud region mapping for a single origin IP address. The IP path - parameter is normalized before lookup (RFC 5952 for IPv6). Returns 404 - (code 1142) if the zone has no mappings or if the specified IP has no mapping. + parameter is normalized before lookup (RFC 5952 for IPv6). Returns 404 if the + zone has no mappings or if the specified IP has no mapping. Args: zone_id: Identifier. @@ -405,17 +359,15 @@ def get( if not origin_ip: raise ValueError(f"Expected a non-empty value for `origin_ip` but received {origin_ip!r}") return self._get( - path_template( - "/zones/{zone_id}/cache/origin_cloud_regions/{origin_ip}", zone_id=zone_id, origin_ip=origin_ip - ), + path_template("/zones/{zone_id}/origin/cloud_regions/{origin_ip}", zone_id=zone_id, origin_ip=origin_ip), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[Optional[OriginCloudRegionGetResponse]]._unwrapper, + post_parser=ResultWrapper[Optional[OriginCloudRegion]]._unwrapper, ), - cast_to=cast(Type[Optional[OriginCloudRegionGetResponse]], ResultWrapper[OriginCloudRegionGetResponse]), + cast_to=cast(Type[Optional[OriginCloudRegion]], ResultWrapper[OriginCloudRegion]), ) def supported_regions( @@ -449,7 +401,7 @@ def supported_regions( if not zone_id: raise ValueError(f"Expected a non-empty value for `zone_id` but received {zone_id!r}") return self._get( - path_template("/zones/{zone_id}/cache/origin_cloud_regions/supported_regions", zone_id=zone_id), + path_template("/zones/{zone_id}/origin/cloud_regions/supported_regions", zone_id=zone_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -484,11 +436,12 @@ def with_streaming_response(self) -> AsyncOriginCloudRegionsResourceWithStreamin """ return AsyncOriginCloudRegionsResourceWithStreamingResponse(self) - async def create( + async def update( self, + path_origin_ip: str, *, zone_id: str, - ip: str, + body_origin_ip: str, region: str, vendor: Literal["aws", "azure", "gcp", "oci"], # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -497,21 +450,24 @@ async def create( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Optional[OriginCloudRegionCreateResponse]: - """Adds a single IP-to-cloud-region mapping for the zone. - - The IP must be a valid - IPv4 or IPv6 address and is normalized to canonical form before storage (RFC - 5952 for IPv6). Returns 400 (code 1145) if a mapping for that IP already exists - — use PATCH to update an existing entry. The vendor and region are validated - against the list from - `GET /zones/{zone_id}/cache/origin_cloud_regions/supported_regions`. + ) -> Optional[OriginCloudRegion]: + """ + Creates a new IP-to-cloud-region mapping or replaces the existing mapping for + the specified IP. PUT is idempotent — calling it repeatedly with the same body + produces the same result. The IP path parameter is normalized to canonical form + (RFC 5952 for IPv6) before storage. The vendor and region are validated against + the list from `GET /zones/{zone_id}/origin/cloud_regions/supported_regions`. + Returns 400 if the `origin_ip` in the body does not match the URL path + parameter. Returns 403 (code 1164) when the zone has reached the limit of 3,500 + IP mappings. Args: zone_id: Identifier. - ip: Origin IP address (IPv4 or IPv6). Normalized to canonical form before storage - (RFC 5952 for IPv6). + body_origin_ip: Origin IP address (IPv4 or IPv6). For the single PUT endpoint + (`PUT /origin/cloud_regions/{origin_ip}`), this field must match the path + parameter or the request will be rejected with a 400 error. For the batch PUT + endpoint, this field identifies which mapping to upsert. region: Cloud vendor region identifier. Must be a valid region for the specified vendor as returned by the supported_regions endpoint. @@ -528,49 +484,57 @@ async def create( """ if not zone_id: raise ValueError(f"Expected a non-empty value for `zone_id` but received {zone_id!r}") - return await self._post( - path_template("/zones/{zone_id}/cache/origin_cloud_regions", zone_id=zone_id), + if not path_origin_ip: + raise ValueError(f"Expected a non-empty value for `path_origin_ip` but received {path_origin_ip!r}") + return await self._put( + path_template( + "/zones/{zone_id}/origin/cloud_regions/{path_origin_ip}", zone_id=zone_id, path_origin_ip=path_origin_ip + ), body=await async_maybe_transform( { - "ip": ip, + "body_origin_ip": body_origin_ip, "region": region, "vendor": vendor, }, - origin_cloud_region_create_params.OriginCloudRegionCreateParams, + origin_cloud_region_update_params.OriginCloudRegionUpdateParams, ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[Optional[OriginCloudRegionCreateResponse]]._unwrapper, - ), - cast_to=cast( - Type[Optional[OriginCloudRegionCreateResponse]], ResultWrapper[OriginCloudRegionCreateResponse] + post_parser=ResultWrapper[Optional[OriginCloudRegion]]._unwrapper, ), + cast_to=cast(Type[Optional[OriginCloudRegion]], ResultWrapper[OriginCloudRegion]), ) - async def list( + def list( self, *, zone_id: str, + page: int | Omit = omit, + per_page: int | Omit = omit, # 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[OriginCloudRegionListResponse]: - """Returns all IP-to-cloud-region mappings configured for the zone. - - Each mapping - tells Cloudflare which cloud vendor and region hosts the origin at that IP, - enabling the edge to route via the nearest Tiered Cache upper-tier co-located - with that cloud provider. Returns an empty array when no mappings exist. + ) -> AsyncPaginator[OriginCloudRegion, AsyncV4PagePaginationArray[OriginCloudRegion]]: + """ + Returns all IP-to-cloud-region mappings configured for the zone with pagination + support. Each mapping tells Cloudflare which cloud vendor and region hosts the + origin at that IP, enabling the edge to route via the nearest Tiered Cache + upper-tier co-located with that cloud provider. Returns an empty array when no + mappings exist. Args: zone_id: Identifier. + page: Page number of paginated results. + + per_page: Number of items per page. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -581,16 +545,23 @@ async def list( """ if not zone_id: raise ValueError(f"Expected a non-empty value for `zone_id` but received {zone_id!r}") - return await self._get( - path_template("/zones/{zone_id}/cache/origin_cloud_regions", zone_id=zone_id), + return self._get_api_list( + path_template("/zones/{zone_id}/origin/cloud_regions", zone_id=zone_id), + page=AsyncV4PagePaginationArray[OriginCloudRegion], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[Optional[OriginCloudRegionListResponse]]._unwrapper, + query=maybe_transform( + { + "page": page, + "per_page": per_page, + }, + origin_cloud_region_list_params.OriginCloudRegionListParams, + ), ), - cast_to=cast(Type[Optional[OriginCloudRegionListResponse]], ResultWrapper[OriginCloudRegionListResponse]), + model=OriginCloudRegion, ) async def delete( @@ -608,9 +579,9 @@ async def delete( """Removes the cloud region mapping for a single origin IP address. The IP path - parameter is normalized before lookup. Returns the deleted entry on success. - Returns 404 (code 1163) if no mapping exists for the specified IP. When the last - mapping for the zone is removed the underlying rule record is also deleted. + parameter is normalized before lookup. Returns the deleted IP on success. + Returns 404 if no mapping exists for the specified IP. When the last mapping for + the zone is removed the underlying rule record is also deleted. Args: zone_id: Identifier. @@ -628,9 +599,7 @@ async def delete( if not origin_ip: raise ValueError(f"Expected a non-empty value for `origin_ip` but received {origin_ip!r}") return await self._delete( - path_template( - "/zones/{zone_id}/cache/origin_cloud_regions/{origin_ip}", zone_id=zone_id, origin_ip=origin_ip - ), + path_template("/zones/{zone_id}/origin/cloud_regions/{origin_ip}", zone_id=zone_id, origin_ip=origin_ip), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -675,7 +644,7 @@ async def bulk_delete( if not zone_id: raise ValueError(f"Expected a non-empty value for `zone_id` but received {zone_id!r}") return await self._delete( - path_template("/zones/{zone_id}/cache/origin_cloud_regions/batch", zone_id=zone_id), + path_template("/zones/{zone_id}/origin/cloud_regions/batch", zone_id=zone_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -688,25 +657,27 @@ async def bulk_delete( ), ) - async def bulk_edit( + async def bulk_update( self, *, zone_id: str, - body: Iterable[origin_cloud_region_bulk_edit_params.Body], + body: Iterable[origin_cloud_region_bulk_update_params.Body], # 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[OriginCloudRegionBulkEditResponse]: - """Adds or updates up to 100 IP-to-cloud-region mappings in a single request. + ) -> Optional[OriginCloudRegionBulkUpdateResponse]: + """Upserts up to 100 IP-to-cloud-region mappings in a single request. - Each - item is validated independently — valid items are applied and invalid items are - returned in the `failed` array. The vendor and region for every item are - validated against the list from - `GET /zones/{zone_id}/cache/origin_cloud_regions/supported_regions`. + Items in the + request body are created or replaced; mappings not included in the request body + are preserved unchanged (this is a merge operation, not a full collection + replacement). Each item is validated independently — valid items are applied and + invalid items are returned in the `failed` array. The vendor and region for + every item are validated against the list from + `GET /zones/{zone_id}/origin/cloud_regions/supported_regions`. Args: zone_id: Identifier. @@ -721,84 +692,21 @@ async def bulk_edit( """ if not zone_id: raise ValueError(f"Expected a non-empty value for `zone_id` but received {zone_id!r}") - return await self._patch( - path_template("/zones/{zone_id}/cache/origin_cloud_regions/batch", zone_id=zone_id), - body=await async_maybe_transform(body, Iterable[origin_cloud_region_bulk_edit_params.Body]), + return await self._put( + path_template("/zones/{zone_id}/origin/cloud_regions/batch", zone_id=zone_id), + body=await async_maybe_transform(body, Iterable[origin_cloud_region_bulk_update_params.Body]), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[Optional[OriginCloudRegionBulkEditResponse]]._unwrapper, + post_parser=ResultWrapper[Optional[OriginCloudRegionBulkUpdateResponse]]._unwrapper, ), cast_to=cast( - Type[Optional[OriginCloudRegionBulkEditResponse]], ResultWrapper[OriginCloudRegionBulkEditResponse] + Type[Optional[OriginCloudRegionBulkUpdateResponse]], ResultWrapper[OriginCloudRegionBulkUpdateResponse] ), ) - async def edit( - self, - *, - zone_id: str, - ip: str, - region: str, - vendor: Literal["aws", "azure", "gcp", "oci"], - # 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[OriginCloudRegionEditResponse]: - """Adds or updates a single IP-to-cloud-region mapping for the zone. - - Unlike POST, - this operation is idempotent — if a mapping for the IP already exists it is - overwritten. Returns the complete updated list of all mappings for the zone. - Returns 403 (code 1164) when the zone has reached the limit of 3,500 IP - mappings. - - Args: - zone_id: Identifier. - - ip: Origin IP address (IPv4 or IPv6). Normalized to canonical form before storage - (RFC 5952 for IPv6). - - region: Cloud vendor region identifier. Must be a valid region for the specified vendor - as returned by the supported_regions endpoint. - - vendor: Cloud vendor hosting the origin. Must be one of the supported vendors. - - 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 zone_id: - raise ValueError(f"Expected a non-empty value for `zone_id` but received {zone_id!r}") - return await self._patch( - path_template("/zones/{zone_id}/cache/origin_cloud_regions", zone_id=zone_id), - body=await async_maybe_transform( - { - "ip": ip, - "region": region, - "vendor": vendor, - }, - origin_cloud_region_edit_params.OriginCloudRegionEditParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - post_parser=ResultWrapper[Optional[OriginCloudRegionEditResponse]]._unwrapper, - ), - cast_to=cast(Type[Optional[OriginCloudRegionEditResponse]], ResultWrapper[OriginCloudRegionEditResponse]), - ) - async def get( self, origin_ip: str, @@ -810,12 +718,12 @@ async def get( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Optional[OriginCloudRegionGetResponse]: + ) -> Optional[OriginCloudRegion]: """Returns the cloud region mapping for a single origin IP address. The IP path - parameter is normalized before lookup (RFC 5952 for IPv6). Returns 404 - (code 1142) if the zone has no mappings or if the specified IP has no mapping. + parameter is normalized before lookup (RFC 5952 for IPv6). Returns 404 if the + zone has no mappings or if the specified IP has no mapping. Args: zone_id: Identifier. @@ -833,17 +741,15 @@ async def get( if not origin_ip: raise ValueError(f"Expected a non-empty value for `origin_ip` but received {origin_ip!r}") return await self._get( - path_template( - "/zones/{zone_id}/cache/origin_cloud_regions/{origin_ip}", zone_id=zone_id, origin_ip=origin_ip - ), + path_template("/zones/{zone_id}/origin/cloud_regions/{origin_ip}", zone_id=zone_id, origin_ip=origin_ip), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout, - post_parser=ResultWrapper[Optional[OriginCloudRegionGetResponse]]._unwrapper, + post_parser=ResultWrapper[Optional[OriginCloudRegion]]._unwrapper, ), - cast_to=cast(Type[Optional[OriginCloudRegionGetResponse]], ResultWrapper[OriginCloudRegionGetResponse]), + cast_to=cast(Type[Optional[OriginCloudRegion]], ResultWrapper[OriginCloudRegion]), ) async def supported_regions( @@ -877,7 +783,7 @@ async def supported_regions( if not zone_id: raise ValueError(f"Expected a non-empty value for `zone_id` but received {zone_id!r}") return await self._get( - path_template("/zones/{zone_id}/cache/origin_cloud_regions/supported_regions", zone_id=zone_id), + path_template("/zones/{zone_id}/origin/cloud_regions/supported_regions", zone_id=zone_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -896,8 +802,8 @@ class OriginCloudRegionsResourceWithRawResponse: def __init__(self, origin_cloud_regions: OriginCloudRegionsResource) -> None: self._origin_cloud_regions = origin_cloud_regions - self.create = to_raw_response_wrapper( - origin_cloud_regions.create, + self.update = to_raw_response_wrapper( + origin_cloud_regions.update, ) self.list = to_raw_response_wrapper( origin_cloud_regions.list, @@ -908,11 +814,8 @@ def __init__(self, origin_cloud_regions: OriginCloudRegionsResource) -> None: self.bulk_delete = to_raw_response_wrapper( origin_cloud_regions.bulk_delete, ) - self.bulk_edit = to_raw_response_wrapper( - origin_cloud_regions.bulk_edit, - ) - self.edit = to_raw_response_wrapper( - origin_cloud_regions.edit, + self.bulk_update = to_raw_response_wrapper( + origin_cloud_regions.bulk_update, ) self.get = to_raw_response_wrapper( origin_cloud_regions.get, @@ -926,8 +829,8 @@ class AsyncOriginCloudRegionsResourceWithRawResponse: def __init__(self, origin_cloud_regions: AsyncOriginCloudRegionsResource) -> None: self._origin_cloud_regions = origin_cloud_regions - self.create = async_to_raw_response_wrapper( - origin_cloud_regions.create, + self.update = async_to_raw_response_wrapper( + origin_cloud_regions.update, ) self.list = async_to_raw_response_wrapper( origin_cloud_regions.list, @@ -938,11 +841,8 @@ def __init__(self, origin_cloud_regions: AsyncOriginCloudRegionsResource) -> Non self.bulk_delete = async_to_raw_response_wrapper( origin_cloud_regions.bulk_delete, ) - self.bulk_edit = async_to_raw_response_wrapper( - origin_cloud_regions.bulk_edit, - ) - self.edit = async_to_raw_response_wrapper( - origin_cloud_regions.edit, + self.bulk_update = async_to_raw_response_wrapper( + origin_cloud_regions.bulk_update, ) self.get = async_to_raw_response_wrapper( origin_cloud_regions.get, @@ -956,8 +856,8 @@ class OriginCloudRegionsResourceWithStreamingResponse: def __init__(self, origin_cloud_regions: OriginCloudRegionsResource) -> None: self._origin_cloud_regions = origin_cloud_regions - self.create = to_streamed_response_wrapper( - origin_cloud_regions.create, + self.update = to_streamed_response_wrapper( + origin_cloud_regions.update, ) self.list = to_streamed_response_wrapper( origin_cloud_regions.list, @@ -968,11 +868,8 @@ def __init__(self, origin_cloud_regions: OriginCloudRegionsResource) -> None: self.bulk_delete = to_streamed_response_wrapper( origin_cloud_regions.bulk_delete, ) - self.bulk_edit = to_streamed_response_wrapper( - origin_cloud_regions.bulk_edit, - ) - self.edit = to_streamed_response_wrapper( - origin_cloud_regions.edit, + self.bulk_update = to_streamed_response_wrapper( + origin_cloud_regions.bulk_update, ) self.get = to_streamed_response_wrapper( origin_cloud_regions.get, @@ -986,8 +883,8 @@ class AsyncOriginCloudRegionsResourceWithStreamingResponse: def __init__(self, origin_cloud_regions: AsyncOriginCloudRegionsResource) -> None: self._origin_cloud_regions = origin_cloud_regions - self.create = async_to_streamed_response_wrapper( - origin_cloud_regions.create, + self.update = async_to_streamed_response_wrapper( + origin_cloud_regions.update, ) self.list = async_to_streamed_response_wrapper( origin_cloud_regions.list, @@ -998,11 +895,8 @@ def __init__(self, origin_cloud_regions: AsyncOriginCloudRegionsResource) -> Non self.bulk_delete = async_to_streamed_response_wrapper( origin_cloud_regions.bulk_delete, ) - self.bulk_edit = async_to_streamed_response_wrapper( - origin_cloud_regions.bulk_edit, - ) - self.edit = async_to_streamed_response_wrapper( - origin_cloud_regions.edit, + self.bulk_update = async_to_streamed_response_wrapper( + origin_cloud_regions.bulk_update, ) self.get = async_to_streamed_response_wrapper( origin_cloud_regions.get, diff --git a/src/cloudflare/types/cache/__init__.py b/src/cloudflare/types/cache/__init__.py index a8c1ab90c62..ba43e7d63fc 100644 --- a/src/cloudflare/types/cache/__init__.py +++ b/src/cloudflare/types/cache/__init__.py @@ -20,26 +20,24 @@ from .cache_reserve_clear_response import CacheReserveClearResponse as CacheReserveClearResponse from .cache_reserve_status_response import CacheReserveStatusResponse as CacheReserveStatusResponse from .smart_tiered_cache_edit_params import SmartTieredCacheEditParams as SmartTieredCacheEditParams -from .origin_cloud_region_edit_params import OriginCloudRegionEditParams as OriginCloudRegionEditParams +from .origin_cloud_region_list_params import OriginCloudRegionListParams as OriginCloudRegionListParams from .smart_tiered_cache_get_response import SmartTieredCacheGetResponse as SmartTieredCacheGetResponse -from .origin_cloud_region_get_response import OriginCloudRegionGetResponse as OriginCloudRegionGetResponse from .smart_tiered_cache_edit_response import SmartTieredCacheEditResponse as SmartTieredCacheEditResponse -from .origin_cloud_region_create_params import OriginCloudRegionCreateParams as OriginCloudRegionCreateParams -from .origin_cloud_region_edit_response import OriginCloudRegionEditResponse as OriginCloudRegionEditResponse -from .origin_cloud_region_list_response import OriginCloudRegionListResponse as OriginCloudRegionListResponse +from .origin_cloud_region_update_params import OriginCloudRegionUpdateParams as OriginCloudRegionUpdateParams from .regional_tiered_cache_edit_params import RegionalTieredCacheEditParams as RegionalTieredCacheEditParams from .regional_tiered_cache_get_response import RegionalTieredCacheGetResponse as RegionalTieredCacheGetResponse from .smart_tiered_cache_delete_response import SmartTieredCacheDeleteResponse as SmartTieredCacheDeleteResponse -from .origin_cloud_region_create_response import OriginCloudRegionCreateResponse as OriginCloudRegionCreateResponse from .origin_cloud_region_delete_response import OriginCloudRegionDeleteResponse as OriginCloudRegionDeleteResponse from .regional_tiered_cache_edit_response import RegionalTieredCacheEditResponse as RegionalTieredCacheEditResponse -from .origin_cloud_region_bulk_edit_params import OriginCloudRegionBulkEditParams as OriginCloudRegionBulkEditParams -from .origin_cloud_region_bulk_edit_response import ( - OriginCloudRegionBulkEditResponse as OriginCloudRegionBulkEditResponse, +from .origin_cloud_region_bulk_update_params import ( + OriginCloudRegionBulkUpdateParams as OriginCloudRegionBulkUpdateParams, ) from .origin_cloud_region_bulk_delete_response import ( OriginCloudRegionBulkDeleteResponse as OriginCloudRegionBulkDeleteResponse, ) +from .origin_cloud_region_bulk_update_response import ( + OriginCloudRegionBulkUpdateResponse as OriginCloudRegionBulkUpdateResponse, +) from .origin_cloud_region_supported_regions_response import ( OriginCloudRegionSupportedRegionsResponse as OriginCloudRegionSupportedRegionsResponse, ) diff --git a/src/cloudflare/types/cache/origin_cloud_region.py b/src/cloudflare/types/cache/origin_cloud_region.py index 54afe283353..2e254f85cf2 100644 --- a/src/cloudflare/types/cache/origin_cloud_region.py +++ b/src/cloudflare/types/cache/origin_cloud_region.py @@ -4,8 +4,6 @@ from datetime import datetime from typing_extensions import Literal -from pydantic import Field as FieldInfo - from ..._models import BaseModel __all__ = ["OriginCloudRegion"] @@ -14,8 +12,11 @@ class OriginCloudRegion(BaseModel): """A single origin IP-to-cloud-region mapping.""" - origin_ip: str = FieldInfo(alias="origin-ip") - """The origin IP address (IPv4 or IPv6, canonicalized).""" + origin_ip: str + """The origin IP address (IPv4 or IPv6). + + Normalized to canonical form (RFC 5952 for IPv6). + """ region: str """Cloud vendor region identifier.""" diff --git a/src/cloudflare/types/cache/origin_cloud_region_bulk_delete_response.py b/src/cloudflare/types/cache/origin_cloud_region_bulk_delete_response.py index d5ea3f1b7d1..556b1e749d8 100644 --- a/src/cloudflare/types/cache/origin_cloud_region_bulk_delete_response.py +++ b/src/cloudflare/types/cache/origin_cloud_region_bulk_delete_response.py @@ -1,20 +1,16 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from typing import List, Optional -from datetime import datetime -from typing_extensions import Literal - -from pydantic import Field as FieldInfo from ..._models import BaseModel -__all__ = ["OriginCloudRegionBulkDeleteResponse", "Value", "ValueFailed", "ValueSucceeded"] +__all__ = ["OriginCloudRegionBulkDeleteResponse", "Failed", "Succeeded"] -class ValueFailed(BaseModel): +class Failed(BaseModel): """Result for a single item in a batch operation.""" - origin_ip: str = FieldInfo(alias="origin-ip") + origin_ip: str """The origin IP address for this item.""" error: Optional[str] = None @@ -23,17 +19,22 @@ class ValueFailed(BaseModel): region: Optional[str] = None """Cloud vendor region identifier. - Present on succeeded items for patch operations. + Present on succeeded items (the new value for upsert, the deleted value for + delete). """ vendor: Optional[str] = None - """Cloud vendor identifier. Present on succeeded items for patch operations.""" + """Cloud vendor identifier. + + Present on succeeded items (the new value for upsert, the deleted value for + delete). + """ -class ValueSucceeded(BaseModel): +class Succeeded(BaseModel): """Result for a single item in a batch operation.""" - origin_ip: str = FieldInfo(alias="origin-ip") + origin_ip: str """The origin IP address for this item.""" error: Optional[str] = None @@ -42,33 +43,23 @@ class ValueSucceeded(BaseModel): region: Optional[str] = None """Cloud vendor region identifier. - Present on succeeded items for patch operations. + Present on succeeded items (the new value for upsert, the deleted value for + delete). """ vendor: Optional[str] = None - """Cloud vendor identifier. Present on succeeded items for patch operations.""" - + """Cloud vendor identifier. -class Value(BaseModel): - failed: List[ValueFailed] - """Items that could not be applied, with error details.""" - - succeeded: List[ValueSucceeded] - """Items that were successfully applied.""" + Present on succeeded items (the new value for upsert, the deleted value for + delete). + """ class OriginCloudRegionBulkDeleteResponse(BaseModel): """Response result for a batch origin cloud region operation.""" - id: Literal["origin_public_cloud_region"] - - editable: bool - """Whether the setting can be modified by the current user.""" - - value: Value - - modified_on: Optional[datetime] = None - """Time the mapping set was last modified. + failed: List[Failed] + """Items that could not be applied, with error details.""" - Null when no items were successfully applied. - """ + succeeded: List[Succeeded] + """Items that were successfully applied.""" diff --git a/src/cloudflare/types/cache/origin_cloud_region_bulk_edit_response.py b/src/cloudflare/types/cache/origin_cloud_region_bulk_edit_response.py deleted file mode 100644 index 097de32e532..00000000000 --- a/src/cloudflare/types/cache/origin_cloud_region_bulk_edit_response.py +++ /dev/null @@ -1,74 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from datetime import datetime -from typing_extensions import Literal - -from pydantic import Field as FieldInfo - -from ..._models import BaseModel - -__all__ = ["OriginCloudRegionBulkEditResponse", "Value", "ValueFailed", "ValueSucceeded"] - - -class ValueFailed(BaseModel): - """Result for a single item in a batch operation.""" - - origin_ip: str = FieldInfo(alias="origin-ip") - """The origin IP address for this item.""" - - error: Optional[str] = None - """Error message explaining why the item failed. Present only on failed items.""" - - region: Optional[str] = None - """Cloud vendor region identifier. - - Present on succeeded items for patch operations. - """ - - vendor: Optional[str] = None - """Cloud vendor identifier. Present on succeeded items for patch operations.""" - - -class ValueSucceeded(BaseModel): - """Result for a single item in a batch operation.""" - - origin_ip: str = FieldInfo(alias="origin-ip") - """The origin IP address for this item.""" - - error: Optional[str] = None - """Error message explaining why the item failed. Present only on failed items.""" - - region: Optional[str] = None - """Cloud vendor region identifier. - - Present on succeeded items for patch operations. - """ - - vendor: Optional[str] = None - """Cloud vendor identifier. Present on succeeded items for patch operations.""" - - -class Value(BaseModel): - failed: List[ValueFailed] - """Items that could not be applied, with error details.""" - - succeeded: List[ValueSucceeded] - """Items that were successfully applied.""" - - -class OriginCloudRegionBulkEditResponse(BaseModel): - """Response result for a batch origin cloud region operation.""" - - id: Literal["origin_public_cloud_region"] - - editable: bool - """Whether the setting can be modified by the current user.""" - - value: Value - - modified_on: Optional[datetime] = None - """Time the mapping set was last modified. - - Null when no items were successfully applied. - """ diff --git a/src/cloudflare/types/cache/origin_cloud_region_bulk_edit_params.py b/src/cloudflare/types/cache/origin_cloud_region_bulk_update_params.py similarity index 59% rename from src/cloudflare/types/cache/origin_cloud_region_bulk_edit_params.py rename to src/cloudflare/types/cache/origin_cloud_region_bulk_update_params.py index c1edc6dc142..f8eaddf731a 100644 --- a/src/cloudflare/types/cache/origin_cloud_region_bulk_edit_params.py +++ b/src/cloudflare/types/cache/origin_cloud_region_bulk_update_params.py @@ -5,10 +5,10 @@ from typing import Iterable from typing_extensions import Literal, Required, TypedDict -__all__ = ["OriginCloudRegionBulkEditParams", "Body"] +__all__ = ["OriginCloudRegionBulkUpdateParams", "Body"] -class OriginCloudRegionBulkEditParams(TypedDict, total=False): +class OriginCloudRegionBulkUpdateParams(TypedDict, total=False): zone_id: Required[str] """Identifier.""" @@ -16,12 +16,15 @@ class OriginCloudRegionBulkEditParams(TypedDict, total=False): class Body(TypedDict, total=False): - """Request body for creating or updating an origin cloud region mapping.""" + """Request body for creating or replacing an origin cloud region mapping.""" - ip: Required[str] + origin_ip: Required[str] """Origin IP address (IPv4 or IPv6). - Normalized to canonical form before storage (RFC 5952 for IPv6). + For the single PUT endpoint (`PUT /origin/cloud_regions/{origin_ip}`), this + field must match the path parameter or the request will be rejected with a 400 + error. For the batch PUT endpoint, this field identifies which mapping to + upsert. """ region: Required[str] diff --git a/src/cloudflare/types/cache/origin_cloud_region_bulk_update_response.py b/src/cloudflare/types/cache/origin_cloud_region_bulk_update_response.py new file mode 100644 index 00000000000..7bce9f3f3fe --- /dev/null +++ b/src/cloudflare/types/cache/origin_cloud_region_bulk_update_response.py @@ -0,0 +1,65 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["OriginCloudRegionBulkUpdateResponse", "Failed", "Succeeded"] + + +class Failed(BaseModel): + """Result for a single item in a batch operation.""" + + origin_ip: str + """The origin IP address for this item.""" + + error: Optional[str] = None + """Error message explaining why the item failed. Present only on failed items.""" + + region: Optional[str] = None + """Cloud vendor region identifier. + + Present on succeeded items (the new value for upsert, the deleted value for + delete). + """ + + vendor: Optional[str] = None + """Cloud vendor identifier. + + Present on succeeded items (the new value for upsert, the deleted value for + delete). + """ + + +class Succeeded(BaseModel): + """Result for a single item in a batch operation.""" + + origin_ip: str + """The origin IP address for this item.""" + + error: Optional[str] = None + """Error message explaining why the item failed. Present only on failed items.""" + + region: Optional[str] = None + """Cloud vendor region identifier. + + Present on succeeded items (the new value for upsert, the deleted value for + delete). + """ + + vendor: Optional[str] = None + """Cloud vendor identifier. + + Present on succeeded items (the new value for upsert, the deleted value for + delete). + """ + + +class OriginCloudRegionBulkUpdateResponse(BaseModel): + """Response result for a batch origin cloud region operation.""" + + failed: List[Failed] + """Items that could not be applied, with error details.""" + + succeeded: List[Succeeded] + """Items that were successfully applied.""" diff --git a/src/cloudflare/types/cache/origin_cloud_region_create_params.py b/src/cloudflare/types/cache/origin_cloud_region_create_params.py deleted file mode 100644 index 001b5377dd7..00000000000 --- a/src/cloudflare/types/cache/origin_cloud_region_create_params.py +++ /dev/null @@ -1,28 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["OriginCloudRegionCreateParams"] - - -class OriginCloudRegionCreateParams(TypedDict, total=False): - zone_id: Required[str] - """Identifier.""" - - ip: Required[str] - """Origin IP address (IPv4 or IPv6). - - Normalized to canonical form before storage (RFC 5952 for IPv6). - """ - - region: Required[str] - """Cloud vendor region identifier. - - Must be a valid region for the specified vendor as returned by the - supported_regions endpoint. - """ - - vendor: Required[Literal["aws", "azure", "gcp", "oci"]] - """Cloud vendor hosting the origin. Must be one of the supported vendors.""" diff --git a/src/cloudflare/types/cache/origin_cloud_region_create_response.py b/src/cloudflare/types/cache/origin_cloud_region_create_response.py deleted file mode 100644 index 370d4051a68..00000000000 --- a/src/cloudflare/types/cache/origin_cloud_region_create_response.py +++ /dev/null @@ -1,25 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from datetime import datetime -from typing_extensions import Literal - -from ..._models import BaseModel -from .origin_cloud_region import OriginCloudRegion - -__all__ = ["OriginCloudRegionCreateResponse"] - - -class OriginCloudRegionCreateResponse(BaseModel): - """Response result for a single origin cloud region mapping.""" - - id: Literal["origin_public_cloud_region"] - - editable: bool - """Whether the setting can be modified by the current user.""" - - value: OriginCloudRegion - """A single origin IP-to-cloud-region mapping.""" - - modified_on: Optional[datetime] = None - """Time the mapping was last modified.""" diff --git a/src/cloudflare/types/cache/origin_cloud_region_delete_response.py b/src/cloudflare/types/cache/origin_cloud_region_delete_response.py index fb8012e50c7..8aec199f2f9 100644 --- a/src/cloudflare/types/cache/origin_cloud_region_delete_response.py +++ b/src/cloudflare/types/cache/origin_cloud_region_delete_response.py @@ -1,25 +1,12 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional -from datetime import datetime -from typing_extensions import Literal - from ..._models import BaseModel -from .origin_cloud_region import OriginCloudRegion __all__ = ["OriginCloudRegionDeleteResponse"] class OriginCloudRegionDeleteResponse(BaseModel): - """Response result for a single origin cloud region mapping.""" - - id: Literal["origin_public_cloud_region"] - - editable: bool - """Whether the setting can be modified by the current user.""" - - value: OriginCloudRegion - """A single origin IP-to-cloud-region mapping.""" + """Response result for a delete operation. Identifies the deleted mapping.""" - modified_on: Optional[datetime] = None - """Time the mapping was last modified.""" + origin_ip: str + """The origin IP address whose mapping was deleted.""" diff --git a/src/cloudflare/types/cache/origin_cloud_region_edit_response.py b/src/cloudflare/types/cache/origin_cloud_region_edit_response.py deleted file mode 100644 index d84400575d2..00000000000 --- a/src/cloudflare/types/cache/origin_cloud_region_edit_response.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from datetime import datetime -from typing_extensions import Literal - -from ..._models import BaseModel -from .origin_cloud_region import OriginCloudRegion - -__all__ = ["OriginCloudRegionEditResponse"] - - -class OriginCloudRegionEditResponse(BaseModel): - """Response result for a list of origin cloud region mappings.""" - - id: Literal["origin_public_cloud_region"] - - editable: bool - """Whether the setting can be modified by the current user.""" - - value: List[OriginCloudRegion] - - modified_on: Optional[datetime] = None - """Time the mapping set was last modified. Null when no mappings exist.""" diff --git a/src/cloudflare/types/cache/origin_cloud_region_get_response.py b/src/cloudflare/types/cache/origin_cloud_region_get_response.py deleted file mode 100644 index 1cb87ebebcf..00000000000 --- a/src/cloudflare/types/cache/origin_cloud_region_get_response.py +++ /dev/null @@ -1,25 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from datetime import datetime -from typing_extensions import Literal - -from ..._models import BaseModel -from .origin_cloud_region import OriginCloudRegion - -__all__ = ["OriginCloudRegionGetResponse"] - - -class OriginCloudRegionGetResponse(BaseModel): - """Response result for a single origin cloud region mapping.""" - - id: Literal["origin_public_cloud_region"] - - editable: bool - """Whether the setting can be modified by the current user.""" - - value: OriginCloudRegion - """A single origin IP-to-cloud-region mapping.""" - - modified_on: Optional[datetime] = None - """Time the mapping was last modified.""" diff --git a/src/cloudflare/types/cache/origin_cloud_region_list_params.py b/src/cloudflare/types/cache/origin_cloud_region_list_params.py new file mode 100644 index 00000000000..665c443d240 --- /dev/null +++ b/src/cloudflare/types/cache/origin_cloud_region_list_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["OriginCloudRegionListParams"] + + +class OriginCloudRegionListParams(TypedDict, total=False): + zone_id: Required[str] + """Identifier.""" + + page: int + """Page number of paginated results.""" + + per_page: int + """Number of items per page.""" diff --git a/src/cloudflare/types/cache/origin_cloud_region_list_response.py b/src/cloudflare/types/cache/origin_cloud_region_list_response.py deleted file mode 100644 index fc9fcf49a68..00000000000 --- a/src/cloudflare/types/cache/origin_cloud_region_list_response.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from datetime import datetime -from typing_extensions import Literal - -from ..._models import BaseModel -from .origin_cloud_region import OriginCloudRegion - -__all__ = ["OriginCloudRegionListResponse"] - - -class OriginCloudRegionListResponse(BaseModel): - """Response result for a list of origin cloud region mappings.""" - - id: Literal["origin_public_cloud_region"] - - editable: bool - """Whether the setting can be modified by the current user.""" - - value: List[OriginCloudRegion] - - modified_on: Optional[datetime] = None - """Time the mapping set was last modified. Null when no mappings exist.""" diff --git a/src/cloudflare/types/cache/origin_cloud_region_edit_params.py b/src/cloudflare/types/cache/origin_cloud_region_update_params.py similarity index 50% rename from src/cloudflare/types/cache/origin_cloud_region_edit_params.py rename to src/cloudflare/types/cache/origin_cloud_region_update_params.py index 270268f630a..cc8a9e813a6 100644 --- a/src/cloudflare/types/cache/origin_cloud_region_edit_params.py +++ b/src/cloudflare/types/cache/origin_cloud_region_update_params.py @@ -2,19 +2,24 @@ from __future__ import annotations -from typing_extensions import Literal, Required, TypedDict +from typing_extensions import Literal, Required, Annotated, TypedDict -__all__ = ["OriginCloudRegionEditParams"] +from ..._utils import PropertyInfo +__all__ = ["OriginCloudRegionUpdateParams"] -class OriginCloudRegionEditParams(TypedDict, total=False): + +class OriginCloudRegionUpdateParams(TypedDict, total=False): zone_id: Required[str] """Identifier.""" - ip: Required[str] + body_origin_ip: Required[Annotated[str, PropertyInfo(alias="origin_ip")]] """Origin IP address (IPv4 or IPv6). - Normalized to canonical form before storage (RFC 5952 for IPv6). + For the single PUT endpoint (`PUT /origin/cloud_regions/{origin_ip}`), this + field must match the path parameter or the request will be rejected with a 400 + error. For the batch PUT endpoint, this field identifies which mapping to + upsert. """ region: Required[str] diff --git a/tests/api_resources/cache/test_origin_cloud_regions.py b/tests/api_resources/cache/test_origin_cloud_regions.py index 53a5c9bf953..61d8a033aa9 100644 --- a/tests/api_resources/cache/test_origin_cloud_regions.py +++ b/tests/api_resources/cache/test_origin_cloud_regions.py @@ -9,14 +9,12 @@ from cloudflare import Cloudflare, AsyncCloudflare from tests.utils import assert_matches_type +from cloudflare.pagination import SyncV4PagePaginationArray, AsyncV4PagePaginationArray from cloudflare.types.cache import ( - OriginCloudRegionGetResponse, - OriginCloudRegionEditResponse, - OriginCloudRegionListResponse, - OriginCloudRegionCreateResponse, + OriginCloudRegion, OriginCloudRegionDeleteResponse, - OriginCloudRegionBulkEditResponse, OriginCloudRegionBulkDeleteResponse, + OriginCloudRegionBulkUpdateResponse, OriginCloudRegionSupportedRegionsResponse, ) @@ -27,20 +25,22 @@ class TestOriginCloudRegions: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) @parametrize - def test_method_create(self, client: Cloudflare) -> None: - origin_cloud_region = client.cache.origin_cloud_regions.create( + def test_method_update(self, client: Cloudflare) -> None: + origin_cloud_region = client.cache.origin_cloud_regions.update( + path_origin_ip="192.0.2.1", zone_id="023e105f4ecef8ad9ca31a8372d0c353", - ip="192.0.2.1", + body_origin_ip="192.0.2.1", region="us-east-1", vendor="aws", ) - assert_matches_type(Optional[OriginCloudRegionCreateResponse], origin_cloud_region, path=["response"]) + assert_matches_type(Optional[OriginCloudRegion], origin_cloud_region, path=["response"]) @parametrize - def test_raw_response_create(self, client: Cloudflare) -> None: - response = client.cache.origin_cloud_regions.with_raw_response.create( + def test_raw_response_update(self, client: Cloudflare) -> None: + response = client.cache.origin_cloud_regions.with_raw_response.update( + path_origin_ip="192.0.2.1", zone_id="023e105f4ecef8ad9ca31a8372d0c353", - ip="192.0.2.1", + body_origin_ip="192.0.2.1", region="us-east-1", vendor="aws", ) @@ -48,13 +48,14 @@ def test_raw_response_create(self, client: Cloudflare) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" origin_cloud_region = response.parse() - assert_matches_type(Optional[OriginCloudRegionCreateResponse], origin_cloud_region, path=["response"]) + assert_matches_type(Optional[OriginCloudRegion], origin_cloud_region, path=["response"]) @parametrize - def test_streaming_response_create(self, client: Cloudflare) -> None: - with client.cache.origin_cloud_regions.with_streaming_response.create( + def test_streaming_response_update(self, client: Cloudflare) -> None: + with client.cache.origin_cloud_regions.with_streaming_response.update( + path_origin_ip="192.0.2.1", zone_id="023e105f4ecef8ad9ca31a8372d0c353", - ip="192.0.2.1", + body_origin_ip="192.0.2.1", region="us-east-1", vendor="aws", ) as response: @@ -62,16 +63,26 @@ def test_streaming_response_create(self, client: Cloudflare) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" origin_cloud_region = response.parse() - assert_matches_type(Optional[OriginCloudRegionCreateResponse], origin_cloud_region, path=["response"]) + assert_matches_type(Optional[OriginCloudRegion], origin_cloud_region, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize - def test_path_params_create(self, client: Cloudflare) -> None: + def test_path_params_update(self, client: Cloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `zone_id` but received ''"): - client.cache.origin_cloud_regions.with_raw_response.create( + client.cache.origin_cloud_regions.with_raw_response.update( + path_origin_ip="192.0.2.1", zone_id="", - ip="192.0.2.1", + body_origin_ip="192.0.2.1", + region="us-east-1", + vendor="aws", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `path_origin_ip` but received ''"): + client.cache.origin_cloud_regions.with_raw_response.update( + path_origin_ip="", + zone_id="023e105f4ecef8ad9ca31a8372d0c353", + body_origin_ip="192.0.2.1", region="us-east-1", vendor="aws", ) @@ -81,7 +92,16 @@ def test_method_list(self, client: Cloudflare) -> None: origin_cloud_region = client.cache.origin_cloud_regions.list( zone_id="023e105f4ecef8ad9ca31a8372d0c353", ) - assert_matches_type(Optional[OriginCloudRegionListResponse], origin_cloud_region, path=["response"]) + assert_matches_type(SyncV4PagePaginationArray[OriginCloudRegion], origin_cloud_region, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Cloudflare) -> None: + origin_cloud_region = client.cache.origin_cloud_regions.list( + zone_id="023e105f4ecef8ad9ca31a8372d0c353", + page=1, + per_page=1, + ) + assert_matches_type(SyncV4PagePaginationArray[OriginCloudRegion], origin_cloud_region, path=["response"]) @parametrize def test_raw_response_list(self, client: Cloudflare) -> None: @@ -92,7 +112,7 @@ def test_raw_response_list(self, client: Cloudflare) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" origin_cloud_region = response.parse() - assert_matches_type(Optional[OriginCloudRegionListResponse], origin_cloud_region, path=["response"]) + assert_matches_type(SyncV4PagePaginationArray[OriginCloudRegion], origin_cloud_region, path=["response"]) @parametrize def test_streaming_response_list(self, client: Cloudflare) -> None: @@ -103,7 +123,7 @@ def test_streaming_response_list(self, client: Cloudflare) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" origin_cloud_region = response.parse() - assert_matches_type(Optional[OriginCloudRegionListResponse], origin_cloud_region, path=["response"]) + assert_matches_type(SyncV4PagePaginationArray[OriginCloudRegion], origin_cloud_region, path=["response"]) assert cast(Any, response.is_closed) is True @@ -201,36 +221,36 @@ def test_path_params_bulk_delete(self, client: Cloudflare) -> None: ) @parametrize - def test_method_bulk_edit(self, client: Cloudflare) -> None: - origin_cloud_region = client.cache.origin_cloud_regions.bulk_edit( + def test_method_bulk_update(self, client: Cloudflare) -> None: + origin_cloud_region = client.cache.origin_cloud_regions.bulk_update( zone_id="023e105f4ecef8ad9ca31a8372d0c353", body=[ { - "ip": "192.0.2.1", + "origin_ip": "192.0.2.1", "region": "us-east-1", "vendor": "aws", }, { - "ip": "2001:db8::1", + "origin_ip": "2001:db8::1", "region": "us-central1", "vendor": "gcp", }, ], ) - assert_matches_type(Optional[OriginCloudRegionBulkEditResponse], origin_cloud_region, path=["response"]) + assert_matches_type(Optional[OriginCloudRegionBulkUpdateResponse], origin_cloud_region, path=["response"]) @parametrize - def test_raw_response_bulk_edit(self, client: Cloudflare) -> None: - response = client.cache.origin_cloud_regions.with_raw_response.bulk_edit( + def test_raw_response_bulk_update(self, client: Cloudflare) -> None: + response = client.cache.origin_cloud_regions.with_raw_response.bulk_update( zone_id="023e105f4ecef8ad9ca31a8372d0c353", body=[ { - "ip": "192.0.2.1", + "origin_ip": "192.0.2.1", "region": "us-east-1", "vendor": "aws", }, { - "ip": "2001:db8::1", + "origin_ip": "2001:db8::1", "region": "us-central1", "vendor": "gcp", }, @@ -240,20 +260,20 @@ def test_raw_response_bulk_edit(self, client: Cloudflare) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" origin_cloud_region = response.parse() - assert_matches_type(Optional[OriginCloudRegionBulkEditResponse], origin_cloud_region, path=["response"]) + assert_matches_type(Optional[OriginCloudRegionBulkUpdateResponse], origin_cloud_region, path=["response"]) @parametrize - def test_streaming_response_bulk_edit(self, client: Cloudflare) -> None: - with client.cache.origin_cloud_regions.with_streaming_response.bulk_edit( + def test_streaming_response_bulk_update(self, client: Cloudflare) -> None: + with client.cache.origin_cloud_regions.with_streaming_response.bulk_update( zone_id="023e105f4ecef8ad9ca31a8372d0c353", body=[ { - "ip": "192.0.2.1", + "origin_ip": "192.0.2.1", "region": "us-east-1", "vendor": "aws", }, { - "ip": "2001:db8::1", + "origin_ip": "2001:db8::1", "region": "us-central1", "vendor": "gcp", }, @@ -263,86 +283,36 @@ def test_streaming_response_bulk_edit(self, client: Cloudflare) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" origin_cloud_region = response.parse() - assert_matches_type(Optional[OriginCloudRegionBulkEditResponse], origin_cloud_region, path=["response"]) + assert_matches_type(Optional[OriginCloudRegionBulkUpdateResponse], origin_cloud_region, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize - def test_path_params_bulk_edit(self, client: Cloudflare) -> None: + def test_path_params_bulk_update(self, client: Cloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `zone_id` but received ''"): - client.cache.origin_cloud_regions.with_raw_response.bulk_edit( + client.cache.origin_cloud_regions.with_raw_response.bulk_update( zone_id="", body=[ { - "ip": "192.0.2.1", + "origin_ip": "192.0.2.1", "region": "us-east-1", "vendor": "aws", }, { - "ip": "2001:db8::1", + "origin_ip": "2001:db8::1", "region": "us-central1", "vendor": "gcp", }, ], ) - @parametrize - def test_method_edit(self, client: Cloudflare) -> None: - origin_cloud_region = client.cache.origin_cloud_regions.edit( - zone_id="023e105f4ecef8ad9ca31a8372d0c353", - ip="2001:db8::1", - region="us-central1", - vendor="gcp", - ) - assert_matches_type(Optional[OriginCloudRegionEditResponse], origin_cloud_region, path=["response"]) - - @parametrize - def test_raw_response_edit(self, client: Cloudflare) -> None: - response = client.cache.origin_cloud_regions.with_raw_response.edit( - zone_id="023e105f4ecef8ad9ca31a8372d0c353", - ip="2001:db8::1", - region="us-central1", - vendor="gcp", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - origin_cloud_region = response.parse() - assert_matches_type(Optional[OriginCloudRegionEditResponse], origin_cloud_region, path=["response"]) - - @parametrize - def test_streaming_response_edit(self, client: Cloudflare) -> None: - with client.cache.origin_cloud_regions.with_streaming_response.edit( - zone_id="023e105f4ecef8ad9ca31a8372d0c353", - ip="2001:db8::1", - region="us-central1", - vendor="gcp", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - origin_cloud_region = response.parse() - assert_matches_type(Optional[OriginCloudRegionEditResponse], origin_cloud_region, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_edit(self, client: Cloudflare) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `zone_id` but received ''"): - client.cache.origin_cloud_regions.with_raw_response.edit( - zone_id="", - ip="2001:db8::1", - region="us-central1", - vendor="gcp", - ) - @parametrize def test_method_get(self, client: Cloudflare) -> None: origin_cloud_region = client.cache.origin_cloud_regions.get( origin_ip="192.0.2.1", zone_id="023e105f4ecef8ad9ca31a8372d0c353", ) - assert_matches_type(Optional[OriginCloudRegionGetResponse], origin_cloud_region, path=["response"]) + assert_matches_type(Optional[OriginCloudRegion], origin_cloud_region, path=["response"]) @parametrize def test_raw_response_get(self, client: Cloudflare) -> None: @@ -354,7 +324,7 @@ def test_raw_response_get(self, client: Cloudflare) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" origin_cloud_region = response.parse() - assert_matches_type(Optional[OriginCloudRegionGetResponse], origin_cloud_region, path=["response"]) + assert_matches_type(Optional[OriginCloudRegion], origin_cloud_region, path=["response"]) @parametrize def test_streaming_response_get(self, client: Cloudflare) -> None: @@ -366,7 +336,7 @@ def test_streaming_response_get(self, client: Cloudflare) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" origin_cloud_region = response.parse() - assert_matches_type(Optional[OriginCloudRegionGetResponse], origin_cloud_region, path=["response"]) + assert_matches_type(Optional[OriginCloudRegion], origin_cloud_region, path=["response"]) assert cast(Any, response.is_closed) is True @@ -431,20 +401,22 @@ class TestAsyncOriginCloudRegions: ) @parametrize - async def test_method_create(self, async_client: AsyncCloudflare) -> None: - origin_cloud_region = await async_client.cache.origin_cloud_regions.create( + async def test_method_update(self, async_client: AsyncCloudflare) -> None: + origin_cloud_region = await async_client.cache.origin_cloud_regions.update( + path_origin_ip="192.0.2.1", zone_id="023e105f4ecef8ad9ca31a8372d0c353", - ip="192.0.2.1", + body_origin_ip="192.0.2.1", region="us-east-1", vendor="aws", ) - assert_matches_type(Optional[OriginCloudRegionCreateResponse], origin_cloud_region, path=["response"]) + assert_matches_type(Optional[OriginCloudRegion], origin_cloud_region, path=["response"]) @parametrize - async def test_raw_response_create(self, async_client: AsyncCloudflare) -> None: - response = await async_client.cache.origin_cloud_regions.with_raw_response.create( + async def test_raw_response_update(self, async_client: AsyncCloudflare) -> None: + response = await async_client.cache.origin_cloud_regions.with_raw_response.update( + path_origin_ip="192.0.2.1", zone_id="023e105f4ecef8ad9ca31a8372d0c353", - ip="192.0.2.1", + body_origin_ip="192.0.2.1", region="us-east-1", vendor="aws", ) @@ -452,13 +424,14 @@ async def test_raw_response_create(self, async_client: AsyncCloudflare) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" origin_cloud_region = await response.parse() - assert_matches_type(Optional[OriginCloudRegionCreateResponse], origin_cloud_region, path=["response"]) + assert_matches_type(Optional[OriginCloudRegion], origin_cloud_region, path=["response"]) @parametrize - async def test_streaming_response_create(self, async_client: AsyncCloudflare) -> None: - async with async_client.cache.origin_cloud_regions.with_streaming_response.create( + async def test_streaming_response_update(self, async_client: AsyncCloudflare) -> None: + async with async_client.cache.origin_cloud_regions.with_streaming_response.update( + path_origin_ip="192.0.2.1", zone_id="023e105f4ecef8ad9ca31a8372d0c353", - ip="192.0.2.1", + body_origin_ip="192.0.2.1", region="us-east-1", vendor="aws", ) as response: @@ -466,16 +439,26 @@ async def test_streaming_response_create(self, async_client: AsyncCloudflare) -> assert response.http_request.headers.get("X-Stainless-Lang") == "python" origin_cloud_region = await response.parse() - assert_matches_type(Optional[OriginCloudRegionCreateResponse], origin_cloud_region, path=["response"]) + assert_matches_type(Optional[OriginCloudRegion], origin_cloud_region, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize - async def test_path_params_create(self, async_client: AsyncCloudflare) -> None: + async def test_path_params_update(self, async_client: AsyncCloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `zone_id` but received ''"): - await async_client.cache.origin_cloud_regions.with_raw_response.create( + await async_client.cache.origin_cloud_regions.with_raw_response.update( + path_origin_ip="192.0.2.1", zone_id="", - ip="192.0.2.1", + body_origin_ip="192.0.2.1", + region="us-east-1", + vendor="aws", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `path_origin_ip` but received ''"): + await async_client.cache.origin_cloud_regions.with_raw_response.update( + path_origin_ip="", + zone_id="023e105f4ecef8ad9ca31a8372d0c353", + body_origin_ip="192.0.2.1", region="us-east-1", vendor="aws", ) @@ -485,7 +468,16 @@ async def test_method_list(self, async_client: AsyncCloudflare) -> None: origin_cloud_region = await async_client.cache.origin_cloud_regions.list( zone_id="023e105f4ecef8ad9ca31a8372d0c353", ) - assert_matches_type(Optional[OriginCloudRegionListResponse], origin_cloud_region, path=["response"]) + assert_matches_type(AsyncV4PagePaginationArray[OriginCloudRegion], origin_cloud_region, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncCloudflare) -> None: + origin_cloud_region = await async_client.cache.origin_cloud_regions.list( + zone_id="023e105f4ecef8ad9ca31a8372d0c353", + page=1, + per_page=1, + ) + assert_matches_type(AsyncV4PagePaginationArray[OriginCloudRegion], origin_cloud_region, path=["response"]) @parametrize async def test_raw_response_list(self, async_client: AsyncCloudflare) -> None: @@ -496,7 +488,7 @@ async def test_raw_response_list(self, async_client: AsyncCloudflare) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" origin_cloud_region = await response.parse() - assert_matches_type(Optional[OriginCloudRegionListResponse], origin_cloud_region, path=["response"]) + assert_matches_type(AsyncV4PagePaginationArray[OriginCloudRegion], origin_cloud_region, path=["response"]) @parametrize async def test_streaming_response_list(self, async_client: AsyncCloudflare) -> None: @@ -507,7 +499,7 @@ async def test_streaming_response_list(self, async_client: AsyncCloudflare) -> N assert response.http_request.headers.get("X-Stainless-Lang") == "python" origin_cloud_region = await response.parse() - assert_matches_type(Optional[OriginCloudRegionListResponse], origin_cloud_region, path=["response"]) + assert_matches_type(AsyncV4PagePaginationArray[OriginCloudRegion], origin_cloud_region, path=["response"]) assert cast(Any, response.is_closed) is True @@ -605,36 +597,36 @@ async def test_path_params_bulk_delete(self, async_client: AsyncCloudflare) -> N ) @parametrize - async def test_method_bulk_edit(self, async_client: AsyncCloudflare) -> None: - origin_cloud_region = await async_client.cache.origin_cloud_regions.bulk_edit( + async def test_method_bulk_update(self, async_client: AsyncCloudflare) -> None: + origin_cloud_region = await async_client.cache.origin_cloud_regions.bulk_update( zone_id="023e105f4ecef8ad9ca31a8372d0c353", body=[ { - "ip": "192.0.2.1", + "origin_ip": "192.0.2.1", "region": "us-east-1", "vendor": "aws", }, { - "ip": "2001:db8::1", + "origin_ip": "2001:db8::1", "region": "us-central1", "vendor": "gcp", }, ], ) - assert_matches_type(Optional[OriginCloudRegionBulkEditResponse], origin_cloud_region, path=["response"]) + assert_matches_type(Optional[OriginCloudRegionBulkUpdateResponse], origin_cloud_region, path=["response"]) @parametrize - async def test_raw_response_bulk_edit(self, async_client: AsyncCloudflare) -> None: - response = await async_client.cache.origin_cloud_regions.with_raw_response.bulk_edit( + async def test_raw_response_bulk_update(self, async_client: AsyncCloudflare) -> None: + response = await async_client.cache.origin_cloud_regions.with_raw_response.bulk_update( zone_id="023e105f4ecef8ad9ca31a8372d0c353", body=[ { - "ip": "192.0.2.1", + "origin_ip": "192.0.2.1", "region": "us-east-1", "vendor": "aws", }, { - "ip": "2001:db8::1", + "origin_ip": "2001:db8::1", "region": "us-central1", "vendor": "gcp", }, @@ -644,20 +636,20 @@ async def test_raw_response_bulk_edit(self, async_client: AsyncCloudflare) -> No assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" origin_cloud_region = await response.parse() - assert_matches_type(Optional[OriginCloudRegionBulkEditResponse], origin_cloud_region, path=["response"]) + assert_matches_type(Optional[OriginCloudRegionBulkUpdateResponse], origin_cloud_region, path=["response"]) @parametrize - async def test_streaming_response_bulk_edit(self, async_client: AsyncCloudflare) -> None: - async with async_client.cache.origin_cloud_regions.with_streaming_response.bulk_edit( + async def test_streaming_response_bulk_update(self, async_client: AsyncCloudflare) -> None: + async with async_client.cache.origin_cloud_regions.with_streaming_response.bulk_update( zone_id="023e105f4ecef8ad9ca31a8372d0c353", body=[ { - "ip": "192.0.2.1", + "origin_ip": "192.0.2.1", "region": "us-east-1", "vendor": "aws", }, { - "ip": "2001:db8::1", + "origin_ip": "2001:db8::1", "region": "us-central1", "vendor": "gcp", }, @@ -667,86 +659,36 @@ async def test_streaming_response_bulk_edit(self, async_client: AsyncCloudflare) assert response.http_request.headers.get("X-Stainless-Lang") == "python" origin_cloud_region = await response.parse() - assert_matches_type(Optional[OriginCloudRegionBulkEditResponse], origin_cloud_region, path=["response"]) + assert_matches_type(Optional[OriginCloudRegionBulkUpdateResponse], origin_cloud_region, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize - async def test_path_params_bulk_edit(self, async_client: AsyncCloudflare) -> None: + async def test_path_params_bulk_update(self, async_client: AsyncCloudflare) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `zone_id` but received ''"): - await async_client.cache.origin_cloud_regions.with_raw_response.bulk_edit( + await async_client.cache.origin_cloud_regions.with_raw_response.bulk_update( zone_id="", body=[ { - "ip": "192.0.2.1", + "origin_ip": "192.0.2.1", "region": "us-east-1", "vendor": "aws", }, { - "ip": "2001:db8::1", + "origin_ip": "2001:db8::1", "region": "us-central1", "vendor": "gcp", }, ], ) - @parametrize - async def test_method_edit(self, async_client: AsyncCloudflare) -> None: - origin_cloud_region = await async_client.cache.origin_cloud_regions.edit( - zone_id="023e105f4ecef8ad9ca31a8372d0c353", - ip="2001:db8::1", - region="us-central1", - vendor="gcp", - ) - assert_matches_type(Optional[OriginCloudRegionEditResponse], origin_cloud_region, path=["response"]) - - @parametrize - async def test_raw_response_edit(self, async_client: AsyncCloudflare) -> None: - response = await async_client.cache.origin_cloud_regions.with_raw_response.edit( - zone_id="023e105f4ecef8ad9ca31a8372d0c353", - ip="2001:db8::1", - region="us-central1", - vendor="gcp", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - origin_cloud_region = await response.parse() - assert_matches_type(Optional[OriginCloudRegionEditResponse], origin_cloud_region, path=["response"]) - - @parametrize - async def test_streaming_response_edit(self, async_client: AsyncCloudflare) -> None: - async with async_client.cache.origin_cloud_regions.with_streaming_response.edit( - zone_id="023e105f4ecef8ad9ca31a8372d0c353", - ip="2001:db8::1", - region="us-central1", - vendor="gcp", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - origin_cloud_region = await response.parse() - assert_matches_type(Optional[OriginCloudRegionEditResponse], origin_cloud_region, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_edit(self, async_client: AsyncCloudflare) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `zone_id` but received ''"): - await async_client.cache.origin_cloud_regions.with_raw_response.edit( - zone_id="", - ip="2001:db8::1", - region="us-central1", - vendor="gcp", - ) - @parametrize async def test_method_get(self, async_client: AsyncCloudflare) -> None: origin_cloud_region = await async_client.cache.origin_cloud_regions.get( origin_ip="192.0.2.1", zone_id="023e105f4ecef8ad9ca31a8372d0c353", ) - assert_matches_type(Optional[OriginCloudRegionGetResponse], origin_cloud_region, path=["response"]) + assert_matches_type(Optional[OriginCloudRegion], origin_cloud_region, path=["response"]) @parametrize async def test_raw_response_get(self, async_client: AsyncCloudflare) -> None: @@ -758,7 +700,7 @@ async def test_raw_response_get(self, async_client: AsyncCloudflare) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" origin_cloud_region = await response.parse() - assert_matches_type(Optional[OriginCloudRegionGetResponse], origin_cloud_region, path=["response"]) + assert_matches_type(Optional[OriginCloudRegion], origin_cloud_region, path=["response"]) @parametrize async def test_streaming_response_get(self, async_client: AsyncCloudflare) -> None: @@ -770,7 +712,7 @@ async def test_streaming_response_get(self, async_client: AsyncCloudflare) -> No assert response.http_request.headers.get("X-Stainless-Lang") == "python" origin_cloud_region = await response.parse() - assert_matches_type(Optional[OriginCloudRegionGetResponse], origin_cloud_region, path=["response"]) + assert_matches_type(Optional[OriginCloudRegion], origin_cloud_region, path=["response"]) assert cast(Any, response.is_closed) is True From 80ce92d4ffb060f761a2fce8c4da08ff03fc3e9c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 5 May 2026 16:32:15 +0000 Subject: [PATCH 39/45] chore(api): update composite API spec --- .stats.yml | 2 +- .../resource_sharing/resource_sharing.py | 16 +++++++++++++++- .../resource_sharing_list_params.py | 11 +++++++++++ tests/api_resources/test_resource_sharing.py | 2 ++ 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 518292c201d..1a4b35d36af 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 2208 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a6c352830d1270d0abb5bb983058ea21815e1bb7d2e163965335dcb0e706f057.yml -openapi_spec_hash: 42dd4ac0ac3f5c00bbe80e26fed2fa51 +openapi_spec_hash: 1cb07cbc59f51be4843f63ea4357d7f2 config_hash: 0c33107d28fc9d1d5726d8ac8459421a diff --git a/src/cloudflare/resources/resource_sharing/resource_sharing.py b/src/cloudflare/resources/resource_sharing/resource_sharing.py index fc3a665fd7d..5fb90fb418a 100644 --- a/src/cloudflare/resources/resource_sharing/resource_sharing.py +++ b/src/cloudflare/resources/resource_sharing/resource_sharing.py @@ -7,7 +7,7 @@ import httpx -from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given from ..._utils import path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from .resources import ( @@ -203,6 +203,7 @@ def list( ] | Omit = omit, status: Literal["active", "deleting", "deleted"] | Omit = omit, + tag: SequenceNotStr[str] | Omit = omit, target_type: Literal["account", "organization"] | Omit = omit, # 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. @@ -235,6 +236,11 @@ def list( status: Filter shares by status. + tag: Filter shares by tag. Each value is either `key=value` (matches shares whose + tags contain that key/value pair) or `key` alone (matches shares that have any + value for that key). May be repeated; multiple `tag` parameters are ANDed + together. Maximum 20 `tag` parameters per request. + target_type: Filter shares by target_type. extra_headers: Send extra headers @@ -266,6 +272,7 @@ def list( "per_page": per_page, "resource_types": resource_types, "status": status, + "tag": tag, "target_type": target_type, }, resource_sharing_list_params.ResourceSharingListParams, @@ -531,6 +538,7 @@ def list( ] | Omit = omit, status: Literal["active", "deleting", "deleted"] | Omit = omit, + tag: SequenceNotStr[str] | Omit = omit, target_type: Literal["account", "organization"] | Omit = omit, # 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. @@ -563,6 +571,11 @@ def list( status: Filter shares by status. + tag: Filter shares by tag. Each value is either `key=value` (matches shares whose + tags contain that key/value pair) or `key` alone (matches shares that have any + value for that key). May be repeated; multiple `tag` parameters are ANDed + together. Maximum 20 `tag` parameters per request. + target_type: Filter shares by target_type. extra_headers: Send extra headers @@ -594,6 +607,7 @@ def list( "per_page": per_page, "resource_types": resource_types, "status": status, + "tag": tag, "target_type": target_type, }, resource_sharing_list_params.ResourceSharingListParams, diff --git a/src/cloudflare/types/resource_sharing/resource_sharing_list_params.py b/src/cloudflare/types/resource_sharing/resource_sharing_list_params.py index 5b96649e2c3..6984b782c2e 100644 --- a/src/cloudflare/types/resource_sharing/resource_sharing_list_params.py +++ b/src/cloudflare/types/resource_sharing/resource_sharing_list_params.py @@ -5,6 +5,8 @@ from typing import List from typing_extensions import Literal, Required, TypedDict +from ..._types import SequenceNotStr + __all__ = ["ResourceSharingListParams"] @@ -47,5 +49,14 @@ class ResourceSharingListParams(TypedDict, total=False): status: Literal["active", "deleting", "deleted"] """Filter shares by status.""" + tag: SequenceNotStr[str] + """Filter shares by tag. + + Each value is either `key=value` (matches shares whose tags contain that + key/value pair) or `key` alone (matches shares that have any value for that + key). May be repeated; multiple `tag` parameters are ANDed together. Maximum 20 + `tag` parameters per request. + """ + target_type: Literal["account", "organization"] """Filter shares by target_type.""" diff --git a/tests/api_resources/test_resource_sharing.py b/tests/api_resources/test_resource_sharing.py index 879e6040c9b..c6f74647ef4 100644 --- a/tests/api_resources/test_resource_sharing.py +++ b/tests/api_resources/test_resource_sharing.py @@ -175,6 +175,7 @@ def test_method_list_with_all_params(self, client: Cloudflare) -> None: per_page=20, resource_types=["custom-ruleset"], status="active", + tag=["env=production"], target_type="account", ) assert_matches_type(SyncV4PagePaginationArray[ResourceSharingListResponse], resource_sharing, path=["response"]) @@ -477,6 +478,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncCloudflare) per_page=20, resource_types=["custom-ruleset"], status="active", + tag=["env=production"], target_type="account", ) assert_matches_type( From 7d03cf2593e27d270fb1e3b1770c52110c1a8978 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 5 May 2026 17:09:19 +0000 Subject: [PATCH 40/45] chore(api): update composite API spec --- .stats.yml | 2 +- src/cloudflare/types/user/user_edit_response.py | 5 ++++- src/cloudflare/types/user/user_get_response.py | 5 ++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.stats.yml b/.stats.yml index 1a4b35d36af..5ac595f61a1 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 2208 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a6c352830d1270d0abb5bb983058ea21815e1bb7d2e163965335dcb0e706f057.yml -openapi_spec_hash: 1cb07cbc59f51be4843f63ea4357d7f2 +openapi_spec_hash: 43b3282cc17b94e7729c724d6a3c67ae config_hash: 0c33107d28fc9d1d5726d8ac8459421a diff --git a/src/cloudflare/types/user/user_edit_response.py b/src/cloudflare/types/user/user_edit_response.py index c273145becf..be3722d9da3 100644 --- a/src/cloudflare/types/user/user_edit_response.py +++ b/src/cloudflare/types/user/user_edit_response.py @@ -9,9 +9,12 @@ class UserEditResponse(BaseModel): - id: Optional[str] = None + id: str """Identifier of the user.""" + email: str + """Current email address of the user.""" + betas: Optional[List[str]] = None """Lists the betas that the user is participating in.""" diff --git a/src/cloudflare/types/user/user_get_response.py b/src/cloudflare/types/user/user_get_response.py index dae3cff17b6..a04ec9f8646 100644 --- a/src/cloudflare/types/user/user_get_response.py +++ b/src/cloudflare/types/user/user_get_response.py @@ -9,9 +9,12 @@ class UserGetResponse(BaseModel): - id: Optional[str] = None + id: str """Identifier of the user.""" + email: str + """Current email address of the user.""" + betas: Optional[List[str]] = None """Lists the betas that the user is participating in.""" From 854a77c9e1ff9a50f82f34afe2cc0d0e5975a558 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 5 May 2026 21:22:17 +0000 Subject: [PATCH 41/45] feat: feat(cache): add create (POST) method for smart_tiered_cache MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(cache): add create (POST) method for smart_tiered_cache Add the missing create method to smart_tiered_cache subresource. The POST endpoint for tiered_cache_smart_topology_enable was already in the api-gateway but missing from the Stainless config. Removes the internal-only endpoints (cache_limit_rate, cache_reserve_jurisdiction, class_of_service) from the original APIX-592 MR — these have no api-gateway routes and are not customer-facing. Closes CACHE-13445 --- .stats.yml | 4 +- src/cloudflare/resources/cache/api.md | 2 + .../resources/cache/smart_tiered_cache.py | 113 +++++++++++++++++- src/cloudflare/types/cache/__init__.py | 2 + .../cache/smart_tiered_cache_create_params.py | 15 +++ .../smart_tiered_cache_create_response.py | 23 ++++ .../cache/test_smart_tiered_cache.py | 85 +++++++++++++ 7 files changed, 241 insertions(+), 3 deletions(-) create mode 100644 src/cloudflare/types/cache/smart_tiered_cache_create_params.py create mode 100644 src/cloudflare/types/cache/smart_tiered_cache_create_response.py diff --git a/.stats.yml b/.stats.yml index 5ac595f61a1..d4a2f2e6c39 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 2208 +configured_endpoints: 2209 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a6c352830d1270d0abb5bb983058ea21815e1bb7d2e163965335dcb0e706f057.yml openapi_spec_hash: 43b3282cc17b94e7729c724d6a3c67ae -config_hash: 0c33107d28fc9d1d5726d8ac8459421a +config_hash: 25d6458459b0af390a57abd94fb34218 diff --git a/src/cloudflare/resources/cache/api.md b/src/cloudflare/resources/cache/api.md index 8b743a99a82..7b2d130b5f4 100644 --- a/src/cloudflare/resources/cache/api.md +++ b/src/cloudflare/resources/cache/api.md @@ -39,6 +39,7 @@ Types: ```python from cloudflare.types.cache import ( + SmartTieredCacheCreateResponse, SmartTieredCacheDeleteResponse, SmartTieredCacheEditResponse, SmartTieredCacheGetResponse, @@ -47,6 +48,7 @@ from cloudflare.types.cache import ( Methods: +- client.cache.smart_tiered_cache.create(\*, zone_id, \*\*params) -> Optional[SmartTieredCacheCreateResponse] - client.cache.smart_tiered_cache.delete(\*, zone_id) -> Optional[SmartTieredCacheDeleteResponse] - client.cache.smart_tiered_cache.edit(\*, zone_id, \*\*params) -> Optional[SmartTieredCacheEditResponse] - client.cache.smart_tiered_cache.get(\*, zone_id) -> Optional[SmartTieredCacheGetResponse] diff --git a/src/cloudflare/resources/cache/smart_tiered_cache.py b/src/cloudflare/resources/cache/smart_tiered_cache.py index ce23d7d3c3e..fe272d3765b 100644 --- a/src/cloudflare/resources/cache/smart_tiered_cache.py +++ b/src/cloudflare/resources/cache/smart_tiered_cache.py @@ -18,10 +18,11 @@ async_to_streamed_response_wrapper, ) from ..._wrappers import ResultWrapper -from ...types.cache import smart_tiered_cache_edit_params +from ...types.cache import smart_tiered_cache_edit_params, smart_tiered_cache_create_params from ..._base_client import make_request_options from ...types.cache.smart_tiered_cache_get_response import SmartTieredCacheGetResponse from ...types.cache.smart_tiered_cache_edit_response import SmartTieredCacheEditResponse +from ...types.cache.smart_tiered_cache_create_response import SmartTieredCacheCreateResponse from ...types.cache.smart_tiered_cache_delete_response import SmartTieredCacheDeleteResponse __all__ = ["SmartTieredCacheResource", "AsyncSmartTieredCacheResource"] @@ -47,6 +48,54 @@ def with_streaming_response(self) -> SmartTieredCacheResourceWithStreamingRespon """ return SmartTieredCacheResourceWithStreamingResponse(self) + def create( + self, + *, + zone_id: str, + value: Literal["on", "off"], + # 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[SmartTieredCacheCreateResponse]: + """ + Smart Tiered Cache dynamically selects the single closest upper tier for each of + your website's origins with no configuration required, using our in-house + performance and routing data. Cloudflare collects latency data for each request + to an origin, and uses the latency data to determine how well any upper-tier + data center is connected with an origin. As a result, Cloudflare can select the + data center with the lowest latency to be the upper-tier for an origin. + + Args: + zone_id: Identifier. + + value: Enable or disable the Smart Tiered Cache. + + 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 zone_id: + raise ValueError(f"Expected a non-empty value for `zone_id` but received {zone_id!r}") + return self._post( + path_template("/zones/{zone_id}/cache/tiered_cache_smart_topology_enable", zone_id=zone_id), + body=maybe_transform({"value": value}, smart_tiered_cache_create_params.SmartTieredCacheCreateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[Optional[SmartTieredCacheCreateResponse]]._unwrapper, + ), + cast_to=cast(Type[Optional[SmartTieredCacheCreateResponse]], ResultWrapper[SmartTieredCacheCreateResponse]), + ) + def delete( self, *, @@ -204,6 +253,56 @@ def with_streaming_response(self) -> AsyncSmartTieredCacheResourceWithStreamingR """ return AsyncSmartTieredCacheResourceWithStreamingResponse(self) + async def create( + self, + *, + zone_id: str, + value: Literal["on", "off"], + # 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[SmartTieredCacheCreateResponse]: + """ + Smart Tiered Cache dynamically selects the single closest upper tier for each of + your website's origins with no configuration required, using our in-house + performance and routing data. Cloudflare collects latency data for each request + to an origin, and uses the latency data to determine how well any upper-tier + data center is connected with an origin. As a result, Cloudflare can select the + data center with the lowest latency to be the upper-tier for an origin. + + Args: + zone_id: Identifier. + + value: Enable or disable the Smart Tiered Cache. + + 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 zone_id: + raise ValueError(f"Expected a non-empty value for `zone_id` but received {zone_id!r}") + return await self._post( + path_template("/zones/{zone_id}/cache/tiered_cache_smart_topology_enable", zone_id=zone_id), + body=await async_maybe_transform( + {"value": value}, smart_tiered_cache_create_params.SmartTieredCacheCreateParams + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + post_parser=ResultWrapper[Optional[SmartTieredCacheCreateResponse]]._unwrapper, + ), + cast_to=cast(Type[Optional[SmartTieredCacheCreateResponse]], ResultWrapper[SmartTieredCacheCreateResponse]), + ) + async def delete( self, *, @@ -347,6 +446,9 @@ class SmartTieredCacheResourceWithRawResponse: def __init__(self, smart_tiered_cache: SmartTieredCacheResource) -> None: self._smart_tiered_cache = smart_tiered_cache + self.create = to_raw_response_wrapper( + smart_tiered_cache.create, + ) self.delete = to_raw_response_wrapper( smart_tiered_cache.delete, ) @@ -362,6 +464,9 @@ class AsyncSmartTieredCacheResourceWithRawResponse: def __init__(self, smart_tiered_cache: AsyncSmartTieredCacheResource) -> None: self._smart_tiered_cache = smart_tiered_cache + self.create = async_to_raw_response_wrapper( + smart_tiered_cache.create, + ) self.delete = async_to_raw_response_wrapper( smart_tiered_cache.delete, ) @@ -377,6 +482,9 @@ class SmartTieredCacheResourceWithStreamingResponse: def __init__(self, smart_tiered_cache: SmartTieredCacheResource) -> None: self._smart_tiered_cache = smart_tiered_cache + self.create = to_streamed_response_wrapper( + smart_tiered_cache.create, + ) self.delete = to_streamed_response_wrapper( smart_tiered_cache.delete, ) @@ -392,6 +500,9 @@ class AsyncSmartTieredCacheResourceWithStreamingResponse: def __init__(self, smart_tiered_cache: AsyncSmartTieredCacheResource) -> None: self._smart_tiered_cache = smart_tiered_cache + self.create = async_to_streamed_response_wrapper( + smart_tiered_cache.create, + ) self.delete = async_to_streamed_response_wrapper( smart_tiered_cache.delete, ) diff --git a/src/cloudflare/types/cache/__init__.py b/src/cloudflare/types/cache/__init__.py index ba43e7d63fc..a0d0d26a181 100644 --- a/src/cloudflare/types/cache/__init__.py +++ b/src/cloudflare/types/cache/__init__.py @@ -22,10 +22,12 @@ from .smart_tiered_cache_edit_params import SmartTieredCacheEditParams as SmartTieredCacheEditParams from .origin_cloud_region_list_params import OriginCloudRegionListParams as OriginCloudRegionListParams from .smart_tiered_cache_get_response import SmartTieredCacheGetResponse as SmartTieredCacheGetResponse +from .smart_tiered_cache_create_params import SmartTieredCacheCreateParams as SmartTieredCacheCreateParams from .smart_tiered_cache_edit_response import SmartTieredCacheEditResponse as SmartTieredCacheEditResponse from .origin_cloud_region_update_params import OriginCloudRegionUpdateParams as OriginCloudRegionUpdateParams from .regional_tiered_cache_edit_params import RegionalTieredCacheEditParams as RegionalTieredCacheEditParams from .regional_tiered_cache_get_response import RegionalTieredCacheGetResponse as RegionalTieredCacheGetResponse +from .smart_tiered_cache_create_response import SmartTieredCacheCreateResponse as SmartTieredCacheCreateResponse from .smart_tiered_cache_delete_response import SmartTieredCacheDeleteResponse as SmartTieredCacheDeleteResponse from .origin_cloud_region_delete_response import OriginCloudRegionDeleteResponse as OriginCloudRegionDeleteResponse from .regional_tiered_cache_edit_response import RegionalTieredCacheEditResponse as RegionalTieredCacheEditResponse diff --git a/src/cloudflare/types/cache/smart_tiered_cache_create_params.py b/src/cloudflare/types/cache/smart_tiered_cache_create_params.py new file mode 100644 index 00000000000..83ca7c702fa --- /dev/null +++ b/src/cloudflare/types/cache/smart_tiered_cache_create_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["SmartTieredCacheCreateParams"] + + +class SmartTieredCacheCreateParams(TypedDict, total=False): + zone_id: Required[str] + """Identifier.""" + + value: Required[Literal["on", "off"]] + """Enable or disable the Smart Tiered Cache.""" diff --git a/src/cloudflare/types/cache/smart_tiered_cache_create_response.py b/src/cloudflare/types/cache/smart_tiered_cache_create_response.py new file mode 100644 index 00000000000..67cc88ded15 --- /dev/null +++ b/src/cloudflare/types/cache/smart_tiered_cache_create_response.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["SmartTieredCacheCreateResponse"] + + +class SmartTieredCacheCreateResponse(BaseModel): + id: Literal["tiered_cache_smart_topology_enable"] + """The identifier of the caching setting.""" + + editable: bool + """Whether the setting is editable.""" + + value: Literal["on", "off"] + """Value of the Smart Tiered Cache zone setting.""" + + modified_on: Optional[datetime] = None + """Last time this setting was modified.""" diff --git a/tests/api_resources/cache/test_smart_tiered_cache.py b/tests/api_resources/cache/test_smart_tiered_cache.py index 3457741e5fe..df662413fd1 100644 --- a/tests/api_resources/cache/test_smart_tiered_cache.py +++ b/tests/api_resources/cache/test_smart_tiered_cache.py @@ -12,6 +12,7 @@ from cloudflare.types.cache import ( SmartTieredCacheGetResponse, SmartTieredCacheEditResponse, + SmartTieredCacheCreateResponse, SmartTieredCacheDeleteResponse, ) @@ -21,6 +22,48 @@ class TestSmartTieredCache: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + @parametrize + def test_method_create(self, client: Cloudflare) -> None: + smart_tiered_cache = client.cache.smart_tiered_cache.create( + zone_id="023e105f4ecef8ad9ca31a8372d0c353", + value="on", + ) + assert_matches_type(Optional[SmartTieredCacheCreateResponse], smart_tiered_cache, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Cloudflare) -> None: + response = client.cache.smart_tiered_cache.with_raw_response.create( + zone_id="023e105f4ecef8ad9ca31a8372d0c353", + value="on", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + smart_tiered_cache = response.parse() + assert_matches_type(Optional[SmartTieredCacheCreateResponse], smart_tiered_cache, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Cloudflare) -> None: + with client.cache.smart_tiered_cache.with_streaming_response.create( + zone_id="023e105f4ecef8ad9ca31a8372d0c353", + value="on", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + smart_tiered_cache = response.parse() + assert_matches_type(Optional[SmartTieredCacheCreateResponse], smart_tiered_cache, 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 `zone_id` but received ''"): + client.cache.smart_tiered_cache.with_raw_response.create( + zone_id="", + value="on", + ) + @parametrize def test_method_delete(self, client: Cloudflare) -> None: smart_tiered_cache = client.cache.smart_tiered_cache.delete( @@ -145,6 +188,48 @@ class TestAsyncSmartTieredCache: "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] ) + @parametrize + async def test_method_create(self, async_client: AsyncCloudflare) -> None: + smart_tiered_cache = await async_client.cache.smart_tiered_cache.create( + zone_id="023e105f4ecef8ad9ca31a8372d0c353", + value="on", + ) + assert_matches_type(Optional[SmartTieredCacheCreateResponse], smart_tiered_cache, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncCloudflare) -> None: + response = await async_client.cache.smart_tiered_cache.with_raw_response.create( + zone_id="023e105f4ecef8ad9ca31a8372d0c353", + value="on", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + smart_tiered_cache = await response.parse() + assert_matches_type(Optional[SmartTieredCacheCreateResponse], smart_tiered_cache, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncCloudflare) -> None: + async with async_client.cache.smart_tiered_cache.with_streaming_response.create( + zone_id="023e105f4ecef8ad9ca31a8372d0c353", + value="on", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + smart_tiered_cache = await response.parse() + assert_matches_type(Optional[SmartTieredCacheCreateResponse], smart_tiered_cache, 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 `zone_id` but received ''"): + await async_client.cache.smart_tiered_cache.with_raw_response.create( + zone_id="", + value="on", + ) + @parametrize async def test_method_delete(self, async_client: AsyncCloudflare) -> None: smart_tiered_cache = await async_client.cache.smart_tiered_cache.delete( From 1fc2411a8246dd13ace62495a3adb8847f77493d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 5 May 2026 21:32:30 +0000 Subject: [PATCH 42/45] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index d4a2f2e6c39..bc63e5a7789 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 2209 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a6c352830d1270d0abb5bb983058ea21815e1bb7d2e163965335dcb0e706f057.yml openapi_spec_hash: 43b3282cc17b94e7729c724d6a3c67ae -config_hash: 25d6458459b0af390a57abd94fb34218 +config_hash: 738e0c7378ea7821d530b044c332db9e From bda722635c0c99747486e38e8c23a422cca71774 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 5 May 2026 21:40:07 +0000 Subject: [PATCH 43/45] feat: feat(radar): add BGP RPKI ROAs timeseries and BGP IPs top ASes endpoints * feat(radar): add BGP RPKI ROAs timeseries and BGP IPs top ASes endpoints - Add /radar/bgp/rpki/roas/timeseries - Add /radar/bgp/ips/top/ases RADAR-7051 --- .stats.yml | 4 +- src/cloudflare/resources/radar/api.md | 26 +- src/cloudflare/resources/radar/bgp/bgp.py | 16 +- .../resources/radar/bgp/ips/__init__.py | 33 +++ .../resources/radar/bgp/{ => ips}/ips.py | 50 +++- src/cloudflare/resources/radar/bgp/ips/top.py | 226 +++++++++++++++ .../resources/radar/bgp/rpki/__init__.py | 14 + .../resources/radar/bgp/rpki/roas.py | 272 ++++++++++++++++++ .../resources/radar/bgp/rpki/rpki.py | 32 +++ .../types/radar/bgp/ips/__init__.py | 6 + .../types/radar/bgp/ips/top_ases_params.py | 28 ++ .../types/radar/bgp/ips/top_ases_response.py | 28 ++ .../types/radar/bgp/rpki/__init__.py | 2 + .../radar/bgp/rpki/roa_timeseries_params.py | 49 ++++ .../radar/bgp/rpki/roa_timeseries_response.py | 30 ++ tests/api_resources/radar/bgp/ips/__init__.py | 1 + tests/api_resources/radar/bgp/ips/test_top.py | 97 +++++++ .../api_resources/radar/bgp/rpki/test_roas.py | 101 +++++++ 18 files changed, 995 insertions(+), 20 deletions(-) create mode 100644 src/cloudflare/resources/radar/bgp/ips/__init__.py rename src/cloudflare/resources/radar/bgp/{ => ips}/ips.py (87%) create mode 100644 src/cloudflare/resources/radar/bgp/ips/top.py create mode 100644 src/cloudflare/resources/radar/bgp/rpki/roas.py create mode 100644 src/cloudflare/types/radar/bgp/ips/__init__.py create mode 100644 src/cloudflare/types/radar/bgp/ips/top_ases_params.py create mode 100644 src/cloudflare/types/radar/bgp/ips/top_ases_response.py create mode 100644 src/cloudflare/types/radar/bgp/rpki/roa_timeseries_params.py create mode 100644 src/cloudflare/types/radar/bgp/rpki/roa_timeseries_response.py create mode 100644 tests/api_resources/radar/bgp/ips/__init__.py create mode 100644 tests/api_resources/radar/bgp/ips/test_top.py create mode 100644 tests/api_resources/radar/bgp/rpki/test_roas.py diff --git a/.stats.yml b/.stats.yml index bc63e5a7789..2413cda3e2e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 2209 +configured_endpoints: 2211 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a6c352830d1270d0abb5bb983058ea21815e1bb7d2e163965335dcb0e706f057.yml openapi_spec_hash: 43b3282cc17b94e7729c724d6a3c67ae -config_hash: 738e0c7378ea7821d530b044c332db9e +config_hash: 82bd9683d33d942855962bb7dc595067 diff --git a/src/cloudflare/resources/radar/api.md b/src/cloudflare/resources/radar/api.md index 1b322eb9563..30ab46a98ad 100644 --- a/src/cloudflare/resources/radar/api.md +++ b/src/cloudflare/resources/radar/api.md @@ -305,7 +305,19 @@ from cloudflare.types.radar.bgp import IPTimeseriesResponse Methods: -- client.radar.bgp.ips.timeseries(\*\*params) -> IPTimeseriesResponse +- client.radar.bgp.ips.timeseries(\*\*params) -> IPTimeseriesResponse + +#### Top + +Types: + +```python +from cloudflare.types.radar.bgp.ips import TopAsesResponse +``` + +Methods: + +- client.radar.bgp.ips.top.ases(\*\*params) -> TopAsesResponse ### RPKI @@ -327,6 +339,18 @@ Methods: - client.radar.bgp.rpki.aspa.snapshot(\*\*params) -> ASPASnapshotResponse - client.radar.bgp.rpki.aspa.timeseries(\*\*params) -> ASPATimeseriesResponse +#### Roas + +Types: + +```python +from cloudflare.types.radar.bgp.rpki import RoaTimeseriesResponse +``` + +Methods: + +- client.radar.bgp.rpki.roas.timeseries(\*\*params) -> RoaTimeseriesResponse + ## Bots Types: diff --git a/src/cloudflare/resources/radar/bgp/bgp.py b/src/cloudflare/resources/radar/bgp/bgp.py index d4d93f61538..f84cb3d137f 100644 --- a/src/cloudflare/resources/radar/bgp/bgp.py +++ b/src/cloudflare/resources/radar/bgp/bgp.py @@ -8,14 +8,6 @@ import httpx -from .ips import ( - IPsResource, - AsyncIPsResource, - IPsResourceWithRawResponse, - AsyncIPsResourceWithRawResponse, - IPsResourceWithStreamingResponse, - AsyncIPsResourceWithStreamingResponse, -) from .routes import ( RoutesResource, AsyncRoutesResource, @@ -24,6 +16,14 @@ RoutesResourceWithStreamingResponse, AsyncRoutesResourceWithStreamingResponse, ) +from .ips.ips import ( + IPsResource, + AsyncIPsResource, + IPsResourceWithRawResponse, + AsyncIPsResourceWithRawResponse, + IPsResourceWithStreamingResponse, + AsyncIPsResourceWithStreamingResponse, +) from .top.top import ( TopResource, AsyncTopResource, diff --git a/src/cloudflare/resources/radar/bgp/ips/__init__.py b/src/cloudflare/resources/radar/bgp/ips/__init__.py new file mode 100644 index 00000000000..7fb6d08dcd8 --- /dev/null +++ b/src/cloudflare/resources/radar/bgp/ips/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .ips import ( + IPsResource, + AsyncIPsResource, + IPsResourceWithRawResponse, + AsyncIPsResourceWithRawResponse, + IPsResourceWithStreamingResponse, + AsyncIPsResourceWithStreamingResponse, +) +from .top import ( + TopResource, + AsyncTopResource, + TopResourceWithRawResponse, + AsyncTopResourceWithRawResponse, + TopResourceWithStreamingResponse, + AsyncTopResourceWithStreamingResponse, +) + +__all__ = [ + "TopResource", + "AsyncTopResource", + "TopResourceWithRawResponse", + "AsyncTopResourceWithRawResponse", + "TopResourceWithStreamingResponse", + "AsyncTopResourceWithStreamingResponse", + "IPsResource", + "AsyncIPsResource", + "IPsResourceWithRawResponse", + "AsyncIPsResourceWithRawResponse", + "IPsResourceWithStreamingResponse", + "AsyncIPsResourceWithStreamingResponse", +] diff --git a/src/cloudflare/resources/radar/bgp/ips.py b/src/cloudflare/resources/radar/bgp/ips/ips.py similarity index 87% rename from src/cloudflare/resources/radar/bgp/ips.py rename to src/cloudflare/resources/radar/bgp/ips/ips.py index ed5d5aa4891..1cb8186841d 100644 --- a/src/cloudflare/resources/radar/bgp/ips.py +++ b/src/cloudflare/resources/radar/bgp/ips/ips.py @@ -8,25 +8,37 @@ import httpx -from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given -from ...._utils import maybe_transform, async_maybe_transform -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import ( +from .top import ( + TopResource, + AsyncTopResource, + TopResourceWithRawResponse, + AsyncTopResourceWithRawResponse, + TopResourceWithStreamingResponse, + AsyncTopResourceWithStreamingResponse, +) +from ....._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +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 ...._base_client import make_request_options -from ....types.radar.bgp import ip_timeseries_params -from ....types.radar.bgp.ip_timeseries_response import IPTimeseriesResponse +from ....._wrappers import ResultWrapper +from ....._base_client import make_request_options +from .....types.radar.bgp import ip_timeseries_params +from .....types.radar.bgp.ip_timeseries_response import IPTimeseriesResponse __all__ = ["IPsResource", "AsyncIPsResource"] class IPsResource(SyncAPIResource): + @cached_property + def top(self) -> TopResource: + return TopResource(self._client) + @cached_property def with_raw_response(self) -> IPsResourceWithRawResponse: """ @@ -130,6 +142,10 @@ def timeseries( class AsyncIPsResource(AsyncAPIResource): + @cached_property + def top(self) -> AsyncTopResource: + return AsyncTopResource(self._client) + @cached_property def with_raw_response(self) -> AsyncIPsResourceWithRawResponse: """ @@ -240,6 +256,10 @@ def __init__(self, ips: IPsResource) -> None: ips.timeseries, ) + @cached_property + def top(self) -> TopResourceWithRawResponse: + return TopResourceWithRawResponse(self._ips.top) + class AsyncIPsResourceWithRawResponse: def __init__(self, ips: AsyncIPsResource) -> None: @@ -249,6 +269,10 @@ def __init__(self, ips: AsyncIPsResource) -> None: ips.timeseries, ) + @cached_property + def top(self) -> AsyncTopResourceWithRawResponse: + return AsyncTopResourceWithRawResponse(self._ips.top) + class IPsResourceWithStreamingResponse: def __init__(self, ips: IPsResource) -> None: @@ -258,6 +282,10 @@ def __init__(self, ips: IPsResource) -> None: ips.timeseries, ) + @cached_property + def top(self) -> TopResourceWithStreamingResponse: + return TopResourceWithStreamingResponse(self._ips.top) + class AsyncIPsResourceWithStreamingResponse: def __init__(self, ips: AsyncIPsResource) -> None: @@ -266,3 +294,7 @@ def __init__(self, ips: AsyncIPsResource) -> None: self.timeseries = async_to_streamed_response_wrapper( ips.timeseries, ) + + @cached_property + def top(self) -> AsyncTopResourceWithStreamingResponse: + return AsyncTopResourceWithStreamingResponse(self._ips.top) diff --git a/src/cloudflare/resources/radar/bgp/ips/top.py b/src/cloudflare/resources/radar/bgp/ips/top.py new file mode 100644 index 00000000000..692b17c1fc5 --- /dev/null +++ b/src/cloudflare/resources/radar/bgp/ips/top.py @@ -0,0 +1,226 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Type, Union, cast +from datetime import datetime +from typing_extensions import Literal + +import httpx + +from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +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 ....._base_client import make_request_options +from .....types.radar.bgp.ips import top_ases_params +from .....types.radar.bgp.ips.top_ases_response import TopAsesResponse + +__all__ = ["TopResource", "AsyncTopResource"] + + +class TopResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> TopResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 TopResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> TopResourceWithStreamingResponse: + """ + 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 TopResourceWithStreamingResponse(self) + + def ases( + self, + *, + country: str | Omit = omit, + date: Union[str, datetime] | Omit = omit, + format: Literal["JSON", "CSV"] | Omit = omit, + limit: int | Omit = omit, + metric: Literal["v4_24s", "v6_48s"] | Omit = omit, + # 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, + ) -> TopAsesResponse: + """ + Returns the top-N autonomous systems by announced IP space at the nearest 8-hour + RIB boundary at or before the requested date. The snapped boundary is returned + as `anchor_ts`. + + Args: + country: Optional ISO 3166-1 alpha-2 country filter. Omit for global top-N. + + date: Filters results by the specified datetime (ISO 8601). + + format: Format in which results will be returned. + + limit: Limits the number of objects returned in the response. + + metric: Ranking metric: IPv4 /24 count or IPv6 /48 count. + + 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 + """ + return self._get( + "/radar/bgp/ips/top/ases", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "country": country, + "date": date, + "format": format, + "limit": limit, + "metric": metric, + }, + top_ases_params.TopAsesParams, + ), + post_parser=ResultWrapper[TopAsesResponse]._unwrapper, + ), + cast_to=cast(Type[TopAsesResponse], ResultWrapper[TopAsesResponse]), + ) + + +class AsyncTopResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncTopResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 AsyncTopResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncTopResourceWithStreamingResponse: + """ + 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 AsyncTopResourceWithStreamingResponse(self) + + async def ases( + self, + *, + country: str | Omit = omit, + date: Union[str, datetime] | Omit = omit, + format: Literal["JSON", "CSV"] | Omit = omit, + limit: int | Omit = omit, + metric: Literal["v4_24s", "v6_48s"] | Omit = omit, + # 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, + ) -> TopAsesResponse: + """ + Returns the top-N autonomous systems by announced IP space at the nearest 8-hour + RIB boundary at or before the requested date. The snapped boundary is returned + as `anchor_ts`. + + Args: + country: Optional ISO 3166-1 alpha-2 country filter. Omit for global top-N. + + date: Filters results by the specified datetime (ISO 8601). + + format: Format in which results will be returned. + + limit: Limits the number of objects returned in the response. + + metric: Ranking metric: IPv4 /24 count or IPv6 /48 count. + + 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 + """ + return await self._get( + "/radar/bgp/ips/top/ases", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "country": country, + "date": date, + "format": format, + "limit": limit, + "metric": metric, + }, + top_ases_params.TopAsesParams, + ), + post_parser=ResultWrapper[TopAsesResponse]._unwrapper, + ), + cast_to=cast(Type[TopAsesResponse], ResultWrapper[TopAsesResponse]), + ) + + +class TopResourceWithRawResponse: + def __init__(self, top: TopResource) -> None: + self._top = top + + self.ases = to_raw_response_wrapper( + top.ases, + ) + + +class AsyncTopResourceWithRawResponse: + def __init__(self, top: AsyncTopResource) -> None: + self._top = top + + self.ases = async_to_raw_response_wrapper( + top.ases, + ) + + +class TopResourceWithStreamingResponse: + def __init__(self, top: TopResource) -> None: + self._top = top + + self.ases = to_streamed_response_wrapper( + top.ases, + ) + + +class AsyncTopResourceWithStreamingResponse: + def __init__(self, top: AsyncTopResource) -> None: + self._top = top + + self.ases = async_to_streamed_response_wrapper( + top.ases, + ) diff --git a/src/cloudflare/resources/radar/bgp/rpki/__init__.py b/src/cloudflare/resources/radar/bgp/rpki/__init__.py index 824bd86d5d1..c09318d6d8b 100644 --- a/src/cloudflare/resources/radar/bgp/rpki/__init__.py +++ b/src/cloudflare/resources/radar/bgp/rpki/__init__.py @@ -8,6 +8,14 @@ ASPAResourceWithStreamingResponse, AsyncASPAResourceWithStreamingResponse, ) +from .roas import ( + RoasResource, + AsyncRoasResource, + RoasResourceWithRawResponse, + AsyncRoasResourceWithRawResponse, + RoasResourceWithStreamingResponse, + AsyncRoasResourceWithStreamingResponse, +) from .rpki import ( RPKIResource, AsyncRPKIResource, @@ -24,6 +32,12 @@ "AsyncASPAResourceWithRawResponse", "ASPAResourceWithStreamingResponse", "AsyncASPAResourceWithStreamingResponse", + "RoasResource", + "AsyncRoasResource", + "RoasResourceWithRawResponse", + "AsyncRoasResourceWithRawResponse", + "RoasResourceWithStreamingResponse", + "AsyncRoasResourceWithStreamingResponse", "RPKIResource", "AsyncRPKIResource", "RPKIResourceWithRawResponse", diff --git a/src/cloudflare/resources/radar/bgp/rpki/roas.py b/src/cloudflare/resources/radar/bgp/rpki/roas.py new file mode 100644 index 00000000000..7e69251d192 --- /dev/null +++ b/src/cloudflare/resources/radar/bgp/rpki/roas.py @@ -0,0 +1,272 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Type, Union, cast +from datetime import datetime +from typing_extensions import Literal + +import httpx + +from ....._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +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 ....._base_client import make_request_options +from .....types.radar.bgp.rpki import roa_timeseries_params +from .....types.radar.bgp.rpki.roa_timeseries_response import RoaTimeseriesResponse + +__all__ = ["RoasResource", "AsyncRoasResource"] + + +class RoasResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> RoasResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 RoasResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> RoasResourceWithStreamingResponse: + """ + 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 RoasResourceWithStreamingResponse(self) + + def timeseries( + self, + *, + asn: SequenceNotStr[str] | Omit = omit, + date_end: Union[str, datetime] | Omit = omit, + date_start: Union[str, datetime] | Omit = omit, + format: Literal["JSON", "CSV"] | Omit = omit, + location: SequenceNotStr[str] | Omit = omit, + metric: Literal[ + "validPfxsRatio", + "validPfxsV4Ratio", + "validPfxsV6Ratio", + "validIpsRatio", + "validIpsV4Ratio", + "validIpsV6Ratio", + ] + | Omit = omit, + name: SequenceNotStr[str] | Omit = omit, + # 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, + ) -> RoaTimeseriesResponse: + """ + Retrieves RPKI ROA (Route Origin Authorization) validation ratios over time. + Returns the selected metric as a time series. Supports filtering by ASN or + location (country code) — multiple values of the same filter type produce one + series per value. If no ASN or location is specified, returns the global + aggregate. + + Args: + asn: Filters results by Autonomous System Number. Specify one or more ASNs. Multiple + values generate one series per ASN. + + date_end: End of the date range (inclusive). + + date_start: Start of the date range (inclusive). + + format: Format in which results will be returned. + + location: Filters results by location. Specify a comma-separated list of alpha-2 location + codes. + + metric: Which RPKI ROA validation metric to return. validPfxsRatio = ratio of RPKI-valid + prefixes (IPv4+IPv6 combined). validPfxsV4Ratio / validPfxsV6Ratio = same, split + by IP version. validIpsRatio = ratio of RPKI-valid address space (IPv4 /24s + + IPv6 /48s). validIpsV4Ratio / validIpsV6Ratio = same, split by IP version. + + name: Array of names used to label the series in the response. + + 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 + """ + return self._get( + "/radar/bgp/rpki/roas/timeseries", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "asn": asn, + "date_end": date_end, + "date_start": date_start, + "format": format, + "location": location, + "metric": metric, + "name": name, + }, + roa_timeseries_params.RoaTimeseriesParams, + ), + post_parser=ResultWrapper[RoaTimeseriesResponse]._unwrapper, + ), + cast_to=cast(Type[RoaTimeseriesResponse], ResultWrapper[RoaTimeseriesResponse]), + ) + + +class AsyncRoasResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncRoasResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + 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 AsyncRoasResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncRoasResourceWithStreamingResponse: + """ + 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 AsyncRoasResourceWithStreamingResponse(self) + + async def timeseries( + self, + *, + asn: SequenceNotStr[str] | Omit = omit, + date_end: Union[str, datetime] | Omit = omit, + date_start: Union[str, datetime] | Omit = omit, + format: Literal["JSON", "CSV"] | Omit = omit, + location: SequenceNotStr[str] | Omit = omit, + metric: Literal[ + "validPfxsRatio", + "validPfxsV4Ratio", + "validPfxsV6Ratio", + "validIpsRatio", + "validIpsV4Ratio", + "validIpsV6Ratio", + ] + | Omit = omit, + name: SequenceNotStr[str] | Omit = omit, + # 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, + ) -> RoaTimeseriesResponse: + """ + Retrieves RPKI ROA (Route Origin Authorization) validation ratios over time. + Returns the selected metric as a time series. Supports filtering by ASN or + location (country code) — multiple values of the same filter type produce one + series per value. If no ASN or location is specified, returns the global + aggregate. + + Args: + asn: Filters results by Autonomous System Number. Specify one or more ASNs. Multiple + values generate one series per ASN. + + date_end: End of the date range (inclusive). + + date_start: Start of the date range (inclusive). + + format: Format in which results will be returned. + + location: Filters results by location. Specify a comma-separated list of alpha-2 location + codes. + + metric: Which RPKI ROA validation metric to return. validPfxsRatio = ratio of RPKI-valid + prefixes (IPv4+IPv6 combined). validPfxsV4Ratio / validPfxsV6Ratio = same, split + by IP version. validIpsRatio = ratio of RPKI-valid address space (IPv4 /24s + + IPv6 /48s). validIpsV4Ratio / validIpsV6Ratio = same, split by IP version. + + name: Array of names used to label the series in the response. + + 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 + """ + return await self._get( + "/radar/bgp/rpki/roas/timeseries", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "asn": asn, + "date_end": date_end, + "date_start": date_start, + "format": format, + "location": location, + "metric": metric, + "name": name, + }, + roa_timeseries_params.RoaTimeseriesParams, + ), + post_parser=ResultWrapper[RoaTimeseriesResponse]._unwrapper, + ), + cast_to=cast(Type[RoaTimeseriesResponse], ResultWrapper[RoaTimeseriesResponse]), + ) + + +class RoasResourceWithRawResponse: + def __init__(self, roas: RoasResource) -> None: + self._roas = roas + + self.timeseries = to_raw_response_wrapper( + roas.timeseries, + ) + + +class AsyncRoasResourceWithRawResponse: + def __init__(self, roas: AsyncRoasResource) -> None: + self._roas = roas + + self.timeseries = async_to_raw_response_wrapper( + roas.timeseries, + ) + + +class RoasResourceWithStreamingResponse: + def __init__(self, roas: RoasResource) -> None: + self._roas = roas + + self.timeseries = to_streamed_response_wrapper( + roas.timeseries, + ) + + +class AsyncRoasResourceWithStreamingResponse: + def __init__(self, roas: AsyncRoasResource) -> None: + self._roas = roas + + self.timeseries = async_to_streamed_response_wrapper( + roas.timeseries, + ) diff --git a/src/cloudflare/resources/radar/bgp/rpki/rpki.py b/src/cloudflare/resources/radar/bgp/rpki/rpki.py index 9d76245de9e..0c5f82ac5cc 100644 --- a/src/cloudflare/resources/radar/bgp/rpki/rpki.py +++ b/src/cloudflare/resources/radar/bgp/rpki/rpki.py @@ -10,6 +10,14 @@ ASPAResourceWithStreamingResponse, AsyncASPAResourceWithStreamingResponse, ) +from .roas import ( + RoasResource, + AsyncRoasResource, + RoasResourceWithRawResponse, + AsyncRoasResourceWithRawResponse, + RoasResourceWithStreamingResponse, + AsyncRoasResourceWithStreamingResponse, +) from ....._compat import cached_property from ....._resource import SyncAPIResource, AsyncAPIResource @@ -21,6 +29,10 @@ class RPKIResource(SyncAPIResource): def aspa(self) -> ASPAResource: return ASPAResource(self._client) + @cached_property + def roas(self) -> RoasResource: + return RoasResource(self._client) + @cached_property def with_raw_response(self) -> RPKIResourceWithRawResponse: """ @@ -46,6 +58,10 @@ class AsyncRPKIResource(AsyncAPIResource): def aspa(self) -> AsyncASPAResource: return AsyncASPAResource(self._client) + @cached_property + def roas(self) -> AsyncRoasResource: + return AsyncRoasResource(self._client) + @cached_property def with_raw_response(self) -> AsyncRPKIResourceWithRawResponse: """ @@ -74,6 +90,10 @@ def __init__(self, rpki: RPKIResource) -> None: def aspa(self) -> ASPAResourceWithRawResponse: return ASPAResourceWithRawResponse(self._rpki.aspa) + @cached_property + def roas(self) -> RoasResourceWithRawResponse: + return RoasResourceWithRawResponse(self._rpki.roas) + class AsyncRPKIResourceWithRawResponse: def __init__(self, rpki: AsyncRPKIResource) -> None: @@ -83,6 +103,10 @@ def __init__(self, rpki: AsyncRPKIResource) -> None: def aspa(self) -> AsyncASPAResourceWithRawResponse: return AsyncASPAResourceWithRawResponse(self._rpki.aspa) + @cached_property + def roas(self) -> AsyncRoasResourceWithRawResponse: + return AsyncRoasResourceWithRawResponse(self._rpki.roas) + class RPKIResourceWithStreamingResponse: def __init__(self, rpki: RPKIResource) -> None: @@ -92,6 +116,10 @@ def __init__(self, rpki: RPKIResource) -> None: def aspa(self) -> ASPAResourceWithStreamingResponse: return ASPAResourceWithStreamingResponse(self._rpki.aspa) + @cached_property + def roas(self) -> RoasResourceWithStreamingResponse: + return RoasResourceWithStreamingResponse(self._rpki.roas) + class AsyncRPKIResourceWithStreamingResponse: def __init__(self, rpki: AsyncRPKIResource) -> None: @@ -100,3 +128,7 @@ def __init__(self, rpki: AsyncRPKIResource) -> None: @cached_property def aspa(self) -> AsyncASPAResourceWithStreamingResponse: return AsyncASPAResourceWithStreamingResponse(self._rpki.aspa) + + @cached_property + def roas(self) -> AsyncRoasResourceWithStreamingResponse: + return AsyncRoasResourceWithStreamingResponse(self._rpki.roas) diff --git a/src/cloudflare/types/radar/bgp/ips/__init__.py b/src/cloudflare/types/radar/bgp/ips/__init__.py new file mode 100644 index 00000000000..1e88101779d --- /dev/null +++ b/src/cloudflare/types/radar/bgp/ips/__init__.py @@ -0,0 +1,6 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .top_ases_params import TopAsesParams as TopAsesParams +from .top_ases_response import TopAsesResponse as TopAsesResponse diff --git a/src/cloudflare/types/radar/bgp/ips/top_ases_params.py b/src/cloudflare/types/radar/bgp/ips/top_ases_params.py new file mode 100644 index 00000000000..6395aa7357e --- /dev/null +++ b/src/cloudflare/types/radar/bgp/ips/top_ases_params.py @@ -0,0 +1,28 @@ +# 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, Annotated, TypedDict + +from ....._utils import PropertyInfo + +__all__ = ["TopAsesParams"] + + +class TopAsesParams(TypedDict, total=False): + country: str + """Optional ISO 3166-1 alpha-2 country filter. Omit for global top-N.""" + + date: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] + """Filters results by the specified datetime (ISO 8601).""" + + format: Literal["JSON", "CSV"] + """Format in which results will be returned.""" + + limit: int + """Limits the number of objects returned in the response.""" + + metric: Literal["v4_24s", "v6_48s"] + """Ranking metric: IPv4 /24 count or IPv6 /48 count.""" diff --git a/src/cloudflare/types/radar/bgp/ips/top_ases_response.py b/src/cloudflare/types/radar/bgp/ips/top_ases_response.py new file mode 100644 index 00000000000..97accf39d42 --- /dev/null +++ b/src/cloudflare/types/radar/bgp/ips/top_ases_response.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime + +from pydantic import Field as FieldInfo + +from ....._models import BaseModel + +__all__ = ["TopAsesResponse", "ASN"] + + +class ASN(BaseModel): + asn: int + + v4_24s: int + + v6_48s: int + + +class TopAsesResponse(BaseModel): + anchor_ts: datetime = FieldInfo(alias="anchorTs") + + asns: List[ASN] + + country: Optional[str] = None + + metric: str diff --git a/src/cloudflare/types/radar/bgp/rpki/__init__.py b/src/cloudflare/types/radar/bgp/rpki/__init__.py index c93307a5f29..7e7cd69c969 100644 --- a/src/cloudflare/types/radar/bgp/rpki/__init__.py +++ b/src/cloudflare/types/radar/bgp/rpki/__init__.py @@ -5,6 +5,8 @@ from .aspa_changes_params import ASPAChangesParams as ASPAChangesParams from .aspa_snapshot_params import ASPASnapshotParams as ASPASnapshotParams from .aspa_changes_response import ASPAChangesResponse as ASPAChangesResponse +from .roa_timeseries_params import RoaTimeseriesParams as RoaTimeseriesParams from .aspa_snapshot_response import ASPASnapshotResponse as ASPASnapshotResponse from .aspa_timeseries_params import ASPATimeseriesParams as ASPATimeseriesParams +from .roa_timeseries_response import RoaTimeseriesResponse as RoaTimeseriesResponse from .aspa_timeseries_response import ASPATimeseriesResponse as ASPATimeseriesResponse diff --git a/src/cloudflare/types/radar/bgp/rpki/roa_timeseries_params.py b/src/cloudflare/types/radar/bgp/rpki/roa_timeseries_params.py new file mode 100644 index 00000000000..f75f6dce597 --- /dev/null +++ b/src/cloudflare/types/radar/bgp/rpki/roa_timeseries_params.py @@ -0,0 +1,49 @@ +# 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, Annotated, TypedDict + +from ....._types import SequenceNotStr +from ....._utils import PropertyInfo + +__all__ = ["RoaTimeseriesParams"] + + +class RoaTimeseriesParams(TypedDict, total=False): + asn: SequenceNotStr[str] + """Filters results by Autonomous System Number. + + Specify one or more ASNs. Multiple values generate one series per ASN. + """ + + date_end: Annotated[Union[str, datetime], PropertyInfo(alias="dateEnd", format="iso8601")] + """End of the date range (inclusive).""" + + date_start: Annotated[Union[str, datetime], PropertyInfo(alias="dateStart", format="iso8601")] + """Start of the date range (inclusive).""" + + format: Literal["JSON", "CSV"] + """Format in which results will be returned.""" + + location: SequenceNotStr[str] + """Filters results by location. + + Specify a comma-separated list of alpha-2 location codes. + """ + + metric: Literal[ + "validPfxsRatio", "validPfxsV4Ratio", "validPfxsV6Ratio", "validIpsRatio", "validIpsV4Ratio", "validIpsV6Ratio" + ] + """Which RPKI ROA validation metric to return. + + validPfxsRatio = ratio of RPKI-valid prefixes (IPv4+IPv6 combined). + validPfxsV4Ratio / validPfxsV6Ratio = same, split by IP version. validIpsRatio = + ratio of RPKI-valid address space (IPv4 /24s + IPv6 /48s). validIpsV4Ratio / + validIpsV6Ratio = same, split by IP version. + """ + + name: SequenceNotStr[str] + """Array of names used to label the series in the response.""" diff --git a/src/cloudflare/types/radar/bgp/rpki/roa_timeseries_response.py b/src/cloudflare/types/radar/bgp/rpki/roa_timeseries_response.py new file mode 100644 index 00000000000..c8dc7aff509 --- /dev/null +++ b/src/cloudflare/types/radar/bgp/rpki/roa_timeseries_response.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from datetime import datetime + +from pydantic import Field as FieldInfo + +from ....._models import BaseModel + +__all__ = ["RoaTimeseriesResponse", "Meta", "Serie0"] + + +class Meta(BaseModel): + data_time: datetime = FieldInfo(alias="dataTime") + """Timestamp of the underlying data.""" + + query_time: datetime = FieldInfo(alias="queryTime") + """Timestamp when the query was executed.""" + + +class Serie0(BaseModel): + timestamps: List[datetime] + + values: List[str] + + +class RoaTimeseriesResponse(BaseModel): + meta: Meta + + serie_0: Serie0 diff --git a/tests/api_resources/radar/bgp/ips/__init__.py b/tests/api_resources/radar/bgp/ips/__init__.py new file mode 100644 index 00000000000..fd8019a9a1a --- /dev/null +++ b/tests/api_resources/radar/bgp/ips/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/radar/bgp/ips/test_top.py b/tests/api_resources/radar/bgp/ips/test_top.py new file mode 100644 index 00000000000..66239dbb817 --- /dev/null +++ b/tests/api_resources/radar/bgp/ips/test_top.py @@ -0,0 +1,97 @@ +# 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 pytest + +from cloudflare import Cloudflare, AsyncCloudflare +from tests.utils import assert_matches_type +from cloudflare._utils import parse_datetime +from cloudflare.types.radar.bgp.ips import TopAsesResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestTop: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_ases(self, client: Cloudflare) -> None: + top = client.radar.bgp.ips.top.ases() + assert_matches_type(TopAsesResponse, top, path=["response"]) + + @parametrize + def test_method_ases_with_all_params(self, client: Cloudflare) -> None: + top = client.radar.bgp.ips.top.ases( + country="US", + date=parse_datetime("2024-09-19T00:00:00Z"), + format="JSON", + limit=5, + metric="v4_24s", + ) + assert_matches_type(TopAsesResponse, top, path=["response"]) + + @parametrize + def test_raw_response_ases(self, client: Cloudflare) -> None: + response = client.radar.bgp.ips.top.with_raw_response.ases() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + top = response.parse() + assert_matches_type(TopAsesResponse, top, path=["response"]) + + @parametrize + def test_streaming_response_ases(self, client: Cloudflare) -> None: + with client.radar.bgp.ips.top.with_streaming_response.ases() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + top = response.parse() + assert_matches_type(TopAsesResponse, top, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncTop: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_ases(self, async_client: AsyncCloudflare) -> None: + top = await async_client.radar.bgp.ips.top.ases() + assert_matches_type(TopAsesResponse, top, path=["response"]) + + @parametrize + async def test_method_ases_with_all_params(self, async_client: AsyncCloudflare) -> None: + top = await async_client.radar.bgp.ips.top.ases( + country="US", + date=parse_datetime("2024-09-19T00:00:00Z"), + format="JSON", + limit=5, + metric="v4_24s", + ) + assert_matches_type(TopAsesResponse, top, path=["response"]) + + @parametrize + async def test_raw_response_ases(self, async_client: AsyncCloudflare) -> None: + response = await async_client.radar.bgp.ips.top.with_raw_response.ases() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + top = await response.parse() + assert_matches_type(TopAsesResponse, top, path=["response"]) + + @parametrize + async def test_streaming_response_ases(self, async_client: AsyncCloudflare) -> None: + async with async_client.radar.bgp.ips.top.with_streaming_response.ases() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + top = await response.parse() + assert_matches_type(TopAsesResponse, top, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/radar/bgp/rpki/test_roas.py b/tests/api_resources/radar/bgp/rpki/test_roas.py new file mode 100644 index 00000000000..7469de8431f --- /dev/null +++ b/tests/api_resources/radar/bgp/rpki/test_roas.py @@ -0,0 +1,101 @@ +# 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 pytest + +from cloudflare import Cloudflare, AsyncCloudflare +from tests.utils import assert_matches_type +from cloudflare._utils import parse_datetime +from cloudflare.types.radar.bgp.rpki import RoaTimeseriesResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestRoas: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_timeseries(self, client: Cloudflare) -> None: + roa = client.radar.bgp.rpki.roas.timeseries() + assert_matches_type(RoaTimeseriesResponse, roa, path=["response"]) + + @parametrize + def test_method_timeseries_with_all_params(self, client: Cloudflare) -> None: + roa = client.radar.bgp.rpki.roas.timeseries( + asn=["string"], + date_end=parse_datetime("2023-09-01T11:41:33.782Z"), + date_start=parse_datetime("2023-09-01T11:41:33.782Z"), + format="JSON", + location=["string"], + metric="validPfxsRatio", + name=["main_series"], + ) + assert_matches_type(RoaTimeseriesResponse, roa, path=["response"]) + + @parametrize + def test_raw_response_timeseries(self, client: Cloudflare) -> None: + response = client.radar.bgp.rpki.roas.with_raw_response.timeseries() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + roa = response.parse() + assert_matches_type(RoaTimeseriesResponse, roa, path=["response"]) + + @parametrize + def test_streaming_response_timeseries(self, client: Cloudflare) -> None: + with client.radar.bgp.rpki.roas.with_streaming_response.timeseries() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + roa = response.parse() + assert_matches_type(RoaTimeseriesResponse, roa, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncRoas: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_timeseries(self, async_client: AsyncCloudflare) -> None: + roa = await async_client.radar.bgp.rpki.roas.timeseries() + assert_matches_type(RoaTimeseriesResponse, roa, path=["response"]) + + @parametrize + async def test_method_timeseries_with_all_params(self, async_client: AsyncCloudflare) -> None: + roa = await async_client.radar.bgp.rpki.roas.timeseries( + asn=["string"], + date_end=parse_datetime("2023-09-01T11:41:33.782Z"), + date_start=parse_datetime("2023-09-01T11:41:33.782Z"), + format="JSON", + location=["string"], + metric="validPfxsRatio", + name=["main_series"], + ) + assert_matches_type(RoaTimeseriesResponse, roa, path=["response"]) + + @parametrize + async def test_raw_response_timeseries(self, async_client: AsyncCloudflare) -> None: + response = await async_client.radar.bgp.rpki.roas.with_raw_response.timeseries() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + roa = await response.parse() + assert_matches_type(RoaTimeseriesResponse, roa, path=["response"]) + + @parametrize + async def test_streaming_response_timeseries(self, async_client: AsyncCloudflare) -> None: + async with async_client.radar.bgp.rpki.roas.with_streaming_response.timeseries() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + roa = await response.parse() + assert_matches_type(RoaTimeseriesResponse, roa, path=["response"]) + + assert cast(Any, response.is_closed) is True From 2dbbc68ef0b3bc1ff5e9f16e52cbac0df80175aa Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 5 May 2026 21:46:34 +0000 Subject: [PATCH 44/45] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 2413cda3e2e..e946dfc40a1 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 2211 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a6c352830d1270d0abb5bb983058ea21815e1bb7d2e163965335dcb0e706f057.yml openapi_spec_hash: 43b3282cc17b94e7729c724d6a3c67ae -config_hash: 82bd9683d33d942855962bb7dc595067 +config_hash: e84ce27865a87048dfceb774cac9c0fd From 4694bd38bb63b0e25ac18c9432271f5b67fb81a1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 5 May 2026 23:38:05 +0000 Subject: [PATCH 45/45] chore(api): update composite API spec --- .stats.yml | 2 +- .../monitor_groups/monitor_groups.py | 30 ------------------- .../resource_sharing/resource_sharing.py | 2 ++ .../resources/resource_sharing/resources.py | 4 +++ .../types/load_balancers/monitor_group.py | 4 +-- .../monitor_group_create_params.py | 6 ---- .../monitor_group_edit_params.py | 6 ---- .../monitor_group_update_params.py | 6 ---- .../resource_create_params.py | 1 + .../resource_create_response.py | 1 + .../resource_delete_response.py | 1 + .../resource_sharing/resource_get_response.py | 1 + .../resource_sharing/resource_list_params.py | 1 + .../resource_list_response.py | 1 + .../resource_sharing_create_params.py | 1 + .../resource_sharing_create_response.py | 1 + .../resource_sharing_delete_response.py | 1 + .../resource_sharing_get_response.py | 1 + .../resource_sharing_list_params.py | 1 + .../resource_sharing_list_response.py | 1 + .../resource_sharing_update_response.py | 1 + .../resource_update_response.py | 1 + .../load_balancers/test_monitor_groups.py | 28 ----------------- 23 files changed, 23 insertions(+), 79 deletions(-) diff --git a/.stats.yml b/.stats.yml index e946dfc40a1..fff4afeba50 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 2211 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-a6c352830d1270d0abb5bb983058ea21815e1bb7d2e163965335dcb0e706f057.yml -openapi_spec_hash: 43b3282cc17b94e7729c724d6a3c67ae +openapi_spec_hash: 512888090352626a0937b97e77f93c6c config_hash: e84ce27865a87048dfceb774cac9c0fd diff --git a/src/cloudflare/resources/load_balancers/monitor_groups/monitor_groups.py b/src/cloudflare/resources/load_balancers/monitor_groups/monitor_groups.py index f62ad18ac48..af986d2cb85 100644 --- a/src/cloudflare/resources/load_balancers/monitor_groups/monitor_groups.py +++ b/src/cloudflare/resources/load_balancers/monitor_groups/monitor_groups.py @@ -61,7 +61,6 @@ def create( self, *, account_id: str, - id: str, description: str, members: Iterable[monitor_group_create_params.Member], # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -77,9 +76,6 @@ def create( Args: account_id: Identifier. - id: The ID of the Monitor Group to use for checking the health of origins within - this pool. - description: A short description of the monitor group members: List of monitors in this group @@ -98,7 +94,6 @@ def create( path_template("/accounts/{account_id}/load_balancers/monitor_groups", account_id=account_id), body=maybe_transform( { - "id": id, "description": description, "members": members, }, @@ -119,7 +114,6 @@ def update( monitor_group_id: str, *, account_id: str, - id: str, description: str, members: Iterable[monitor_group_update_params.Member], # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -135,9 +129,6 @@ def update( Args: account_id: Identifier. - id: The ID of the Monitor Group to use for checking the health of origins within - this pool. - description: A short description of the monitor group members: List of monitors in this group @@ -162,7 +153,6 @@ def update( ), body=maybe_transform( { - "id": id, "description": description, "members": members, }, @@ -265,7 +255,6 @@ def edit( monitor_group_id: str, *, account_id: str, - id: str, description: str, members: Iterable[monitor_group_edit_params.Member], # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -281,9 +270,6 @@ def edit( Args: account_id: Identifier. - id: The ID of the Monitor Group to use for checking the health of origins within - this pool. - description: A short description of the monitor group members: List of monitors in this group @@ -308,7 +294,6 @@ def edit( ), body=maybe_transform( { - "id": id, "description": description, "members": members, }, @@ -399,7 +384,6 @@ async def create( self, *, account_id: str, - id: str, description: str, members: Iterable[monitor_group_create_params.Member], # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -415,9 +399,6 @@ async def create( Args: account_id: Identifier. - id: The ID of the Monitor Group to use for checking the health of origins within - this pool. - description: A short description of the monitor group members: List of monitors in this group @@ -436,7 +417,6 @@ async def create( path_template("/accounts/{account_id}/load_balancers/monitor_groups", account_id=account_id), body=await async_maybe_transform( { - "id": id, "description": description, "members": members, }, @@ -457,7 +437,6 @@ async def update( monitor_group_id: str, *, account_id: str, - id: str, description: str, members: Iterable[monitor_group_update_params.Member], # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -473,9 +452,6 @@ async def update( Args: account_id: Identifier. - id: The ID of the Monitor Group to use for checking the health of origins within - this pool. - description: A short description of the monitor group members: List of monitors in this group @@ -500,7 +476,6 @@ async def update( ), body=await async_maybe_transform( { - "id": id, "description": description, "members": members, }, @@ -603,7 +578,6 @@ async def edit( monitor_group_id: str, *, account_id: str, - id: str, description: str, members: Iterable[monitor_group_edit_params.Member], # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -619,9 +593,6 @@ async def edit( Args: account_id: Identifier. - id: The ID of the Monitor Group to use for checking the health of origins within - this pool. - description: A short description of the monitor group members: List of monitors in this group @@ -646,7 +617,6 @@ async def edit( ), body=await async_maybe_transform( { - "id": id, "description": description, "members": members, }, diff --git a/src/cloudflare/resources/resource_sharing/resource_sharing.py b/src/cloudflare/resources/resource_sharing/resource_sharing.py index 5fb90fb418a..fa5288fe7ba 100644 --- a/src/cloudflare/resources/resource_sharing/resource_sharing.py +++ b/src/cloudflare/resources/resource_sharing/resource_sharing.py @@ -199,6 +199,7 @@ def list( "gateway-destination-ip", "gateway-block-page-settings", "gateway-extended-email-matching", + "idp-federation-grant", ] ] | Omit = omit, @@ -534,6 +535,7 @@ def list( "gateway-destination-ip", "gateway-block-page-settings", "gateway-extended-email-matching", + "idp-federation-grant", ] ] | Omit = omit, diff --git a/src/cloudflare/resources/resource_sharing/resources.py b/src/cloudflare/resources/resource_sharing/resources.py index ba92aa2776f..807904557ba 100644 --- a/src/cloudflare/resources/resource_sharing/resources.py +++ b/src/cloudflare/resources/resource_sharing/resources.py @@ -64,6 +64,7 @@ def create( "gateway-destination-ip", "gateway-block-page-settings", "gateway-extended-email-matching", + "idp-federation-grant", ], # 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. @@ -195,6 +196,7 @@ def list( "gateway-destination-ip", "gateway-block-page-settings", "gateway-extended-email-matching", + "idp-federation-grant", ] | Omit = omit, status: Literal["active", "deleting", "deleted"] | Omit = omit, @@ -400,6 +402,7 @@ async def create( "gateway-destination-ip", "gateway-block-page-settings", "gateway-extended-email-matching", + "idp-federation-grant", ], # 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. @@ -531,6 +534,7 @@ def list( "gateway-destination-ip", "gateway-block-page-settings", "gateway-extended-email-matching", + "idp-federation-grant", ] | Omit = omit, status: Literal["active", "deleting", "deleted"] | Omit = omit, diff --git a/src/cloudflare/types/load_balancers/monitor_group.py b/src/cloudflare/types/load_balancers/monitor_group.py index bd6ac9c5a38..8edc3a67c1b 100644 --- a/src/cloudflare/types/load_balancers/monitor_group.py +++ b/src/cloudflare/types/load_balancers/monitor_group.py @@ -44,8 +44,8 @@ class MonitorGroup(BaseModel): members: List[Member] """List of monitors in this group""" - created_at: Optional[datetime] = None + created_on: Optional[datetime] = None """The timestamp of when the monitor group was created""" - updated_at: Optional[datetime] = None + modified_on: Optional[datetime] = None """The timestamp of when the monitor group was last updated""" diff --git a/src/cloudflare/types/load_balancers/monitor_group_create_params.py b/src/cloudflare/types/load_balancers/monitor_group_create_params.py index 0d9b6714ddd..8152ce1b8e7 100644 --- a/src/cloudflare/types/load_balancers/monitor_group_create_params.py +++ b/src/cloudflare/types/load_balancers/monitor_group_create_params.py @@ -12,12 +12,6 @@ class MonitorGroupCreateParams(TypedDict, total=False): account_id: Required[str] """Identifier.""" - id: Required[str] - """ - The ID of the Monitor Group to use for checking the health of origins within - this pool. - """ - description: Required[str] """A short description of the monitor group""" diff --git a/src/cloudflare/types/load_balancers/monitor_group_edit_params.py b/src/cloudflare/types/load_balancers/monitor_group_edit_params.py index 212f85f5360..1b3ff37abf6 100644 --- a/src/cloudflare/types/load_balancers/monitor_group_edit_params.py +++ b/src/cloudflare/types/load_balancers/monitor_group_edit_params.py @@ -12,12 +12,6 @@ class MonitorGroupEditParams(TypedDict, total=False): account_id: Required[str] """Identifier.""" - id: Required[str] - """ - The ID of the Monitor Group to use for checking the health of origins within - this pool. - """ - description: Required[str] """A short description of the monitor group""" diff --git a/src/cloudflare/types/load_balancers/monitor_group_update_params.py b/src/cloudflare/types/load_balancers/monitor_group_update_params.py index 9122012730b..b7f82358e16 100644 --- a/src/cloudflare/types/load_balancers/monitor_group_update_params.py +++ b/src/cloudflare/types/load_balancers/monitor_group_update_params.py @@ -12,12 +12,6 @@ class MonitorGroupUpdateParams(TypedDict, total=False): account_id: Required[str] """Identifier.""" - id: Required[str] - """ - The ID of the Monitor Group to use for checking the health of origins within - this pool. - """ - description: Required[str] """A short description of the monitor group""" diff --git a/src/cloudflare/types/resource_sharing/resource_create_params.py b/src/cloudflare/types/resource_sharing/resource_create_params.py index a5b1f95764f..2594e4a9d7c 100644 --- a/src/cloudflare/types/resource_sharing/resource_create_params.py +++ b/src/cloudflare/types/resource_sharing/resource_create_params.py @@ -27,6 +27,7 @@ class ResourceCreateParams(TypedDict, total=False): "gateway-destination-ip", "gateway-block-page-settings", "gateway-extended-email-matching", + "idp-federation-grant", ] ] """Resource Type.""" diff --git a/src/cloudflare/types/resource_sharing/resource_create_response.py b/src/cloudflare/types/resource_sharing/resource_create_response.py index 9100a80af02..6ade1d9fbe3 100644 --- a/src/cloudflare/types/resource_sharing/resource_create_response.py +++ b/src/cloudflare/types/resource_sharing/resource_create_response.py @@ -33,6 +33,7 @@ class ResourceCreateResponse(BaseModel): "gateway-destination-ip", "gateway-block-page-settings", "gateway-extended-email-matching", + "idp-federation-grant", ] """Resource Type.""" diff --git a/src/cloudflare/types/resource_sharing/resource_delete_response.py b/src/cloudflare/types/resource_sharing/resource_delete_response.py index d1ddf972f39..deff33152bc 100644 --- a/src/cloudflare/types/resource_sharing/resource_delete_response.py +++ b/src/cloudflare/types/resource_sharing/resource_delete_response.py @@ -33,6 +33,7 @@ class ResourceDeleteResponse(BaseModel): "gateway-destination-ip", "gateway-block-page-settings", "gateway-extended-email-matching", + "idp-federation-grant", ] """Resource Type.""" diff --git a/src/cloudflare/types/resource_sharing/resource_get_response.py b/src/cloudflare/types/resource_sharing/resource_get_response.py index 1eeb5c85987..a357bb5074f 100644 --- a/src/cloudflare/types/resource_sharing/resource_get_response.py +++ b/src/cloudflare/types/resource_sharing/resource_get_response.py @@ -33,6 +33,7 @@ class ResourceGetResponse(BaseModel): "gateway-destination-ip", "gateway-block-page-settings", "gateway-extended-email-matching", + "idp-federation-grant", ] """Resource Type.""" diff --git a/src/cloudflare/types/resource_sharing/resource_list_params.py b/src/cloudflare/types/resource_sharing/resource_list_params.py index cad9c27cae1..7b1bcc36f3c 100644 --- a/src/cloudflare/types/resource_sharing/resource_list_params.py +++ b/src/cloudflare/types/resource_sharing/resource_list_params.py @@ -23,6 +23,7 @@ class ResourceListParams(TypedDict, total=False): "gateway-destination-ip", "gateway-block-page-settings", "gateway-extended-email-matching", + "idp-federation-grant", ] """Filter share resources by resource_type.""" diff --git a/src/cloudflare/types/resource_sharing/resource_list_response.py b/src/cloudflare/types/resource_sharing/resource_list_response.py index bfda9a7d3da..28474135379 100644 --- a/src/cloudflare/types/resource_sharing/resource_list_response.py +++ b/src/cloudflare/types/resource_sharing/resource_list_response.py @@ -33,6 +33,7 @@ class ResourceListResponse(BaseModel): "gateway-destination-ip", "gateway-block-page-settings", "gateway-extended-email-matching", + "idp-federation-grant", ] """Resource Type.""" diff --git a/src/cloudflare/types/resource_sharing/resource_sharing_create_params.py b/src/cloudflare/types/resource_sharing/resource_sharing_create_params.py index d5adacfdba7..ea065a8f253 100644 --- a/src/cloudflare/types/resource_sharing/resource_sharing_create_params.py +++ b/src/cloudflare/types/resource_sharing/resource_sharing_create_params.py @@ -47,6 +47,7 @@ class Resource(TypedDict, total=False): "gateway-destination-ip", "gateway-block-page-settings", "gateway-extended-email-matching", + "idp-federation-grant", ] ] """Resource Type.""" diff --git a/src/cloudflare/types/resource_sharing/resource_sharing_create_response.py b/src/cloudflare/types/resource_sharing/resource_sharing_create_response.py index c0b6774c64e..a0993e761f3 100644 --- a/src/cloudflare/types/resource_sharing/resource_sharing_create_response.py +++ b/src/cloudflare/types/resource_sharing/resource_sharing_create_response.py @@ -34,6 +34,7 @@ class Resource(BaseModel): "gateway-destination-ip", "gateway-block-page-settings", "gateway-extended-email-matching", + "idp-federation-grant", ] """Resource Type.""" diff --git a/src/cloudflare/types/resource_sharing/resource_sharing_delete_response.py b/src/cloudflare/types/resource_sharing/resource_sharing_delete_response.py index c3cd3665093..fbbd5a5bd1b 100644 --- a/src/cloudflare/types/resource_sharing/resource_sharing_delete_response.py +++ b/src/cloudflare/types/resource_sharing/resource_sharing_delete_response.py @@ -34,6 +34,7 @@ class Resource(BaseModel): "gateway-destination-ip", "gateway-block-page-settings", "gateway-extended-email-matching", + "idp-federation-grant", ] """Resource Type.""" diff --git a/src/cloudflare/types/resource_sharing/resource_sharing_get_response.py b/src/cloudflare/types/resource_sharing/resource_sharing_get_response.py index 2a3cdc1c320..e15aa02faf6 100644 --- a/src/cloudflare/types/resource_sharing/resource_sharing_get_response.py +++ b/src/cloudflare/types/resource_sharing/resource_sharing_get_response.py @@ -34,6 +34,7 @@ class Resource(BaseModel): "gateway-destination-ip", "gateway-block-page-settings", "gateway-extended-email-matching", + "idp-federation-grant", ] """Resource Type.""" diff --git a/src/cloudflare/types/resource_sharing/resource_sharing_list_params.py b/src/cloudflare/types/resource_sharing/resource_sharing_list_params.py index 6984b782c2e..bcc0490aa51 100644 --- a/src/cloudflare/types/resource_sharing/resource_sharing_list_params.py +++ b/src/cloudflare/types/resource_sharing/resource_sharing_list_params.py @@ -42,6 +42,7 @@ class ResourceSharingListParams(TypedDict, total=False): "gateway-destination-ip", "gateway-block-page-settings", "gateway-extended-email-matching", + "idp-federation-grant", ] ] """Filter share resources by resource_types.""" diff --git a/src/cloudflare/types/resource_sharing/resource_sharing_list_response.py b/src/cloudflare/types/resource_sharing/resource_sharing_list_response.py index 4a89eb0af47..5581ed31b37 100644 --- a/src/cloudflare/types/resource_sharing/resource_sharing_list_response.py +++ b/src/cloudflare/types/resource_sharing/resource_sharing_list_response.py @@ -34,6 +34,7 @@ class Resource(BaseModel): "gateway-destination-ip", "gateway-block-page-settings", "gateway-extended-email-matching", + "idp-federation-grant", ] """Resource Type.""" diff --git a/src/cloudflare/types/resource_sharing/resource_sharing_update_response.py b/src/cloudflare/types/resource_sharing/resource_sharing_update_response.py index f8cf8f102b8..c955262c0fa 100644 --- a/src/cloudflare/types/resource_sharing/resource_sharing_update_response.py +++ b/src/cloudflare/types/resource_sharing/resource_sharing_update_response.py @@ -34,6 +34,7 @@ class Resource(BaseModel): "gateway-destination-ip", "gateway-block-page-settings", "gateway-extended-email-matching", + "idp-federation-grant", ] """Resource Type.""" diff --git a/src/cloudflare/types/resource_sharing/resource_update_response.py b/src/cloudflare/types/resource_sharing/resource_update_response.py index 0d53b6b87f1..f207220bf2d 100644 --- a/src/cloudflare/types/resource_sharing/resource_update_response.py +++ b/src/cloudflare/types/resource_sharing/resource_update_response.py @@ -33,6 +33,7 @@ class ResourceUpdateResponse(BaseModel): "gateway-destination-ip", "gateway-block-page-settings", "gateway-extended-email-matching", + "idp-federation-grant", ] """Resource Type.""" diff --git a/tests/api_resources/load_balancers/test_monitor_groups.py b/tests/api_resources/load_balancers/test_monitor_groups.py index 7c9ecf52ac8..aaf93e98929 100644 --- a/tests/api_resources/load_balancers/test_monitor_groups.py +++ b/tests/api_resources/load_balancers/test_monitor_groups.py @@ -24,7 +24,6 @@ class TestMonitorGroups: def test_method_create(self, client: Cloudflare) -> None: monitor_group = client.load_balancers.monitor_groups.create( account_id="023e105f4ecef8ad9ca31a8372d0c353", - id="id", description="Primary datacenter monitors", members=[ { @@ -41,7 +40,6 @@ def test_method_create(self, client: Cloudflare) -> None: def test_raw_response_create(self, client: Cloudflare) -> None: response = client.load_balancers.monitor_groups.with_raw_response.create( account_id="023e105f4ecef8ad9ca31a8372d0c353", - id="id", description="Primary datacenter monitors", members=[ { @@ -62,7 +60,6 @@ def test_raw_response_create(self, client: Cloudflare) -> None: def test_streaming_response_create(self, client: Cloudflare) -> None: with client.load_balancers.monitor_groups.with_streaming_response.create( account_id="023e105f4ecef8ad9ca31a8372d0c353", - id="id", description="Primary datacenter monitors", members=[ { @@ -86,7 +83,6 @@ 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.load_balancers.monitor_groups.with_raw_response.create( account_id="", - id="id", description="Primary datacenter monitors", members=[ { @@ -103,7 +99,6 @@ def test_method_update(self, client: Cloudflare) -> None: monitor_group = client.load_balancers.monitor_groups.update( monitor_group_id="17b5962d775c646f3f9725cbc7a53df4", account_id="023e105f4ecef8ad9ca31a8372d0c353", - id="id", description="Primary datacenter monitors", members=[ { @@ -121,7 +116,6 @@ def test_raw_response_update(self, client: Cloudflare) -> None: response = client.load_balancers.monitor_groups.with_raw_response.update( monitor_group_id="17b5962d775c646f3f9725cbc7a53df4", account_id="023e105f4ecef8ad9ca31a8372d0c353", - id="id", description="Primary datacenter monitors", members=[ { @@ -143,7 +137,6 @@ def test_streaming_response_update(self, client: Cloudflare) -> None: with client.load_balancers.monitor_groups.with_streaming_response.update( monitor_group_id="17b5962d775c646f3f9725cbc7a53df4", account_id="023e105f4ecef8ad9ca31a8372d0c353", - id="id", description="Primary datacenter monitors", members=[ { @@ -168,7 +161,6 @@ def test_path_params_update(self, client: Cloudflare) -> None: client.load_balancers.monitor_groups.with_raw_response.update( monitor_group_id="17b5962d775c646f3f9725cbc7a53df4", account_id="", - id="id", description="Primary datacenter monitors", members=[ { @@ -184,7 +176,6 @@ def test_path_params_update(self, client: Cloudflare) -> None: client.load_balancers.monitor_groups.with_raw_response.update( monitor_group_id="", account_id="023e105f4ecef8ad9ca31a8372d0c353", - id="id", description="Primary datacenter monitors", members=[ { @@ -287,7 +278,6 @@ def test_method_edit(self, client: Cloudflare) -> None: monitor_group = client.load_balancers.monitor_groups.edit( monitor_group_id="17b5962d775c646f3f9725cbc7a53df4", account_id="023e105f4ecef8ad9ca31a8372d0c353", - id="id", description="Primary datacenter monitors", members=[ { @@ -305,7 +295,6 @@ def test_raw_response_edit(self, client: Cloudflare) -> None: response = client.load_balancers.monitor_groups.with_raw_response.edit( monitor_group_id="17b5962d775c646f3f9725cbc7a53df4", account_id="023e105f4ecef8ad9ca31a8372d0c353", - id="id", description="Primary datacenter monitors", members=[ { @@ -327,7 +316,6 @@ def test_streaming_response_edit(self, client: Cloudflare) -> None: with client.load_balancers.monitor_groups.with_streaming_response.edit( monitor_group_id="17b5962d775c646f3f9725cbc7a53df4", account_id="023e105f4ecef8ad9ca31a8372d0c353", - id="id", description="Primary datacenter monitors", members=[ { @@ -352,7 +340,6 @@ def test_path_params_edit(self, client: Cloudflare) -> None: client.load_balancers.monitor_groups.with_raw_response.edit( monitor_group_id="17b5962d775c646f3f9725cbc7a53df4", account_id="", - id="id", description="Primary datacenter monitors", members=[ { @@ -368,7 +355,6 @@ def test_path_params_edit(self, client: Cloudflare) -> None: client.load_balancers.monitor_groups.with_raw_response.edit( monitor_group_id="", account_id="023e105f4ecef8ad9ca31a8372d0c353", - id="id", description="Primary datacenter monitors", members=[ { @@ -438,7 +424,6 @@ class TestAsyncMonitorGroups: async def test_method_create(self, async_client: AsyncCloudflare) -> None: monitor_group = await async_client.load_balancers.monitor_groups.create( account_id="023e105f4ecef8ad9ca31a8372d0c353", - id="id", description="Primary datacenter monitors", members=[ { @@ -455,7 +440,6 @@ async def test_method_create(self, async_client: AsyncCloudflare) -> None: async def test_raw_response_create(self, async_client: AsyncCloudflare) -> None: response = await async_client.load_balancers.monitor_groups.with_raw_response.create( account_id="023e105f4ecef8ad9ca31a8372d0c353", - id="id", description="Primary datacenter monitors", members=[ { @@ -476,7 +460,6 @@ async def test_raw_response_create(self, async_client: AsyncCloudflare) -> None: async def test_streaming_response_create(self, async_client: AsyncCloudflare) -> None: async with async_client.load_balancers.monitor_groups.with_streaming_response.create( account_id="023e105f4ecef8ad9ca31a8372d0c353", - id="id", description="Primary datacenter monitors", members=[ { @@ -500,7 +483,6 @@ 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.load_balancers.monitor_groups.with_raw_response.create( account_id="", - id="id", description="Primary datacenter monitors", members=[ { @@ -517,7 +499,6 @@ async def test_method_update(self, async_client: AsyncCloudflare) -> None: monitor_group = await async_client.load_balancers.monitor_groups.update( monitor_group_id="17b5962d775c646f3f9725cbc7a53df4", account_id="023e105f4ecef8ad9ca31a8372d0c353", - id="id", description="Primary datacenter monitors", members=[ { @@ -535,7 +516,6 @@ async def test_raw_response_update(self, async_client: AsyncCloudflare) -> None: response = await async_client.load_balancers.monitor_groups.with_raw_response.update( monitor_group_id="17b5962d775c646f3f9725cbc7a53df4", account_id="023e105f4ecef8ad9ca31a8372d0c353", - id="id", description="Primary datacenter monitors", members=[ { @@ -557,7 +537,6 @@ async def test_streaming_response_update(self, async_client: AsyncCloudflare) -> async with async_client.load_balancers.monitor_groups.with_streaming_response.update( monitor_group_id="17b5962d775c646f3f9725cbc7a53df4", account_id="023e105f4ecef8ad9ca31a8372d0c353", - id="id", description="Primary datacenter monitors", members=[ { @@ -582,7 +561,6 @@ async def test_path_params_update(self, async_client: AsyncCloudflare) -> None: await async_client.load_balancers.monitor_groups.with_raw_response.update( monitor_group_id="17b5962d775c646f3f9725cbc7a53df4", account_id="", - id="id", description="Primary datacenter monitors", members=[ { @@ -598,7 +576,6 @@ async def test_path_params_update(self, async_client: AsyncCloudflare) -> None: await async_client.load_balancers.monitor_groups.with_raw_response.update( monitor_group_id="", account_id="023e105f4ecef8ad9ca31a8372d0c353", - id="id", description="Primary datacenter monitors", members=[ { @@ -701,7 +678,6 @@ async def test_method_edit(self, async_client: AsyncCloudflare) -> None: monitor_group = await async_client.load_balancers.monitor_groups.edit( monitor_group_id="17b5962d775c646f3f9725cbc7a53df4", account_id="023e105f4ecef8ad9ca31a8372d0c353", - id="id", description="Primary datacenter monitors", members=[ { @@ -719,7 +695,6 @@ async def test_raw_response_edit(self, async_client: AsyncCloudflare) -> None: response = await async_client.load_balancers.monitor_groups.with_raw_response.edit( monitor_group_id="17b5962d775c646f3f9725cbc7a53df4", account_id="023e105f4ecef8ad9ca31a8372d0c353", - id="id", description="Primary datacenter monitors", members=[ { @@ -741,7 +716,6 @@ async def test_streaming_response_edit(self, async_client: AsyncCloudflare) -> N async with async_client.load_balancers.monitor_groups.with_streaming_response.edit( monitor_group_id="17b5962d775c646f3f9725cbc7a53df4", account_id="023e105f4ecef8ad9ca31a8372d0c353", - id="id", description="Primary datacenter monitors", members=[ { @@ -766,7 +740,6 @@ async def test_path_params_edit(self, async_client: AsyncCloudflare) -> None: await async_client.load_balancers.monitor_groups.with_raw_response.edit( monitor_group_id="17b5962d775c646f3f9725cbc7a53df4", account_id="", - id="id", description="Primary datacenter monitors", members=[ { @@ -782,7 +755,6 @@ async def test_path_params_edit(self, async_client: AsyncCloudflare) -> None: await async_client.load_balancers.monitor_groups.with_raw_response.edit( monitor_group_id="", account_id="023e105f4ecef8ad9ca31a8372d0c353", - id="id", description="Primary datacenter monitors", members=[ {