diff --git a/src/knockapi/_base_client.py b/src/knockapi/_base_client.py index 07161fcb..132238eb 100644 --- a/src/knockapi/_base_client.py +++ b/src/knockapi/_base_client.py @@ -34,9 +34,7 @@ import anyio import httpx import distro -import pydantic from httpx import URL -from pydantic import PrivateAttr from . import _exceptions from ._qs import Querystring @@ -61,6 +59,7 @@ from ._utils import is_dict, is_list, asyncify, is_given, lru_cache, is_mapping from ._compat import PYDANTIC_V1, model_copy, model_dump from ._models import GenericModel, FinalRequestOptions, validate_type, construct_type +from ._pydantic import PrivateAttr, ValidationError as _ValidationError from ._response import ( APIResponse, BaseAPIResponse, @@ -224,7 +223,7 @@ def _info_to_options(self, info: PageInfo) -> FinalRequestOptions: class BaseSyncPage(BasePage[_T], Generic[_T]): - _client: SyncAPIClient = pydantic.PrivateAttr() + _client: SyncAPIClient = PrivateAttr() def _set_private_attributes( self, @@ -312,7 +311,7 @@ async def __aiter__(self) -> AsyncIterator[_T]: class BaseAsyncPage(BasePage[_T], Generic[_T]): - _client: AsyncAPIClient = pydantic.PrivateAttr() + _client: AsyncAPIClient = PrivateAttr() def _set_private_attributes( self, @@ -626,7 +625,7 @@ def _process_response_data( return cast(ResponseT, validate_type(type_=cast_to, value=data)) return cast(ResponseT, construct_type(type_=cast_to, value=data)) - except pydantic.ValidationError as err: + except _ValidationError as err: raise APIResponseValidationError(response=response, body=data) from err @property diff --git a/src/knockapi/_compat.py b/src/knockapi/_compat.py index bdef67f0..4c783a6f 100644 --- a/src/knockapi/_compat.py +++ b/src/knockapi/_compat.py @@ -17,7 +17,7 @@ # Pyright incorrectly reports some of our functions as overriding a method when they don't # pyright: reportIncompatibleMethodOverride=false -PYDANTIC_V1 = pydantic.VERSION.startswith("1.") +PYDANTIC_V1 = True if TYPE_CHECKING: @@ -43,16 +43,29 @@ def is_typeddict(type_: type[Any]) -> bool: # noqa: ARG001 ... else: - # v1 re-exports + # v1 re-exports — route through pydantic.v1 when v2 is installed if PYDANTIC_V1: - from pydantic.typing import ( - get_args as get_args, - is_union as is_union, - get_origin as get_origin, - is_typeddict as is_typeddict, - is_literal_type as is_literal_type, - ) - from pydantic.datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime + if not pydantic.VERSION.startswith("1."): + from pydantic.v1.typing import ( # type: ignore[no-redef] + get_args as get_args, + is_union as is_union, + get_origin as get_origin, + is_typeddict as is_typeddict, + is_literal_type as is_literal_type, + ) + from pydantic.v1.datetime_parse import ( # type: ignore[no-redef] + parse_date as parse_date, + parse_datetime as parse_datetime, + ) + else: + from pydantic.typing import ( + get_args as get_args, + is_union as is_union, + get_origin as get_origin, + is_typeddict as is_typeddict, + is_literal_type as is_literal_type, + ) + from pydantic.datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime else: from ._utils import ( get_args as get_args, @@ -172,9 +185,14 @@ class GenericModel(pydantic.BaseModel): ... else: if PYDANTIC_V1: - import pydantic.generics + if not pydantic.VERSION.startswith("1."): + import pydantic.v1.generics # type: ignore[import-untyped] + + class GenericModel(pydantic.v1.generics.GenericModel, pydantic.v1.BaseModel): ... # type: ignore[no-redef] + else: + import pydantic.generics - class GenericModel(pydantic.generics.GenericModel, pydantic.BaseModel): ... + class GenericModel(pydantic.generics.GenericModel, pydantic.BaseModel): ... else: # there no longer needs to be a distinction in v2 but # we still have to create our own subclass to avoid diff --git a/src/knockapi/_models.py b/src/knockapi/_models.py index 6a3cd1d2..3a958656 100644 --- a/src/knockapi/_models.py +++ b/src/knockapi/_models.py @@ -67,6 +67,10 @@ if TYPE_CHECKING: from pydantic_core.core_schema import ModelField, ModelSchema, LiteralSchema, ModelFieldsSchema + _PydanticV1BaseModel = pydantic.BaseModel +else: + from ._pydantic import BaseModel as _PydanticV1BaseModel + __all__ = ["BaseModel", "GenericModel"] _T = TypeVar("_T") @@ -80,7 +84,7 @@ class _ConfigProtocol(Protocol): allow_population_by_field_name: bool -class BaseModel(pydantic.BaseModel): +class BaseModel(_PydanticV1BaseModel): # type: ignore[misc] if PYDANTIC_V1: @property @@ -89,8 +93,8 @@ def model_fields_set(self) -> set[str]: # a forwards-compat shim for pydantic v2 return self.__fields_set__ # type: ignore - class Config(pydantic.BaseConfig): # pyright: ignore[reportDeprecated] - extra: Any = pydantic.Extra.allow # type: ignore + class Config(_PydanticV1BaseModel.Config): # type: ignore[misc, name-defined] + extra = "allow" # type: ignore else: model_config: ClassVar[ConfigDict] = ConfigDict( extra="allow", defer_build=coerce_boolean(os.environ.get("DEFER_PYDANTIC_BUILD", "true")) @@ -260,6 +264,7 @@ def model_dump( exclude_unset: bool = False, exclude_defaults: bool = False, exclude_none: bool = False, + exclude_computed_fields: bool = False, round_trip: bool = False, warnings: bool | Literal["none", "warn", "error"] = True, context: dict[str, Any] | None = None, @@ -288,6 +293,8 @@ def model_dump( """ if mode not in {"json", "python"}: raise ValueError("mode must be either 'json' or 'python'") + if exclude_computed_fields != False: + raise ValueError("exclude_computed_fields is only supported in Pydantic v2") if round_trip != False: raise ValueError("round_trip is only supported in Pydantic v2") if warnings != True: @@ -314,12 +321,14 @@ def model_dump_json( self, *, indent: int | None = None, + ensure_ascii: bool = False, include: IncEx | None = None, exclude: IncEx | None = None, by_alias: bool | None = None, exclude_unset: bool = False, exclude_defaults: bool = False, exclude_none: bool = False, + exclude_computed_fields: bool = False, round_trip: bool = False, warnings: bool | Literal["none", "warn", "error"] = True, context: dict[str, Any] | None = None, @@ -344,6 +353,10 @@ def model_dump_json( Returns: A JSON string representation of the model. """ + if ensure_ascii != False: + raise ValueError("ensure_ascii is only supported in Pydantic v2") + if exclude_computed_fields != False: + raise ValueError("exclude_computed_fields is only supported in Pydantic v2") if round_trip != False: raise ValueError("round_trip is only supported in Pydantic v2") if warnings != True: @@ -771,7 +784,7 @@ class FinalRequestOptionsInput(TypedDict, total=False): @final -class FinalRequestOptions(pydantic.BaseModel): +class FinalRequestOptions(_PydanticV1BaseModel): # type: ignore[misc] method: str url: str params: Query = {} @@ -790,7 +803,7 @@ class FinalRequestOptions(pydantic.BaseModel): if PYDANTIC_V1: - class Config(pydantic.BaseConfig): # pyright: ignore[reportDeprecated] + class Config(_PydanticV1BaseModel.Config): # type: ignore[misc, name-defined] arbitrary_types_allowed: bool = True else: model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True) diff --git a/src/knockapi/_pydantic.py b/src/knockapi/_pydantic.py new file mode 100644 index 00000000..b88f5352 --- /dev/null +++ b/src/knockapi/_pydantic.py @@ -0,0 +1,18 @@ +"""Central pydantic compatibility shim. + +When pydantic v2 is installed, import from the bundled v1 compat layer +(pydantic.v1). When pydantic v1 is installed natively, import directly. +""" + +from __future__ import annotations + +import pydantic + +if not pydantic.VERSION.startswith("1."): + from pydantic.v1 import Field, BaseModel, BaseConfig, PrivateAttr, ValidationError # type: ignore[no-redef] + from pydantic.v1.fields import FieldInfo # type: ignore[no-redef, assignment] +else: + from pydantic import Field, BaseModel, BaseConfig, PrivateAttr, ValidationError # type: ignore[assignment] + from pydantic.fields import FieldInfo # type: ignore[assignment] + +__all__ = ["BaseConfig", "BaseModel", "Field", "FieldInfo", "PrivateAttr", "ValidationError"] diff --git a/src/knockapi/_response.py b/src/knockapi/_response.py index b6c164b7..a8924872 100644 --- a/src/knockapi/_response.py +++ b/src/knockapi/_response.py @@ -32,8 +32,12 @@ from ._exceptions import KnockError, APIResponseValidationError if TYPE_CHECKING: + _PydanticBaseModel = pydantic.BaseModel + from ._models import FinalRequestOptions from ._base_client import BaseClient +else: + from ._pydantic import BaseModel as _PydanticBaseModel P = ParamSpec("P") @@ -215,7 +219,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: origin # pyright: ignore[reportUnknownArgumentType] ) and not issubclass(origin, BaseModel) - and issubclass(origin, pydantic.BaseModel) + and (issubclass(origin, _PydanticBaseModel) or issubclass(origin, pydantic.BaseModel)) ): raise TypeError("Pydantic models must subclass our base model type, e.g. `from knockapi import BaseModel`") diff --git a/src/knockapi/_utils/_transform.py b/src/knockapi/_utils/_transform.py index 52075492..d7e16fdf 100644 --- a/src/knockapi/_utils/_transform.py +++ b/src/knockapi/_utils/_transform.py @@ -3,13 +3,18 @@ import io import base64 import pathlib -from typing import Any, Mapping, TypeVar, cast +from typing import TYPE_CHECKING, Any, Mapping, TypeVar, cast from datetime import date, datetime from typing_extensions import Literal, get_args, override, get_type_hints as _get_type_hints import anyio import pydantic +if TYPE_CHECKING: + _PydanticBaseModel = pydantic.BaseModel +else: + from .._pydantic import BaseModel as _PydanticBaseModel + from ._utils import ( is_list, is_given, @@ -217,7 +222,7 @@ def _transform_recursive( data = _transform_recursive(data, annotation=annotation, inner_type=subtype) return data - if isinstance(data, pydantic.BaseModel): + if isinstance(data, _PydanticBaseModel): return model_dump(data, exclude_unset=True, mode="json") annotated_type = _get_annotated_type(annotation) @@ -383,7 +388,7 @@ async def _async_transform_recursive( data = await _async_transform_recursive(data, annotation=annotation, inner_type=subtype) return data - if isinstance(data, pydantic.BaseModel): + if isinstance(data, _PydanticBaseModel): return model_dump(data, exclude_unset=True, mode="json") annotated_type = _get_annotated_type(annotation) diff --git a/src/knockapi/types/activity.py b/src/knockapi/types/activity.py index 4f1d6e3d..56c9f124 100644 --- a/src/knockapi/types/activity.py +++ b/src/knockapi/types/activity.py @@ -3,10 +3,9 @@ from typing import Dict, Optional from datetime import datetime -from pydantic import Field as FieldInfo - from .._models import BaseModel from .recipient import Recipient +from .._pydantic import Field as FieldInfo __all__ = ["Activity"] diff --git a/src/knockapi/types/audience_member.py b/src/knockapi/types/audience_member.py index d7eac530..72a1e698 100644 --- a/src/knockapi/types/audience_member.py +++ b/src/knockapi/types/audience_member.py @@ -3,10 +3,9 @@ from typing import Optional from datetime import datetime -from pydantic import Field as FieldInfo - from .user import User from .._models import BaseModel +from .._pydantic import Field as FieldInfo __all__ = ["AudienceMember"] diff --git a/src/knockapi/types/bulk_operation.py b/src/knockapi/types/bulk_operation.py index 58d6e6b7..63803d82 100644 --- a/src/knockapi/types/bulk_operation.py +++ b/src/knockapi/types/bulk_operation.py @@ -4,9 +4,8 @@ from datetime import datetime from typing_extensions import Literal -from pydantic import Field as FieldInfo - from .._models import BaseModel +from .._pydantic import Field as FieldInfo __all__ = ["BulkOperation", "ErrorItem"] diff --git a/src/knockapi/types/message.py b/src/knockapi/types/message.py index dc8a8bc4..65041839 100644 --- a/src/knockapi/types/message.py +++ b/src/knockapi/types/message.py @@ -4,9 +4,8 @@ from datetime import datetime from typing_extensions import Literal -from pydantic import Field as FieldInfo - from .._models import BaseModel +from .._pydantic import Field as FieldInfo from .recipient_reference import RecipientReference __all__ = ["Message", "Source", "Channel"] diff --git a/src/knockapi/types/message_delivery_log.py b/src/knockapi/types/message_delivery_log.py index 49273a63..7205250e 100644 --- a/src/knockapi/types/message_delivery_log.py +++ b/src/knockapi/types/message_delivery_log.py @@ -3,9 +3,8 @@ from typing import Dict, Union, Optional from typing_extensions import Literal -from pydantic import Field as FieldInfo - from .._models import BaseModel +from .._pydantic import Field as FieldInfo __all__ = ["MessageDeliveryLog", "Request", "Response"] diff --git a/src/knockapi/types/message_event.py b/src/knockapi/types/message_event.py index dba46e24..db7f0463 100644 --- a/src/knockapi/types/message_event.py +++ b/src/knockapi/types/message_event.py @@ -4,9 +4,8 @@ from datetime import datetime from typing_extensions import Literal -from pydantic import Field as FieldInfo - from .._models import BaseModel +from .._pydantic import Field as FieldInfo from .recipient_reference import RecipientReference __all__ = ["MessageEvent"] diff --git a/src/knockapi/types/message_get_content_response.py b/src/knockapi/types/message_get_content_response.py index c22339a4..b50c3134 100644 --- a/src/knockapi/types/message_get_content_response.py +++ b/src/knockapi/types/message_get_content_response.py @@ -4,9 +4,8 @@ from datetime import datetime from typing_extensions import Literal, TypeAlias -from pydantic import Field as FieldInfo - from .._models import BaseModel +from .._pydantic import Field as FieldInfo __all__ = [ "MessageGetContentResponse", diff --git a/src/knockapi/types/messages/batch_get_content_response.py b/src/knockapi/types/messages/batch_get_content_response.py index 1205f7a9..b3363474 100644 --- a/src/knockapi/types/messages/batch_get_content_response.py +++ b/src/knockapi/types/messages/batch_get_content_response.py @@ -4,9 +4,8 @@ from datetime import datetime from typing_extensions import Literal, TypeAlias -from pydantic import Field as FieldInfo - from ..._models import BaseModel +from ..._pydantic import Field as FieldInfo __all__ = [ "BatchGetContentResponse", diff --git a/src/knockapi/types/object.py b/src/knockapi/types/object.py index 3d2ed638..a5ba3abb 100644 --- a/src/knockapi/types/object.py +++ b/src/knockapi/types/object.py @@ -3,9 +3,8 @@ from typing import Dict, Optional from datetime import datetime -from pydantic import Field as FieldInfo - from .._models import BaseModel +from .._pydantic import Field as FieldInfo __all__ = ["Object"] diff --git a/src/knockapi/types/providers/ms_team_list_channels_response.py b/src/knockapi/types/providers/ms_team_list_channels_response.py index 5d4ad75c..239f9c96 100644 --- a/src/knockapi/types/providers/ms_team_list_channels_response.py +++ b/src/knockapi/types/providers/ms_team_list_channels_response.py @@ -2,9 +2,8 @@ from typing import List, Optional -from pydantic import Field as FieldInfo - from ..._models import BaseModel +from ..._pydantic import Field as FieldInfo __all__ = ["MsTeamListChannelsResponse", "MsTeamsChannel"] diff --git a/src/knockapi/types/providers/ms_team_list_teams_response.py b/src/knockapi/types/providers/ms_team_list_teams_response.py index f18abcd1..23a7c4a7 100644 --- a/src/knockapi/types/providers/ms_team_list_teams_response.py +++ b/src/knockapi/types/providers/ms_team_list_teams_response.py @@ -2,9 +2,8 @@ from typing import Optional -from pydantic import Field as FieldInfo - from ..._models import BaseModel +from ..._pydantic import Field as FieldInfo __all__ = ["MsTeamListTeamsResponse"] diff --git a/src/knockapi/types/recipients/channel_data.py b/src/knockapi/types/recipients/channel_data.py index 3c35931c..35ca9da3 100644 --- a/src/knockapi/types/recipients/channel_data.py +++ b/src/knockapi/types/recipients/channel_data.py @@ -3,9 +3,8 @@ from typing import List, Union, Optional from typing_extensions import Literal, TypeAlias -from pydantic import Field as FieldInfo - from ..._models import BaseModel +from ..._pydantic import Field as FieldInfo from .push_channel_data import PushChannelData from .slack_channel_data import SlackChannelData from .discord_channel_data import DiscordChannelData diff --git a/src/knockapi/types/recipients/subscription.py b/src/knockapi/types/recipients/subscription.py index ff47ce98..66279083 100644 --- a/src/knockapi/types/recipients/subscription.py +++ b/src/knockapi/types/recipients/subscription.py @@ -4,11 +4,10 @@ from typing import Dict, Optional from datetime import datetime -from pydantic import Field as FieldInfo - from ..object import Object from ..._models import BaseModel from ..recipient import Recipient +from ..._pydantic import Field as FieldInfo __all__ = ["Subscription"] diff --git a/src/knockapi/types/schedule.py b/src/knockapi/types/schedule.py index 56fd93ef..eab65dbe 100644 --- a/src/knockapi/types/schedule.py +++ b/src/knockapi/types/schedule.py @@ -3,10 +3,9 @@ from typing import Dict, List, Optional from datetime import datetime -from pydantic import Field as FieldInfo - from .._models import BaseModel from .recipient import Recipient +from .._pydantic import Field as FieldInfo from .schedule_repeat_rule import ScheduleRepeatRule __all__ = ["Schedule"] diff --git a/src/knockapi/types/schedule_repeat_rule.py b/src/knockapi/types/schedule_repeat_rule.py index cec89c83..53fe02cf 100644 --- a/src/knockapi/types/schedule_repeat_rule.py +++ b/src/knockapi/types/schedule_repeat_rule.py @@ -3,9 +3,8 @@ from typing import List, Optional from typing_extensions import Literal -from pydantic import Field as FieldInfo - from .._models import BaseModel +from .._pydantic import Field as FieldInfo __all__ = ["ScheduleRepeatRule"] diff --git a/src/knockapi/types/shared/page_info.py b/src/knockapi/types/shared/page_info.py index c211dbd5..c8f88f3c 100644 --- a/src/knockapi/types/shared/page_info.py +++ b/src/knockapi/types/shared/page_info.py @@ -2,9 +2,8 @@ from typing import Optional -from pydantic import Field as FieldInfo - from ..._models import BaseModel +from ..._pydantic import Field as FieldInfo __all__ = ["PageInfo"] diff --git a/src/knockapi/types/tenant.py b/src/knockapi/types/tenant.py index 52703834..83462896 100644 --- a/src/knockapi/types/tenant.py +++ b/src/knockapi/types/tenant.py @@ -2,9 +2,8 @@ from typing import TYPE_CHECKING, Dict, Optional -from pydantic import Field as FieldInfo - from .._models import BaseModel +from .._pydantic import Field as FieldInfo from .recipients.preference_set import PreferenceSet __all__ = ["Tenant", "Settings", "SettingsBranding"] diff --git a/src/knockapi/types/user.py b/src/knockapi/types/user.py index c8416766..202c757f 100644 --- a/src/knockapi/types/user.py +++ b/src/knockapi/types/user.py @@ -3,9 +3,8 @@ from typing import TYPE_CHECKING, Dict, Optional from datetime import datetime -from pydantic import Field as FieldInfo - from .._models import BaseModel +from .._pydantic import Field as FieldInfo __all__ = ["User"] diff --git a/src/knockapi/types/users/feed_list_items_response.py b/src/knockapi/types/users/feed_list_items_response.py index bb577199..c9f617e9 100644 --- a/src/knockapi/types/users/feed_list_items_response.py +++ b/src/knockapi/types/users/feed_list_items_response.py @@ -3,11 +3,10 @@ from typing import Dict, List, Union, Optional from typing_extensions import Literal, TypeAlias -from pydantic import Field as FieldInfo - from ..._models import BaseModel from ..activity import Activity from ..recipient import Recipient +from ..._pydantic import Field as FieldInfo __all__ = [ "FeedListItemsResponse", diff --git a/tests/api_resources/objects/test_bulk.py b/tests/api_resources/objects/test_bulk.py index ae3b3978..a60bc71d 100644 --- a/tests/api_resources/objects/test_bulk.py +++ b/tests/api_resources/objects/test_bulk.py @@ -68,7 +68,7 @@ def test_path_params_delete(self, client: Knock) -> None: def test_method_add_subscriptions(self, client: Knock) -> None: bulk = client.objects.bulk.add_subscriptions( collection="projects", - subscriptions=[{"recipients": [{"id": "user_1"}]}], + subscriptions=cast(Any, [{"recipients": [{"id": "user_1"}]}]), ) assert_matches_type(BulkOperation, bulk, path=["response"]) @@ -77,7 +77,7 @@ def test_method_add_subscriptions(self, client: Knock) -> None: def test_raw_response_add_subscriptions(self, client: Knock) -> None: response = client.objects.bulk.with_raw_response.add_subscriptions( collection="projects", - subscriptions=[{"recipients": [{"id": "user_1"}]}], + subscriptions=cast(Any, [{"recipients": [{"id": "user_1"}]}]), ) assert response.is_closed is True @@ -90,7 +90,7 @@ def test_raw_response_add_subscriptions(self, client: Knock) -> None: def test_streaming_response_add_subscriptions(self, client: Knock) -> None: with client.objects.bulk.with_streaming_response.add_subscriptions( collection="projects", - subscriptions=[{"recipients": [{"id": "user_1"}]}], + subscriptions=cast(Any, [{"recipients": [{"id": "user_1"}]}]), ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -106,7 +106,7 @@ def test_path_params_add_subscriptions(self, client: Knock) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `collection` but received ''"): client.objects.bulk.with_raw_response.add_subscriptions( collection="", - subscriptions=[{"recipients": [{"id": "user_1"}]}], + subscriptions=cast(Any, [{"recipients": [{"id": "user_1"}]}]), ) @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @@ -212,7 +212,7 @@ async def test_path_params_delete(self, async_client: AsyncKnock) -> None: async def test_method_add_subscriptions(self, async_client: AsyncKnock) -> None: bulk = await async_client.objects.bulk.add_subscriptions( collection="projects", - subscriptions=[{"recipients": [{"id": "user_1"}]}], + subscriptions=cast(Any, [{"recipients": [{"id": "user_1"}]}]), ) assert_matches_type(BulkOperation, bulk, path=["response"]) @@ -221,7 +221,7 @@ async def test_method_add_subscriptions(self, async_client: AsyncKnock) -> None: async def test_raw_response_add_subscriptions(self, async_client: AsyncKnock) -> None: response = await async_client.objects.bulk.with_raw_response.add_subscriptions( collection="projects", - subscriptions=[{"recipients": [{"id": "user_1"}]}], + subscriptions=cast(Any, [{"recipients": [{"id": "user_1"}]}]), ) assert response.is_closed is True @@ -234,7 +234,7 @@ async def test_raw_response_add_subscriptions(self, async_client: AsyncKnock) -> async def test_streaming_response_add_subscriptions(self, async_client: AsyncKnock) -> None: async with async_client.objects.bulk.with_streaming_response.add_subscriptions( collection="projects", - subscriptions=[{"recipients": [{"id": "user_1"}]}], + subscriptions=cast(Any, [{"recipients": [{"id": "user_1"}]}]), ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -250,7 +250,7 @@ async def test_path_params_add_subscriptions(self, async_client: AsyncKnock) -> with pytest.raises(ValueError, match=r"Expected a non-empty value for `collection` but received ''"): await async_client.objects.bulk.with_raw_response.add_subscriptions( collection="", - subscriptions=[{"recipients": [{"id": "user_1"}]}], + subscriptions=cast(Any, [{"recipients": [{"id": "user_1"}]}]), ) @pytest.mark.skip(reason="Prism doesn't support callbacks yet") diff --git a/tests/test_client.py b/tests/test_client.py index 7ec61e2c..71a048c8 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -16,12 +16,12 @@ import httpx import pytest from respx import MockRouter -from pydantic import ValidationError from knockapi import Knock, AsyncKnock, APIResponseValidationError from knockapi._types import Omit from knockapi._utils import asyncify from knockapi._models import BaseModel, FinalRequestOptions +from knockapi._pydantic import ValidationError from knockapi._exceptions import KnockError, APIStatusError, APITimeoutError, APIResponseValidationError from knockapi._base_client import ( DEFAULT_TIMEOUT, diff --git a/tests/test_models.py b/tests/test_models.py index 4de78522..0765c935 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -5,11 +5,11 @@ import pytest import pydantic -from pydantic import Field from knockapi._utils import PropertyInfo from knockapi._compat import PYDANTIC_V1, parse_obj, model_dump, model_json from knockapi._models import BaseModel, construct_type +from knockapi._pydantic import Field class BasicModel(BaseModel):