diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 811e184..f852183 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "7.16.0" + ".": "7.17.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 0dd4709..9be8c11 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 123 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-f54bd32a07b6d85cfda75812728f86aa295b0f3fb662ead7670179f809195896.yml -openapi_spec_hash: 0a283754d97445ef84d50720ba47081a -config_hash: 3536872b17998fc451577505e15afb3d +configured_endpoints: 134 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-e0c54fd2a28d7beec2c18a6c7abb833e0dd9b14e99c48cf1cfd126f664f1dc62.yml +openapi_spec_hash: 713a396d0875e2000de918032b499b2e +config_hash: 83c79a6ad0a0b5dcce3b85208026343b diff --git a/CHANGELOG.md b/CHANGELOG.md index 0877604..fea178a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 7.17.0 (2026-06-24) + +Full Changelog: [v7.16.0...v7.17.0](https://github.com/trycourier/courier-python/compare/v7.16.0...v7.17.0) + +### Features + +* **preferences:** workspace preference sections & nested topics endpoints ([362609a](https://github.com/trycourier/courier-python/commit/362609ad7f9f9416c9b3bfabb846128c595dcda6)) + ## 7.16.0 (2026-06-23) Full Changelog: [v7.15.0...v7.16.0](https://github.com/trycourier/courier-python/compare/v7.15.0...v7.16.0) diff --git a/api.md b/api.md index eee01fa..07acc28 100644 --- a/api.md +++ b/api.md @@ -481,6 +481,43 @@ Methods: - client.routing_strategies.list_notifications(id, \*\*params) -> AssociatedNotificationListResponse - client.routing_strategies.replace(id, \*\*params) -> RoutingStrategyGetResponse +# PreferenceSections + +Types: + +```python +from courier.types import ( + PreferenceSectionCreateRequest, + PreferenceSectionGetResponse, + PreferenceSectionListResponse, + PreferenceSectionReplaceRequest, + PreferenceTopicCreateRequest, + PreferenceTopicGetResponse, + PreferenceTopicListResponse, + PreferenceTopicReplaceRequest, + PublishPreferencesResponse, +) +``` + +Methods: + +- client.preference_sections.create(\*\*params) -> PreferenceSectionGetResponse +- client.preference_sections.retrieve(section_id) -> PreferenceSectionGetResponse +- client.preference_sections.list() -> PreferenceSectionListResponse +- client.preference_sections.archive(section_id) -> None +- client.preference_sections.publish() -> PublishPreferencesResponse +- client.preference_sections.replace(section_id, \*\*params) -> PreferenceSectionGetResponse + +## Topics + +Methods: + +- client.preference_sections.topics.create(section_id, \*\*params) -> PreferenceTopicGetResponse +- client.preference_sections.topics.retrieve(topic_id, \*, section_id) -> PreferenceTopicGetResponse +- client.preference_sections.topics.list(section_id) -> PreferenceTopicListResponse +- client.preference_sections.topics.archive(topic_id, \*, section_id) -> None +- client.preference_sections.topics.replace(topic_id, \*, section_id, \*\*params) -> PreferenceTopicGetResponse + # Profiles Types: diff --git a/pyproject.toml b/pyproject.toml index 64dfbee..340c309 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "trycourier" -version = "7.16.0" +version = "7.17.0" description = "The official Python library for the Courier API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/courier/_client.py b/src/courier/_client.py index 64fa136..b79512a 100644 --- a/src/courier/_client.py +++ b/src/courier/_client.py @@ -56,6 +56,7 @@ translations, notifications, routing_strategies, + preference_sections, ) from .resources.auth import AuthResource, AsyncAuthResource from .resources.bulk import BulkResource, AsyncBulkResource @@ -77,6 +78,10 @@ from .resources.providers.providers import ProvidersResource, AsyncProvidersResource from .resources.automations.automations import AutomationsResource, AsyncAutomationsResource from .resources.notifications.notifications import NotificationsResource, AsyncNotificationsResource + from .resources.preference_sections.preference_sections import ( + PreferenceSectionsResource, + AsyncPreferenceSectionsResource, + ) __all__ = ["Timeout", "Transport", "ProxiesTypes", "RequestOptions", "Courier", "AsyncCourier", "Client", "AsyncClient"] @@ -241,6 +246,12 @@ def routing_strategies(self) -> RoutingStrategiesResource: return RoutingStrategiesResource(self) + @cached_property + def preference_sections(self) -> PreferenceSectionsResource: + from .resources.preference_sections import PreferenceSectionsResource + + return PreferenceSectionsResource(self) + @cached_property def profiles(self) -> ProfilesResource: from .resources.profiles import ProfilesResource @@ -538,6 +549,12 @@ def routing_strategies(self) -> AsyncRoutingStrategiesResource: return AsyncRoutingStrategiesResource(self) + @cached_property + def preference_sections(self) -> AsyncPreferenceSectionsResource: + from .resources.preference_sections import AsyncPreferenceSectionsResource + + return AsyncPreferenceSectionsResource(self) + @cached_property def profiles(self) -> AsyncProfilesResource: from .resources.profiles import AsyncProfilesResource @@ -777,6 +794,12 @@ def routing_strategies(self) -> routing_strategies.RoutingStrategiesResourceWith return RoutingStrategiesResourceWithRawResponse(self._client.routing_strategies) + @cached_property + def preference_sections(self) -> preference_sections.PreferenceSectionsResourceWithRawResponse: + from .resources.preference_sections import PreferenceSectionsResourceWithRawResponse + + return PreferenceSectionsResourceWithRawResponse(self._client.preference_sections) + @cached_property def profiles(self) -> profiles.ProfilesResourceWithRawResponse: from .resources.profiles import ProfilesResourceWithRawResponse @@ -904,6 +927,12 @@ def routing_strategies(self) -> routing_strategies.AsyncRoutingStrategiesResourc return AsyncRoutingStrategiesResourceWithRawResponse(self._client.routing_strategies) + @cached_property + def preference_sections(self) -> preference_sections.AsyncPreferenceSectionsResourceWithRawResponse: + from .resources.preference_sections import AsyncPreferenceSectionsResourceWithRawResponse + + return AsyncPreferenceSectionsResourceWithRawResponse(self._client.preference_sections) + @cached_property def profiles(self) -> profiles.AsyncProfilesResourceWithRawResponse: from .resources.profiles import AsyncProfilesResourceWithRawResponse @@ -1031,6 +1060,12 @@ def routing_strategies(self) -> routing_strategies.RoutingStrategiesResourceWith return RoutingStrategiesResourceWithStreamingResponse(self._client.routing_strategies) + @cached_property + def preference_sections(self) -> preference_sections.PreferenceSectionsResourceWithStreamingResponse: + from .resources.preference_sections import PreferenceSectionsResourceWithStreamingResponse + + return PreferenceSectionsResourceWithStreamingResponse(self._client.preference_sections) + @cached_property def profiles(self) -> profiles.ProfilesResourceWithStreamingResponse: from .resources.profiles import ProfilesResourceWithStreamingResponse @@ -1158,6 +1193,12 @@ def routing_strategies(self) -> routing_strategies.AsyncRoutingStrategiesResourc return AsyncRoutingStrategiesResourceWithStreamingResponse(self._client.routing_strategies) + @cached_property + def preference_sections(self) -> preference_sections.AsyncPreferenceSectionsResourceWithStreamingResponse: + from .resources.preference_sections import AsyncPreferenceSectionsResourceWithStreamingResponse + + return AsyncPreferenceSectionsResourceWithStreamingResponse(self._client.preference_sections) + @cached_property def profiles(self) -> profiles.AsyncProfilesResourceWithStreamingResponse: from .resources.profiles import AsyncProfilesResourceWithStreamingResponse diff --git a/src/courier/_version.py b/src/courier/_version.py index 6fb1f77..313a105 100644 --- a/src/courier/_version.py +++ b/src/courier/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "courier" -__version__ = "7.16.0" # x-release-please-version +__version__ = "7.17.0" # x-release-please-version diff --git a/src/courier/resources/__init__.py b/src/courier/resources/__init__.py index 3933d0a..20439e3 100644 --- a/src/courier/resources/__init__.py +++ b/src/courier/resources/__init__.py @@ -160,6 +160,14 @@ RoutingStrategiesResourceWithStreamingResponse, AsyncRoutingStrategiesResourceWithStreamingResponse, ) +from .preference_sections import ( + PreferenceSectionsResource, + AsyncPreferenceSectionsResource, + PreferenceSectionsResourceWithRawResponse, + AsyncPreferenceSectionsResourceWithRawResponse, + PreferenceSectionsResourceWithStreamingResponse, + AsyncPreferenceSectionsResourceWithStreamingResponse, +) __all__ = [ "SendResource", @@ -258,6 +266,12 @@ "AsyncRoutingStrategiesResourceWithRawResponse", "RoutingStrategiesResourceWithStreamingResponse", "AsyncRoutingStrategiesResourceWithStreamingResponse", + "PreferenceSectionsResource", + "AsyncPreferenceSectionsResource", + "PreferenceSectionsResourceWithRawResponse", + "AsyncPreferenceSectionsResourceWithRawResponse", + "PreferenceSectionsResourceWithStreamingResponse", + "AsyncPreferenceSectionsResourceWithStreamingResponse", "ProfilesResource", "AsyncProfilesResource", "ProfilesResourceWithRawResponse", diff --git a/src/courier/resources/preference_sections/__init__.py b/src/courier/resources/preference_sections/__init__.py new file mode 100644 index 0000000..2ce5b7b --- /dev/null +++ b/src/courier/resources/preference_sections/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .topics import ( + TopicsResource, + AsyncTopicsResource, + TopicsResourceWithRawResponse, + AsyncTopicsResourceWithRawResponse, + TopicsResourceWithStreamingResponse, + AsyncTopicsResourceWithStreamingResponse, +) +from .preference_sections import ( + PreferenceSectionsResource, + AsyncPreferenceSectionsResource, + PreferenceSectionsResourceWithRawResponse, + AsyncPreferenceSectionsResourceWithRawResponse, + PreferenceSectionsResourceWithStreamingResponse, + AsyncPreferenceSectionsResourceWithStreamingResponse, +) + +__all__ = [ + "TopicsResource", + "AsyncTopicsResource", + "TopicsResourceWithRawResponse", + "AsyncTopicsResourceWithRawResponse", + "TopicsResourceWithStreamingResponse", + "AsyncTopicsResourceWithStreamingResponse", + "PreferenceSectionsResource", + "AsyncPreferenceSectionsResource", + "PreferenceSectionsResourceWithRawResponse", + "AsyncPreferenceSectionsResourceWithRawResponse", + "PreferenceSectionsResourceWithStreamingResponse", + "AsyncPreferenceSectionsResourceWithStreamingResponse", +] diff --git a/src/courier/resources/preference_sections/preference_sections.py b/src/courier/resources/preference_sections/preference_sections.py new file mode 100644 index 0000000..47267cf --- /dev/null +++ b/src/courier/resources/preference_sections/preference_sections.py @@ -0,0 +1,632 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Optional + +import httpx + +from .topics import ( + TopicsResource, + AsyncTopicsResource, + TopicsResourceWithRawResponse, + AsyncTopicsResourceWithRawResponse, + TopicsResourceWithStreamingResponse, + AsyncTopicsResourceWithStreamingResponse, +) +from ...types import preference_section_create_params, preference_section_replace_params +from ..._types import Body, Omit, Query, Headers, NoneType, 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.publish_preferences_response import PublishPreferencesResponse +from ...types.shared.channel_classification import ChannelClassification +from ...types.preference_section_get_response import PreferenceSectionGetResponse +from ...types.preference_section_list_response import PreferenceSectionListResponse + +__all__ = ["PreferenceSectionsResource", "AsyncPreferenceSectionsResource"] + + +class PreferenceSectionsResource(SyncAPIResource): + @cached_property + def topics(self) -> TopicsResource: + return TopicsResource(self._client) + + @cached_property + def with_raw_response(self) -> PreferenceSectionsResourceWithRawResponse: + """ + 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/trycourier/courier-python#accessing-raw-response-data-eg-headers + """ + return PreferenceSectionsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> PreferenceSectionsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/trycourier/courier-python#with_streaming_response + """ + return PreferenceSectionsResourceWithStreamingResponse(self) + + def create( + self, + *, + name: str, + has_custom_routing: Optional[bool] | Omit = omit, + routing_options: Optional[List[ChannelClassification]] | 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, + ) -> PreferenceSectionGetResponse: + """Create a preference section in your workspace. + + The section id is generated and + returned. Topics are created inside a section via POST + /preferences/sections/{section_id}/topics. + + Args: + name: Human-readable name for the section. + + has_custom_routing: Whether the section defines custom routing for its topics. + + routing_options: Default channels for the section. Defaults to empty if omitted. + + 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._post( + "/preferences/sections", + body=maybe_transform( + { + "name": name, + "has_custom_routing": has_custom_routing, + "routing_options": routing_options, + }, + preference_section_create_params.PreferenceSectionCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PreferenceSectionGetResponse, + ) + + def retrieve( + self, + section_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, + ) -> PreferenceSectionGetResponse: + """ + Retrieve a preference section by id, including its topics. + + 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 section_id: + raise ValueError(f"Expected a non-empty value for `section_id` but received {section_id!r}") + return self._get( + path_template("/preferences/sections/{section_id}", section_id=section_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PreferenceSectionGetResponse, + ) + + def list( + self, + *, + # 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, + ) -> PreferenceSectionListResponse: + """List the workspace's preference sections. + + Each section embeds its topics. Scoped + to the workspace of the API key. + """ + return self._get( + "/preferences/sections", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PreferenceSectionListResponse, + ) + + def archive( + self, + section_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, + ) -> None: + """Archive a preference section. + + The section must be empty: delete its topics + first, otherwise the request fails with 409. + + 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 section_id: + raise ValueError(f"Expected a non-empty value for `section_id` but received {section_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + path_template("/preferences/sections/{section_id}", section_id=section_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def publish( + self, + *, + # 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, + ) -> PublishPreferencesResponse: + """Publish the workspace's preferences page. + + Takes a snapshot of every section with + its topics under a new published version, making the current state visible on + the hosted preferences page (non-draft). + """ + return self._post( + "/preferences/publish", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PublishPreferencesResponse, + ) + + def replace( + self, + section_id: str, + *, + name: str, + has_custom_routing: Optional[bool] | Omit = omit, + routing_options: Optional[List[ChannelClassification]] | 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, + ) -> PreferenceSectionGetResponse: + """Replace a preference section. + + Full document replacement; missing optional fields + are cleared. Topics attached to the section are unaffected. + + Args: + name: Human-readable name for the section. + + has_custom_routing: Whether the section defines custom routing for its topics. + + routing_options: Default channels for the section. Omit to clear. + + 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 section_id: + raise ValueError(f"Expected a non-empty value for `section_id` but received {section_id!r}") + return self._put( + path_template("/preferences/sections/{section_id}", section_id=section_id), + body=maybe_transform( + { + "name": name, + "has_custom_routing": has_custom_routing, + "routing_options": routing_options, + }, + preference_section_replace_params.PreferenceSectionReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PreferenceSectionGetResponse, + ) + + +class AsyncPreferenceSectionsResource(AsyncAPIResource): + @cached_property + def topics(self) -> AsyncTopicsResource: + return AsyncTopicsResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncPreferenceSectionsResourceWithRawResponse: + """ + 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/trycourier/courier-python#accessing-raw-response-data-eg-headers + """ + return AsyncPreferenceSectionsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncPreferenceSectionsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/trycourier/courier-python#with_streaming_response + """ + return AsyncPreferenceSectionsResourceWithStreamingResponse(self) + + async def create( + self, + *, + name: str, + has_custom_routing: Optional[bool] | Omit = omit, + routing_options: Optional[List[ChannelClassification]] | 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, + ) -> PreferenceSectionGetResponse: + """Create a preference section in your workspace. + + The section id is generated and + returned. Topics are created inside a section via POST + /preferences/sections/{section_id}/topics. + + Args: + name: Human-readable name for the section. + + has_custom_routing: Whether the section defines custom routing for its topics. + + routing_options: Default channels for the section. Defaults to empty if omitted. + + 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._post( + "/preferences/sections", + body=await async_maybe_transform( + { + "name": name, + "has_custom_routing": has_custom_routing, + "routing_options": routing_options, + }, + preference_section_create_params.PreferenceSectionCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PreferenceSectionGetResponse, + ) + + async def retrieve( + self, + section_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, + ) -> PreferenceSectionGetResponse: + """ + Retrieve a preference section by id, including its topics. + + 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 section_id: + raise ValueError(f"Expected a non-empty value for `section_id` but received {section_id!r}") + return await self._get( + path_template("/preferences/sections/{section_id}", section_id=section_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PreferenceSectionGetResponse, + ) + + async def list( + self, + *, + # 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, + ) -> PreferenceSectionListResponse: + """List the workspace's preference sections. + + Each section embeds its topics. Scoped + to the workspace of the API key. + """ + return await self._get( + "/preferences/sections", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PreferenceSectionListResponse, + ) + + async def archive( + self, + section_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, + ) -> None: + """Archive a preference section. + + The section must be empty: delete its topics + first, otherwise the request fails with 409. + + 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 section_id: + raise ValueError(f"Expected a non-empty value for `section_id` but received {section_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + path_template("/preferences/sections/{section_id}", section_id=section_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def publish( + self, + *, + # 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, + ) -> PublishPreferencesResponse: + """Publish the workspace's preferences page. + + Takes a snapshot of every section with + its topics under a new published version, making the current state visible on + the hosted preferences page (non-draft). + """ + return await self._post( + "/preferences/publish", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PublishPreferencesResponse, + ) + + async def replace( + self, + section_id: str, + *, + name: str, + has_custom_routing: Optional[bool] | Omit = omit, + routing_options: Optional[List[ChannelClassification]] | 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, + ) -> PreferenceSectionGetResponse: + """Replace a preference section. + + Full document replacement; missing optional fields + are cleared. Topics attached to the section are unaffected. + + Args: + name: Human-readable name for the section. + + has_custom_routing: Whether the section defines custom routing for its topics. + + routing_options: Default channels for the section. Omit to clear. + + 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 section_id: + raise ValueError(f"Expected a non-empty value for `section_id` but received {section_id!r}") + return await self._put( + path_template("/preferences/sections/{section_id}", section_id=section_id), + body=await async_maybe_transform( + { + "name": name, + "has_custom_routing": has_custom_routing, + "routing_options": routing_options, + }, + preference_section_replace_params.PreferenceSectionReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PreferenceSectionGetResponse, + ) + + +class PreferenceSectionsResourceWithRawResponse: + def __init__(self, preference_sections: PreferenceSectionsResource) -> None: + self._preference_sections = preference_sections + + self.create = to_raw_response_wrapper( + preference_sections.create, + ) + self.retrieve = to_raw_response_wrapper( + preference_sections.retrieve, + ) + self.list = to_raw_response_wrapper( + preference_sections.list, + ) + self.archive = to_raw_response_wrapper( + preference_sections.archive, + ) + self.publish = to_raw_response_wrapper( + preference_sections.publish, + ) + self.replace = to_raw_response_wrapper( + preference_sections.replace, + ) + + @cached_property + def topics(self) -> TopicsResourceWithRawResponse: + return TopicsResourceWithRawResponse(self._preference_sections.topics) + + +class AsyncPreferenceSectionsResourceWithRawResponse: + def __init__(self, preference_sections: AsyncPreferenceSectionsResource) -> None: + self._preference_sections = preference_sections + + self.create = async_to_raw_response_wrapper( + preference_sections.create, + ) + self.retrieve = async_to_raw_response_wrapper( + preference_sections.retrieve, + ) + self.list = async_to_raw_response_wrapper( + preference_sections.list, + ) + self.archive = async_to_raw_response_wrapper( + preference_sections.archive, + ) + self.publish = async_to_raw_response_wrapper( + preference_sections.publish, + ) + self.replace = async_to_raw_response_wrapper( + preference_sections.replace, + ) + + @cached_property + def topics(self) -> AsyncTopicsResourceWithRawResponse: + return AsyncTopicsResourceWithRawResponse(self._preference_sections.topics) + + +class PreferenceSectionsResourceWithStreamingResponse: + def __init__(self, preference_sections: PreferenceSectionsResource) -> None: + self._preference_sections = preference_sections + + self.create = to_streamed_response_wrapper( + preference_sections.create, + ) + self.retrieve = to_streamed_response_wrapper( + preference_sections.retrieve, + ) + self.list = to_streamed_response_wrapper( + preference_sections.list, + ) + self.archive = to_streamed_response_wrapper( + preference_sections.archive, + ) + self.publish = to_streamed_response_wrapper( + preference_sections.publish, + ) + self.replace = to_streamed_response_wrapper( + preference_sections.replace, + ) + + @cached_property + def topics(self) -> TopicsResourceWithStreamingResponse: + return TopicsResourceWithStreamingResponse(self._preference_sections.topics) + + +class AsyncPreferenceSectionsResourceWithStreamingResponse: + def __init__(self, preference_sections: AsyncPreferenceSectionsResource) -> None: + self._preference_sections = preference_sections + + self.create = async_to_streamed_response_wrapper( + preference_sections.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + preference_sections.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + preference_sections.list, + ) + self.archive = async_to_streamed_response_wrapper( + preference_sections.archive, + ) + self.publish = async_to_streamed_response_wrapper( + preference_sections.publish, + ) + self.replace = async_to_streamed_response_wrapper( + preference_sections.replace, + ) + + @cached_property + def topics(self) -> AsyncTopicsResourceWithStreamingResponse: + return AsyncTopicsResourceWithStreamingResponse(self._preference_sections.topics) diff --git a/src/courier/resources/preference_sections/topics.py b/src/courier/resources/preference_sections/topics.py new file mode 100644 index 0000000..4ea2c17 --- /dev/null +++ b/src/courier/resources/preference_sections/topics.py @@ -0,0 +1,646 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, List, Optional +from typing_extensions import Literal + +import httpx + +from ..._types import Body, Omit, Query, Headers, NoneType, 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.preference_sections import topic_create_params, topic_replace_params +from ...types.preference_topic_get_response import PreferenceTopicGetResponse +from ...types.shared.channel_classification import ChannelClassification +from ...types.preference_topic_list_response import PreferenceTopicListResponse + +__all__ = ["TopicsResource", "AsyncTopicsResource"] + + +class TopicsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> TopicsResourceWithRawResponse: + """ + 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/trycourier/courier-python#accessing-raw-response-data-eg-headers + """ + return TopicsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> TopicsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/trycourier/courier-python#with_streaming_response + """ + return TopicsResourceWithStreamingResponse(self) + + def create( + self, + section_id: str, + *, + default_status: Literal["OPTED_OUT", "OPTED_IN", "REQUIRED"], + name: str, + allowed_preferences: Optional[List[Literal["snooze", "channel_preferences"]]] | Omit = omit, + include_unsubscribe_header: Optional[bool] | Omit = omit, + routing_options: Optional[List[ChannelClassification]] | Omit = omit, + topic_data: Optional[Dict[str, object]] | 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, + ) -> PreferenceTopicGetResponse: + """Create a subscription preference topic inside a section. + + Fails with 404 if the + section does not exist. The topic id is generated and returned. + + Args: + default_status: The default subscription status applied when a recipient has not set their own. + + name: Human-readable name for the preference topic. + + allowed_preferences: Preference controls a recipient may customize for this topic. Defaults to empty + if omitted. + + include_unsubscribe_header: Whether to include a list-unsubscribe header on emails for this topic. + + routing_options: Default channels delivered for this topic. Defaults to empty if omitted. + + topic_data: Arbitrary metadata associated with the topic. + + 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 section_id: + raise ValueError(f"Expected a non-empty value for `section_id` but received {section_id!r}") + return self._post( + path_template("/preferences/sections/{section_id}/topics", section_id=section_id), + body=maybe_transform( + { + "default_status": default_status, + "name": name, + "allowed_preferences": allowed_preferences, + "include_unsubscribe_header": include_unsubscribe_header, + "routing_options": routing_options, + "topic_data": topic_data, + }, + topic_create_params.TopicCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PreferenceTopicGetResponse, + ) + + def retrieve( + self, + topic_id: str, + *, + section_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, + ) -> PreferenceTopicGetResponse: + """Retrieve a topic within a section. + + Returns 404 if the section does not exist, + the topic does not exist, or the topic belongs to a different section. + + 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 section_id: + raise ValueError(f"Expected a non-empty value for `section_id` but received {section_id!r}") + if not topic_id: + raise ValueError(f"Expected a non-empty value for `topic_id` but received {topic_id!r}") + return self._get( + path_template( + "/preferences/sections/{section_id}/topics/{topic_id}", section_id=section_id, topic_id=topic_id + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PreferenceTopicGetResponse, + ) + + def list( + self, + section_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, + ) -> PreferenceTopicListResponse: + """ + List the topics in a preference section. + + 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 section_id: + raise ValueError(f"Expected a non-empty value for `section_id` but received {section_id!r}") + return self._get( + path_template("/preferences/sections/{section_id}/topics", section_id=section_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PreferenceTopicListResponse, + ) + + def archive( + self, + topic_id: str, + *, + section_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, + ) -> None: + """Archive a topic and remove it from its section. + + Same 404 rules as GET. + + 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 section_id: + raise ValueError(f"Expected a non-empty value for `section_id` but received {section_id!r}") + if not topic_id: + raise ValueError(f"Expected a non-empty value for `topic_id` but received {topic_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + path_template( + "/preferences/sections/{section_id}/topics/{topic_id}", section_id=section_id, topic_id=topic_id + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def replace( + self, + topic_id: str, + *, + section_id: str, + default_status: Literal["OPTED_OUT", "OPTED_IN", "REQUIRED"], + name: str, + allowed_preferences: Optional[List[Literal["snooze", "channel_preferences"]]] | Omit = omit, + include_unsubscribe_header: Optional[bool] | Omit = omit, + routing_options: Optional[List[ChannelClassification]] | Omit = omit, + topic_data: Optional[Dict[str, object]] | 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, + ) -> PreferenceTopicGetResponse: + """Replace a topic within a section. + + Full document replacement; missing optional + fields are cleared. Same 404 rules as GET. + + Args: + default_status: The default subscription status applied when a recipient has not set their own. + + name: Human-readable name for the preference topic. + + allowed_preferences: Preference controls a recipient may customize. Omit to clear. + + include_unsubscribe_header: Whether to include a list-unsubscribe header on emails for this topic. + + routing_options: Default channels delivered for this topic. Omit to clear. + + topic_data: Arbitrary metadata associated with the topic. Omit to clear. + + 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 section_id: + raise ValueError(f"Expected a non-empty value for `section_id` but received {section_id!r}") + if not topic_id: + raise ValueError(f"Expected a non-empty value for `topic_id` but received {topic_id!r}") + return self._put( + path_template( + "/preferences/sections/{section_id}/topics/{topic_id}", section_id=section_id, topic_id=topic_id + ), + body=maybe_transform( + { + "default_status": default_status, + "name": name, + "allowed_preferences": allowed_preferences, + "include_unsubscribe_header": include_unsubscribe_header, + "routing_options": routing_options, + "topic_data": topic_data, + }, + topic_replace_params.TopicReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PreferenceTopicGetResponse, + ) + + +class AsyncTopicsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncTopicsResourceWithRawResponse: + """ + 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/trycourier/courier-python#accessing-raw-response-data-eg-headers + """ + return AsyncTopicsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncTopicsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/trycourier/courier-python#with_streaming_response + """ + return AsyncTopicsResourceWithStreamingResponse(self) + + async def create( + self, + section_id: str, + *, + default_status: Literal["OPTED_OUT", "OPTED_IN", "REQUIRED"], + name: str, + allowed_preferences: Optional[List[Literal["snooze", "channel_preferences"]]] | Omit = omit, + include_unsubscribe_header: Optional[bool] | Omit = omit, + routing_options: Optional[List[ChannelClassification]] | Omit = omit, + topic_data: Optional[Dict[str, object]] | 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, + ) -> PreferenceTopicGetResponse: + """Create a subscription preference topic inside a section. + + Fails with 404 if the + section does not exist. The topic id is generated and returned. + + Args: + default_status: The default subscription status applied when a recipient has not set their own. + + name: Human-readable name for the preference topic. + + allowed_preferences: Preference controls a recipient may customize for this topic. Defaults to empty + if omitted. + + include_unsubscribe_header: Whether to include a list-unsubscribe header on emails for this topic. + + routing_options: Default channels delivered for this topic. Defaults to empty if omitted. + + topic_data: Arbitrary metadata associated with the topic. + + 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 section_id: + raise ValueError(f"Expected a non-empty value for `section_id` but received {section_id!r}") + return await self._post( + path_template("/preferences/sections/{section_id}/topics", section_id=section_id), + body=await async_maybe_transform( + { + "default_status": default_status, + "name": name, + "allowed_preferences": allowed_preferences, + "include_unsubscribe_header": include_unsubscribe_header, + "routing_options": routing_options, + "topic_data": topic_data, + }, + topic_create_params.TopicCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PreferenceTopicGetResponse, + ) + + async def retrieve( + self, + topic_id: str, + *, + section_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, + ) -> PreferenceTopicGetResponse: + """Retrieve a topic within a section. + + Returns 404 if the section does not exist, + the topic does not exist, or the topic belongs to a different section. + + 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 section_id: + raise ValueError(f"Expected a non-empty value for `section_id` but received {section_id!r}") + if not topic_id: + raise ValueError(f"Expected a non-empty value for `topic_id` but received {topic_id!r}") + return await self._get( + path_template( + "/preferences/sections/{section_id}/topics/{topic_id}", section_id=section_id, topic_id=topic_id + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PreferenceTopicGetResponse, + ) + + async def list( + self, + section_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, + ) -> PreferenceTopicListResponse: + """ + List the topics in a preference section. + + 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 section_id: + raise ValueError(f"Expected a non-empty value for `section_id` but received {section_id!r}") + return await self._get( + path_template("/preferences/sections/{section_id}/topics", section_id=section_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PreferenceTopicListResponse, + ) + + async def archive( + self, + topic_id: str, + *, + section_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, + ) -> None: + """Archive a topic and remove it from its section. + + Same 404 rules as GET. + + 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 section_id: + raise ValueError(f"Expected a non-empty value for `section_id` but received {section_id!r}") + if not topic_id: + raise ValueError(f"Expected a non-empty value for `topic_id` but received {topic_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + path_template( + "/preferences/sections/{section_id}/topics/{topic_id}", section_id=section_id, topic_id=topic_id + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def replace( + self, + topic_id: str, + *, + section_id: str, + default_status: Literal["OPTED_OUT", "OPTED_IN", "REQUIRED"], + name: str, + allowed_preferences: Optional[List[Literal["snooze", "channel_preferences"]]] | Omit = omit, + include_unsubscribe_header: Optional[bool] | Omit = omit, + routing_options: Optional[List[ChannelClassification]] | Omit = omit, + topic_data: Optional[Dict[str, object]] | 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, + ) -> PreferenceTopicGetResponse: + """Replace a topic within a section. + + Full document replacement; missing optional + fields are cleared. Same 404 rules as GET. + + Args: + default_status: The default subscription status applied when a recipient has not set their own. + + name: Human-readable name for the preference topic. + + allowed_preferences: Preference controls a recipient may customize. Omit to clear. + + include_unsubscribe_header: Whether to include a list-unsubscribe header on emails for this topic. + + routing_options: Default channels delivered for this topic. Omit to clear. + + topic_data: Arbitrary metadata associated with the topic. Omit to clear. + + 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 section_id: + raise ValueError(f"Expected a non-empty value for `section_id` but received {section_id!r}") + if not topic_id: + raise ValueError(f"Expected a non-empty value for `topic_id` but received {topic_id!r}") + return await self._put( + path_template( + "/preferences/sections/{section_id}/topics/{topic_id}", section_id=section_id, topic_id=topic_id + ), + body=await async_maybe_transform( + { + "default_status": default_status, + "name": name, + "allowed_preferences": allowed_preferences, + "include_unsubscribe_header": include_unsubscribe_header, + "routing_options": routing_options, + "topic_data": topic_data, + }, + topic_replace_params.TopicReplaceParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PreferenceTopicGetResponse, + ) + + +class TopicsResourceWithRawResponse: + def __init__(self, topics: TopicsResource) -> None: + self._topics = topics + + self.create = to_raw_response_wrapper( + topics.create, + ) + self.retrieve = to_raw_response_wrapper( + topics.retrieve, + ) + self.list = to_raw_response_wrapper( + topics.list, + ) + self.archive = to_raw_response_wrapper( + topics.archive, + ) + self.replace = to_raw_response_wrapper( + topics.replace, + ) + + +class AsyncTopicsResourceWithRawResponse: + def __init__(self, topics: AsyncTopicsResource) -> None: + self._topics = topics + + self.create = async_to_raw_response_wrapper( + topics.create, + ) + self.retrieve = async_to_raw_response_wrapper( + topics.retrieve, + ) + self.list = async_to_raw_response_wrapper( + topics.list, + ) + self.archive = async_to_raw_response_wrapper( + topics.archive, + ) + self.replace = async_to_raw_response_wrapper( + topics.replace, + ) + + +class TopicsResourceWithStreamingResponse: + def __init__(self, topics: TopicsResource) -> None: + self._topics = topics + + self.create = to_streamed_response_wrapper( + topics.create, + ) + self.retrieve = to_streamed_response_wrapper( + topics.retrieve, + ) + self.list = to_streamed_response_wrapper( + topics.list, + ) + self.archive = to_streamed_response_wrapper( + topics.archive, + ) + self.replace = to_streamed_response_wrapper( + topics.replace, + ) + + +class AsyncTopicsResourceWithStreamingResponse: + def __init__(self, topics: AsyncTopicsResource) -> None: + self._topics = topics + + self.create = async_to_streamed_response_wrapper( + topics.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + topics.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + topics.list, + ) + self.archive = async_to_streamed_response_wrapper( + topics.archive, + ) + self.replace = async_to_streamed_response_wrapper( + topics.replace, + ) diff --git a/src/courier/types/__init__.py b/src/courier/types/__init__.py index 22ef85d..bd8105f 100644 --- a/src/courier/types/__init__.py +++ b/src/courier/types/__init__.py @@ -235,6 +235,7 @@ from .journey_segment_trigger_node import JourneySegmentTriggerNode as JourneySegmentTriggerNode from .journey_throttle_static_node import JourneyThrottleStaticNode as JourneyThrottleStaticNode from .notification_retrieve_params import NotificationRetrieveParams as NotificationRetrieveParams +from .publish_preferences_response import PublishPreferencesResponse as PublishPreferencesResponse from .put_tenant_template_response import PutTenantTemplateResponse as PutTenantTemplateResponse from .routing_strategy_list_params import RoutingStrategyListParams as RoutingStrategyListParams from .subscription_topic_new_param import SubscriptionTopicNewParam as SubscriptionTopicNewParam @@ -245,6 +246,7 @@ from .journey_throttle_dynamic_node import JourneyThrottleDynamicNode as JourneyThrottleDynamicNode from .notification_template_payload import NotificationTemplatePayload as NotificationTemplatePayload from .notification_template_summary import NotificationTemplateSummary as NotificationTemplateSummary +from .preference_topic_get_response import PreferenceTopicGetResponse as PreferenceTopicGetResponse from .routing_strategy_get_response import RoutingStrategyGetResponse as RoutingStrategyGetResponse from .translation_retrieve_response import TranslationRetrieveResponse as TranslationRetrieveResponse from .audience_list_members_response import AudienceListMembersResponse as AudienceListMembersResponse @@ -255,19 +257,24 @@ from .journey_versions_list_response import JourneyVersionsListResponse as JourneyVersionsListResponse from .notification_put_locale_params import NotificationPutLocaleParams as NotificationPutLocaleParams from .notification_template_response import NotificationTemplateResponse as NotificationTemplateResponse +from .preference_topic_list_response import PreferenceTopicListResponse as PreferenceTopicListResponse from .routing_strategy_create_params import RoutingStrategyCreateParams as RoutingStrategyCreateParams from .routing_strategy_list_response import RoutingStrategyListResponse as RoutingStrategyListResponse from .inbound_bulk_message_user_param import InboundBulkMessageUserParam as InboundBulkMessageUserParam from .journey_api_invoke_trigger_node import JourneyAPIInvokeTriggerNode as JourneyAPIInvokeTriggerNode from .notification_put_content_params import NotificationPutContentParams as NotificationPutContentParams from .notification_put_element_params import NotificationPutElementParams as NotificationPutElementParams +from .preference_section_get_response import PreferenceSectionGetResponse as PreferenceSectionGetResponse from .routing_strategy_replace_params import RoutingStrategyReplaceParams as RoutingStrategyReplaceParams from .base_template_tenant_association import BaseTemplateTenantAssociation as BaseTemplateTenantAssociation +from .preference_section_create_params import PreferenceSectionCreateParams as PreferenceSectionCreateParams +from .preference_section_list_response import PreferenceSectionListResponse as PreferenceSectionListResponse from .automation_template_list_response import AutomationTemplateListResponse as AutomationTemplateListResponse from .journey_delay_duration_node_param import JourneyDelayDurationNodeParam as JourneyDelayDurationNodeParam from .journey_fetch_post_put_node_param import JourneyFetchPostPutNodeParam as JourneyFetchPostPutNodeParam from .notification_content_get_response import NotificationContentGetResponse as NotificationContentGetResponse from .notification_list_versions_params import NotificationListVersionsParams as NotificationListVersionsParams +from .preference_section_replace_params import PreferenceSectionReplaceParams as PreferenceSectionReplaceParams from .put_subscriptions_recipient_param import PutSubscriptionsRecipientParam as PutSubscriptionsRecipientParam from .journey_segment_trigger_node_param import JourneySegmentTriggerNodeParam as JourneySegmentTriggerNodeParam from .journey_throttle_static_node_param import JourneyThrottleStaticNodeParam as JourneyThrottleStaticNodeParam diff --git a/src/courier/types/preference_section_create_params.py b/src/courier/types/preference_section_create_params.py new file mode 100644 index 0000000..a9d0e77 --- /dev/null +++ b/src/courier/types/preference_section_create_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Optional +from typing_extensions import Required, TypedDict + +from .shared.channel_classification import ChannelClassification + +__all__ = ["PreferenceSectionCreateParams"] + + +class PreferenceSectionCreateParams(TypedDict, total=False): + name: Required[str] + """Human-readable name for the section.""" + + has_custom_routing: Optional[bool] + """Whether the section defines custom routing for its topics.""" + + routing_options: Optional[List[ChannelClassification]] + """Default channels for the section. Defaults to empty if omitted.""" diff --git a/src/courier/types/preference_section_get_response.py b/src/courier/types/preference_section_get_response.py new file mode 100644 index 0000000..1e853c2 --- /dev/null +++ b/src/courier/types/preference_section_get_response.py @@ -0,0 +1,40 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from .._models import BaseModel +from .preference_topic_get_response import PreferenceTopicGetResponse +from .shared.channel_classification import ChannelClassification + +__all__ = ["PreferenceSectionGetResponse"] + + +class PreferenceSectionGetResponse(BaseModel): + """A preference section in your workspace, including its topics.""" + + id: str + """The preference section id.""" + + created: str + """ISO-8601 timestamp of when the section was created.""" + + has_custom_routing: bool + """Whether the section defines custom routing for its topics.""" + + name: str + """Human-readable name.""" + + routing_options: List[ChannelClassification] + """Default channels for the section. May be empty.""" + + topics: List[PreferenceTopicGetResponse] + """The topics contained in this section.""" + + creator: Optional[str] = None + """Id of the creator.""" + + updated: Optional[str] = None + """ISO-8601 timestamp of the last update.""" + + updater: Optional[str] = None + """Id of the last updater.""" diff --git a/src/courier/types/preference_section_list_response.py b/src/courier/types/preference_section_list_response.py new file mode 100644 index 0000000..c825514 --- /dev/null +++ b/src/courier/types/preference_section_list_response.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from .._models import BaseModel +from .preference_section_get_response import PreferenceSectionGetResponse + +__all__ = ["PreferenceSectionListResponse"] + + +class PreferenceSectionListResponse(BaseModel): + """The workspace's preference sections, each with its topics.""" + + results: List[PreferenceSectionGetResponse] diff --git a/src/courier/types/preference_section_replace_params.py b/src/courier/types/preference_section_replace_params.py new file mode 100644 index 0000000..87c2e1a --- /dev/null +++ b/src/courier/types/preference_section_replace_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Optional +from typing_extensions import Required, TypedDict + +from .shared.channel_classification import ChannelClassification + +__all__ = ["PreferenceSectionReplaceParams"] + + +class PreferenceSectionReplaceParams(TypedDict, total=False): + name: Required[str] + """Human-readable name for the section.""" + + has_custom_routing: Optional[bool] + """Whether the section defines custom routing for its topics.""" + + routing_options: Optional[List[ChannelClassification]] + """Default channels for the section. Omit to clear.""" diff --git a/src/courier/types/preference_sections/__init__.py b/src/courier/types/preference_sections/__init__.py new file mode 100644 index 0000000..43664cc --- /dev/null +++ b/src/courier/types/preference_sections/__init__.py @@ -0,0 +1,6 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .topic_create_params import TopicCreateParams as TopicCreateParams +from .topic_replace_params import TopicReplaceParams as TopicReplaceParams diff --git a/src/courier/types/preference_sections/topic_create_params.py b/src/courier/types/preference_sections/topic_create_params.py new file mode 100644 index 0000000..4fdd262 --- /dev/null +++ b/src/courier/types/preference_sections/topic_create_params.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, List, Optional +from typing_extensions import Literal, Required, TypedDict + +from ..shared.channel_classification import ChannelClassification + +__all__ = ["TopicCreateParams"] + + +class TopicCreateParams(TypedDict, total=False): + default_status: Required[Literal["OPTED_OUT", "OPTED_IN", "REQUIRED"]] + """The default subscription status applied when a recipient has not set their own.""" + + name: Required[str] + """Human-readable name for the preference topic.""" + + allowed_preferences: Optional[List[Literal["snooze", "channel_preferences"]]] + """Preference controls a recipient may customize for this topic. + + Defaults to empty if omitted. + """ + + include_unsubscribe_header: Optional[bool] + """Whether to include a list-unsubscribe header on emails for this topic.""" + + routing_options: Optional[List[ChannelClassification]] + """Default channels delivered for this topic. Defaults to empty if omitted.""" + + topic_data: Optional[Dict[str, object]] + """Arbitrary metadata associated with the topic.""" diff --git a/src/courier/types/preference_sections/topic_replace_params.py b/src/courier/types/preference_sections/topic_replace_params.py new file mode 100644 index 0000000..7e6c593 --- /dev/null +++ b/src/courier/types/preference_sections/topic_replace_params.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, List, Optional +from typing_extensions import Literal, Required, TypedDict + +from ..shared.channel_classification import ChannelClassification + +__all__ = ["TopicReplaceParams"] + + +class TopicReplaceParams(TypedDict, total=False): + section_id: Required[str] + + default_status: Required[Literal["OPTED_OUT", "OPTED_IN", "REQUIRED"]] + """The default subscription status applied when a recipient has not set their own.""" + + name: Required[str] + """Human-readable name for the preference topic.""" + + allowed_preferences: Optional[List[Literal["snooze", "channel_preferences"]]] + """Preference controls a recipient may customize. Omit to clear.""" + + include_unsubscribe_header: Optional[bool] + """Whether to include a list-unsubscribe header on emails for this topic.""" + + routing_options: Optional[List[ChannelClassification]] + """Default channels delivered for this topic. Omit to clear.""" + + topic_data: Optional[Dict[str, object]] + """Arbitrary metadata associated with the topic. Omit to clear.""" diff --git a/src/courier/types/preference_topic_get_response.py b/src/courier/types/preference_topic_get_response.py new file mode 100644 index 0000000..1ad846a --- /dev/null +++ b/src/courier/types/preference_topic_get_response.py @@ -0,0 +1,46 @@ +# 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 +from .shared.channel_classification import ChannelClassification + +__all__ = ["PreferenceTopicGetResponse"] + + +class PreferenceTopicGetResponse(BaseModel): + """A subscription preference topic in your workspace.""" + + id: str + """The preference topic id.""" + + allowed_preferences: List[Literal["snooze", "channel_preferences"]] + """Preference controls a recipient may customize. May be empty.""" + + created: str + """ISO-8601 timestamp of when the topic was created.""" + + default_status: Literal["OPTED_OUT", "OPTED_IN", "REQUIRED"] + """The default subscription status applied when a recipient has not set their own.""" + + include_unsubscribe_header: bool + """Whether a list-unsubscribe header is included on emails for this topic.""" + + name: str + """Human-readable name.""" + + routing_options: List[ChannelClassification] + """Default channels delivered for this topic. May be empty.""" + + topic_data: Dict[str, object] + """Arbitrary metadata associated with the topic.""" + + updated: str + """ISO-8601 timestamp of the last update.""" + + creator: Optional[str] = None + """Id of the creator.""" + + updater: Optional[str] = None + """Id of the last updater.""" diff --git a/src/courier/types/preference_topic_list_response.py b/src/courier/types/preference_topic_list_response.py new file mode 100644 index 0000000..47c22c4 --- /dev/null +++ b/src/courier/types/preference_topic_list_response.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from .._models import BaseModel +from .preference_topic_get_response import PreferenceTopicGetResponse + +__all__ = ["PreferenceTopicListResponse"] + + +class PreferenceTopicListResponse(BaseModel): + """Topics contained in a preference section.""" + + results: List[PreferenceTopicGetResponse] diff --git a/src/courier/types/publish_preferences_response.py b/src/courier/types/publish_preferences_response.py new file mode 100644 index 0000000..c179b5c --- /dev/null +++ b/src/courier/types/publish_preferences_response.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from .._models import BaseModel + +__all__ = ["PublishPreferencesResponse"] + + +class PublishPreferencesResponse(BaseModel): + """Result of publishing the workspace's preferences page.""" + + page_id: str + """Id of the published page snapshot.""" + + published_at: str + """ISO-8601 timestamp of the publish.""" + + published_version: float + """Monotonic published version (epoch milliseconds).""" + + preview_url: Optional[str] = None + """Draft-mode hosted preferences page URL for previewing.""" + + published_by: Optional[str] = None + """Id of the publisher.""" diff --git a/tests/api_resources/preference_sections/__init__.py b/tests/api_resources/preference_sections/__init__.py new file mode 100644 index 0000000..fd8019a --- /dev/null +++ b/tests/api_resources/preference_sections/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/preference_sections/test_topics.py b/tests/api_resources/preference_sections/test_topics.py new file mode 100644 index 0000000..1317fd4 --- /dev/null +++ b/tests/api_resources/preference_sections/test_topics.py @@ -0,0 +1,598 @@ +# 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 courier import Courier, AsyncCourier +from tests.utils import assert_matches_type +from courier.types import PreferenceTopicGetResponse, PreferenceTopicListResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestTopics: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_create(self, client: Courier) -> None: + topic = client.preference_sections.topics.create( + section_id="section_id", + default_status="OPTED_OUT", + name="Marketing", + ) + assert_matches_type(PreferenceTopicGetResponse, topic, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_create_with_all_params(self, client: Courier) -> None: + topic = client.preference_sections.topics.create( + section_id="section_id", + default_status="OPTED_OUT", + name="Marketing", + allowed_preferences=["snooze"], + include_unsubscribe_header=True, + routing_options=["direct_message"], + topic_data={"foo": "bar"}, + ) + assert_matches_type(PreferenceTopicGetResponse, topic, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_create(self, client: Courier) -> None: + response = client.preference_sections.topics.with_raw_response.create( + section_id="section_id", + default_status="OPTED_OUT", + name="Marketing", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + topic = response.parse() + assert_matches_type(PreferenceTopicGetResponse, topic, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_create(self, client: Courier) -> None: + with client.preference_sections.topics.with_streaming_response.create( + section_id="section_id", + default_status="OPTED_OUT", + name="Marketing", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + topic = response.parse() + assert_matches_type(PreferenceTopicGetResponse, topic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_create(self, client: Courier) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `section_id` but received ''"): + client.preference_sections.topics.with_raw_response.create( + section_id="", + default_status="OPTED_OUT", + name="Marketing", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_retrieve(self, client: Courier) -> None: + topic = client.preference_sections.topics.retrieve( + topic_id="topic_id", + section_id="section_id", + ) + assert_matches_type(PreferenceTopicGetResponse, topic, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_retrieve(self, client: Courier) -> None: + response = client.preference_sections.topics.with_raw_response.retrieve( + topic_id="topic_id", + section_id="section_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + topic = response.parse() + assert_matches_type(PreferenceTopicGetResponse, topic, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_retrieve(self, client: Courier) -> None: + with client.preference_sections.topics.with_streaming_response.retrieve( + topic_id="topic_id", + section_id="section_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + topic = response.parse() + assert_matches_type(PreferenceTopicGetResponse, topic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_retrieve(self, client: Courier) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `section_id` but received ''"): + client.preference_sections.topics.with_raw_response.retrieve( + topic_id="topic_id", + section_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `topic_id` but received ''"): + client.preference_sections.topics.with_raw_response.retrieve( + topic_id="", + section_id="section_id", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list(self, client: Courier) -> None: + topic = client.preference_sections.topics.list( + "section_id", + ) + assert_matches_type(PreferenceTopicListResponse, topic, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_list(self, client: Courier) -> None: + response = client.preference_sections.topics.with_raw_response.list( + "section_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + topic = response.parse() + assert_matches_type(PreferenceTopicListResponse, topic, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_list(self, client: Courier) -> None: + with client.preference_sections.topics.with_streaming_response.list( + "section_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + topic = response.parse() + assert_matches_type(PreferenceTopicListResponse, topic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_list(self, client: Courier) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `section_id` but received ''"): + client.preference_sections.topics.with_raw_response.list( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_archive(self, client: Courier) -> None: + topic = client.preference_sections.topics.archive( + topic_id="topic_id", + section_id="section_id", + ) + assert topic is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_archive(self, client: Courier) -> None: + response = client.preference_sections.topics.with_raw_response.archive( + topic_id="topic_id", + section_id="section_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + topic = response.parse() + assert topic is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_archive(self, client: Courier) -> None: + with client.preference_sections.topics.with_streaming_response.archive( + topic_id="topic_id", + section_id="section_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + topic = response.parse() + assert topic is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_archive(self, client: Courier) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `section_id` but received ''"): + client.preference_sections.topics.with_raw_response.archive( + topic_id="topic_id", + section_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `topic_id` but received ''"): + client.preference_sections.topics.with_raw_response.archive( + topic_id="", + section_id="section_id", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_replace(self, client: Courier) -> None: + topic = client.preference_sections.topics.replace( + topic_id="topic_id", + section_id="section_id", + default_status="OPTED_OUT", + name="name", + ) + assert_matches_type(PreferenceTopicGetResponse, topic, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_replace_with_all_params(self, client: Courier) -> None: + topic = client.preference_sections.topics.replace( + topic_id="topic_id", + section_id="section_id", + default_status="OPTED_OUT", + name="name", + allowed_preferences=["snooze"], + include_unsubscribe_header=True, + routing_options=["direct_message"], + topic_data={"foo": "bar"}, + ) + assert_matches_type(PreferenceTopicGetResponse, topic, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_replace(self, client: Courier) -> None: + response = client.preference_sections.topics.with_raw_response.replace( + topic_id="topic_id", + section_id="section_id", + default_status="OPTED_OUT", + name="name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + topic = response.parse() + assert_matches_type(PreferenceTopicGetResponse, topic, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_replace(self, client: Courier) -> None: + with client.preference_sections.topics.with_streaming_response.replace( + topic_id="topic_id", + section_id="section_id", + default_status="OPTED_OUT", + name="name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + topic = response.parse() + assert_matches_type(PreferenceTopicGetResponse, topic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_replace(self, client: Courier) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `section_id` but received ''"): + client.preference_sections.topics.with_raw_response.replace( + topic_id="topic_id", + section_id="", + default_status="OPTED_OUT", + name="name", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `topic_id` but received ''"): + client.preference_sections.topics.with_raw_response.replace( + topic_id="", + section_id="section_id", + default_status="OPTED_OUT", + name="name", + ) + + +class TestAsyncTopics: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_create(self, async_client: AsyncCourier) -> None: + topic = await async_client.preference_sections.topics.create( + section_id="section_id", + default_status="OPTED_OUT", + name="Marketing", + ) + assert_matches_type(PreferenceTopicGetResponse, topic, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncCourier) -> None: + topic = await async_client.preference_sections.topics.create( + section_id="section_id", + default_status="OPTED_OUT", + name="Marketing", + allowed_preferences=["snooze"], + include_unsubscribe_header=True, + routing_options=["direct_message"], + topic_data={"foo": "bar"}, + ) + assert_matches_type(PreferenceTopicGetResponse, topic, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_create(self, async_client: AsyncCourier) -> None: + response = await async_client.preference_sections.topics.with_raw_response.create( + section_id="section_id", + default_status="OPTED_OUT", + name="Marketing", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + topic = await response.parse() + assert_matches_type(PreferenceTopicGetResponse, topic, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_create(self, async_client: AsyncCourier) -> None: + async with async_client.preference_sections.topics.with_streaming_response.create( + section_id="section_id", + default_status="OPTED_OUT", + name="Marketing", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + topic = await response.parse() + assert_matches_type(PreferenceTopicGetResponse, topic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_create(self, async_client: AsyncCourier) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `section_id` but received ''"): + await async_client.preference_sections.topics.with_raw_response.create( + section_id="", + default_status="OPTED_OUT", + name="Marketing", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_retrieve(self, async_client: AsyncCourier) -> None: + topic = await async_client.preference_sections.topics.retrieve( + topic_id="topic_id", + section_id="section_id", + ) + assert_matches_type(PreferenceTopicGetResponse, topic, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncCourier) -> None: + response = await async_client.preference_sections.topics.with_raw_response.retrieve( + topic_id="topic_id", + section_id="section_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + topic = await response.parse() + assert_matches_type(PreferenceTopicGetResponse, topic, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncCourier) -> None: + async with async_client.preference_sections.topics.with_streaming_response.retrieve( + topic_id="topic_id", + section_id="section_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + topic = await response.parse() + assert_matches_type(PreferenceTopicGetResponse, topic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncCourier) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `section_id` but received ''"): + await async_client.preference_sections.topics.with_raw_response.retrieve( + topic_id="topic_id", + section_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `topic_id` but received ''"): + await async_client.preference_sections.topics.with_raw_response.retrieve( + topic_id="", + section_id="section_id", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list(self, async_client: AsyncCourier) -> None: + topic = await async_client.preference_sections.topics.list( + "section_id", + ) + assert_matches_type(PreferenceTopicListResponse, topic, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_list(self, async_client: AsyncCourier) -> None: + response = await async_client.preference_sections.topics.with_raw_response.list( + "section_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + topic = await response.parse() + assert_matches_type(PreferenceTopicListResponse, topic, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_list(self, async_client: AsyncCourier) -> None: + async with async_client.preference_sections.topics.with_streaming_response.list( + "section_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + topic = await response.parse() + assert_matches_type(PreferenceTopicListResponse, topic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_list(self, async_client: AsyncCourier) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `section_id` but received ''"): + await async_client.preference_sections.topics.with_raw_response.list( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_archive(self, async_client: AsyncCourier) -> None: + topic = await async_client.preference_sections.topics.archive( + topic_id="topic_id", + section_id="section_id", + ) + assert topic is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_archive(self, async_client: AsyncCourier) -> None: + response = await async_client.preference_sections.topics.with_raw_response.archive( + topic_id="topic_id", + section_id="section_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + topic = await response.parse() + assert topic is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_archive(self, async_client: AsyncCourier) -> None: + async with async_client.preference_sections.topics.with_streaming_response.archive( + topic_id="topic_id", + section_id="section_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + topic = await response.parse() + assert topic is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_archive(self, async_client: AsyncCourier) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `section_id` but received ''"): + await async_client.preference_sections.topics.with_raw_response.archive( + topic_id="topic_id", + section_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `topic_id` but received ''"): + await async_client.preference_sections.topics.with_raw_response.archive( + topic_id="", + section_id="section_id", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_replace(self, async_client: AsyncCourier) -> None: + topic = await async_client.preference_sections.topics.replace( + topic_id="topic_id", + section_id="section_id", + default_status="OPTED_OUT", + name="name", + ) + assert_matches_type(PreferenceTopicGetResponse, topic, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_replace_with_all_params(self, async_client: AsyncCourier) -> None: + topic = await async_client.preference_sections.topics.replace( + topic_id="topic_id", + section_id="section_id", + default_status="OPTED_OUT", + name="name", + allowed_preferences=["snooze"], + include_unsubscribe_header=True, + routing_options=["direct_message"], + topic_data={"foo": "bar"}, + ) + assert_matches_type(PreferenceTopicGetResponse, topic, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_replace(self, async_client: AsyncCourier) -> None: + response = await async_client.preference_sections.topics.with_raw_response.replace( + topic_id="topic_id", + section_id="section_id", + default_status="OPTED_OUT", + name="name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + topic = await response.parse() + assert_matches_type(PreferenceTopicGetResponse, topic, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_replace(self, async_client: AsyncCourier) -> None: + async with async_client.preference_sections.topics.with_streaming_response.replace( + topic_id="topic_id", + section_id="section_id", + default_status="OPTED_OUT", + name="name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + topic = await response.parse() + assert_matches_type(PreferenceTopicGetResponse, topic, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_replace(self, async_client: AsyncCourier) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `section_id` but received ''"): + await async_client.preference_sections.topics.with_raw_response.replace( + topic_id="topic_id", + section_id="", + default_status="OPTED_OUT", + name="name", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `topic_id` but received ''"): + await async_client.preference_sections.topics.with_raw_response.replace( + topic_id="", + section_id="section_id", + default_status="OPTED_OUT", + name="name", + ) diff --git a/tests/api_resources/test_preference_sections.py b/tests/api_resources/test_preference_sections.py new file mode 100644 index 0000000..fc02cc3 --- /dev/null +++ b/tests/api_resources/test_preference_sections.py @@ -0,0 +1,510 @@ +# 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 courier import Courier, AsyncCourier +from tests.utils import assert_matches_type +from courier.types import ( + PublishPreferencesResponse, + PreferenceSectionGetResponse, + PreferenceSectionListResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestPreferenceSections: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_create(self, client: Courier) -> None: + preference_section = client.preference_sections.create( + name="Account Notifications", + ) + assert_matches_type(PreferenceSectionGetResponse, preference_section, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_create_with_all_params(self, client: Courier) -> None: + preference_section = client.preference_sections.create( + name="Account Notifications", + has_custom_routing=True, + routing_options=["direct_message"], + ) + assert_matches_type(PreferenceSectionGetResponse, preference_section, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_create(self, client: Courier) -> None: + response = client.preference_sections.with_raw_response.create( + name="Account Notifications", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + preference_section = response.parse() + assert_matches_type(PreferenceSectionGetResponse, preference_section, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_create(self, client: Courier) -> None: + with client.preference_sections.with_streaming_response.create( + name="Account Notifications", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + preference_section = response.parse() + assert_matches_type(PreferenceSectionGetResponse, preference_section, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_retrieve(self, client: Courier) -> None: + preference_section = client.preference_sections.retrieve( + "section_id", + ) + assert_matches_type(PreferenceSectionGetResponse, preference_section, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_retrieve(self, client: Courier) -> None: + response = client.preference_sections.with_raw_response.retrieve( + "section_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + preference_section = response.parse() + assert_matches_type(PreferenceSectionGetResponse, preference_section, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_retrieve(self, client: Courier) -> None: + with client.preference_sections.with_streaming_response.retrieve( + "section_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + preference_section = response.parse() + assert_matches_type(PreferenceSectionGetResponse, preference_section, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_retrieve(self, client: Courier) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `section_id` but received ''"): + client.preference_sections.with_raw_response.retrieve( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list(self, client: Courier) -> None: + preference_section = client.preference_sections.list() + assert_matches_type(PreferenceSectionListResponse, preference_section, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_list(self, client: Courier) -> None: + response = client.preference_sections.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + preference_section = response.parse() + assert_matches_type(PreferenceSectionListResponse, preference_section, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_list(self, client: Courier) -> None: + with client.preference_sections.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + preference_section = response.parse() + assert_matches_type(PreferenceSectionListResponse, preference_section, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_archive(self, client: Courier) -> None: + preference_section = client.preference_sections.archive( + "section_id", + ) + assert preference_section is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_archive(self, client: Courier) -> None: + response = client.preference_sections.with_raw_response.archive( + "section_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + preference_section = response.parse() + assert preference_section is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_archive(self, client: Courier) -> None: + with client.preference_sections.with_streaming_response.archive( + "section_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + preference_section = response.parse() + assert preference_section is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_archive(self, client: Courier) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `section_id` but received ''"): + client.preference_sections.with_raw_response.archive( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_publish(self, client: Courier) -> None: + preference_section = client.preference_sections.publish() + assert_matches_type(PublishPreferencesResponse, preference_section, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_publish(self, client: Courier) -> None: + response = client.preference_sections.with_raw_response.publish() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + preference_section = response.parse() + assert_matches_type(PublishPreferencesResponse, preference_section, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_publish(self, client: Courier) -> None: + with client.preference_sections.with_streaming_response.publish() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + preference_section = response.parse() + assert_matches_type(PublishPreferencesResponse, preference_section, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_replace(self, client: Courier) -> None: + preference_section = client.preference_sections.replace( + section_id="section_id", + name="name", + ) + assert_matches_type(PreferenceSectionGetResponse, preference_section, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_replace_with_all_params(self, client: Courier) -> None: + preference_section = client.preference_sections.replace( + section_id="section_id", + name="name", + has_custom_routing=True, + routing_options=["direct_message"], + ) + assert_matches_type(PreferenceSectionGetResponse, preference_section, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_replace(self, client: Courier) -> None: + response = client.preference_sections.with_raw_response.replace( + section_id="section_id", + name="name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + preference_section = response.parse() + assert_matches_type(PreferenceSectionGetResponse, preference_section, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_replace(self, client: Courier) -> None: + with client.preference_sections.with_streaming_response.replace( + section_id="section_id", + name="name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + preference_section = response.parse() + assert_matches_type(PreferenceSectionGetResponse, preference_section, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_replace(self, client: Courier) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `section_id` but received ''"): + client.preference_sections.with_raw_response.replace( + section_id="", + name="name", + ) + + +class TestAsyncPreferenceSections: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_create(self, async_client: AsyncCourier) -> None: + preference_section = await async_client.preference_sections.create( + name="Account Notifications", + ) + assert_matches_type(PreferenceSectionGetResponse, preference_section, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncCourier) -> None: + preference_section = await async_client.preference_sections.create( + name="Account Notifications", + has_custom_routing=True, + routing_options=["direct_message"], + ) + assert_matches_type(PreferenceSectionGetResponse, preference_section, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_create(self, async_client: AsyncCourier) -> None: + response = await async_client.preference_sections.with_raw_response.create( + name="Account Notifications", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + preference_section = await response.parse() + assert_matches_type(PreferenceSectionGetResponse, preference_section, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_create(self, async_client: AsyncCourier) -> None: + async with async_client.preference_sections.with_streaming_response.create( + name="Account Notifications", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + preference_section = await response.parse() + assert_matches_type(PreferenceSectionGetResponse, preference_section, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_retrieve(self, async_client: AsyncCourier) -> None: + preference_section = await async_client.preference_sections.retrieve( + "section_id", + ) + assert_matches_type(PreferenceSectionGetResponse, preference_section, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncCourier) -> None: + response = await async_client.preference_sections.with_raw_response.retrieve( + "section_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + preference_section = await response.parse() + assert_matches_type(PreferenceSectionGetResponse, preference_section, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncCourier) -> None: + async with async_client.preference_sections.with_streaming_response.retrieve( + "section_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + preference_section = await response.parse() + assert_matches_type(PreferenceSectionGetResponse, preference_section, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncCourier) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `section_id` but received ''"): + await async_client.preference_sections.with_raw_response.retrieve( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list(self, async_client: AsyncCourier) -> None: + preference_section = await async_client.preference_sections.list() + assert_matches_type(PreferenceSectionListResponse, preference_section, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_list(self, async_client: AsyncCourier) -> None: + response = await async_client.preference_sections.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + preference_section = await response.parse() + assert_matches_type(PreferenceSectionListResponse, preference_section, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_list(self, async_client: AsyncCourier) -> None: + async with async_client.preference_sections.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + preference_section = await response.parse() + assert_matches_type(PreferenceSectionListResponse, preference_section, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_archive(self, async_client: AsyncCourier) -> None: + preference_section = await async_client.preference_sections.archive( + "section_id", + ) + assert preference_section is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_archive(self, async_client: AsyncCourier) -> None: + response = await async_client.preference_sections.with_raw_response.archive( + "section_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + preference_section = await response.parse() + assert preference_section is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_archive(self, async_client: AsyncCourier) -> None: + async with async_client.preference_sections.with_streaming_response.archive( + "section_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + preference_section = await response.parse() + assert preference_section is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_archive(self, async_client: AsyncCourier) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `section_id` but received ''"): + await async_client.preference_sections.with_raw_response.archive( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_publish(self, async_client: AsyncCourier) -> None: + preference_section = await async_client.preference_sections.publish() + assert_matches_type(PublishPreferencesResponse, preference_section, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_publish(self, async_client: AsyncCourier) -> None: + response = await async_client.preference_sections.with_raw_response.publish() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + preference_section = await response.parse() + assert_matches_type(PublishPreferencesResponse, preference_section, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_publish(self, async_client: AsyncCourier) -> None: + async with async_client.preference_sections.with_streaming_response.publish() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + preference_section = await response.parse() + assert_matches_type(PublishPreferencesResponse, preference_section, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_replace(self, async_client: AsyncCourier) -> None: + preference_section = await async_client.preference_sections.replace( + section_id="section_id", + name="name", + ) + assert_matches_type(PreferenceSectionGetResponse, preference_section, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_replace_with_all_params(self, async_client: AsyncCourier) -> None: + preference_section = await async_client.preference_sections.replace( + section_id="section_id", + name="name", + has_custom_routing=True, + routing_options=["direct_message"], + ) + assert_matches_type(PreferenceSectionGetResponse, preference_section, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_replace(self, async_client: AsyncCourier) -> None: + response = await async_client.preference_sections.with_raw_response.replace( + section_id="section_id", + name="name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + preference_section = await response.parse() + assert_matches_type(PreferenceSectionGetResponse, preference_section, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_replace(self, async_client: AsyncCourier) -> None: + async with async_client.preference_sections.with_streaming_response.replace( + section_id="section_id", + name="name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + preference_section = await response.parse() + assert_matches_type(PreferenceSectionGetResponse, preference_section, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_replace(self, async_client: AsyncCourier) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `section_id` but received ''"): + await async_client.preference_sections.with_raw_response.replace( + section_id="", + name="name", + )