diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index d86f03e..f27fb6b 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -14,7 +14,7 @@ jobs:
- name: Set up python
uses: actions/setup-python@v5
with:
- python-version: 3.8
+ python-version: 3.11
- name: Bootstrap poetry
run: |
curl -sSL https://install.python-poetry.org | python - -y --version 1.5.1
@@ -31,7 +31,7 @@ jobs:
- name: Set up python
uses: actions/setup-python@v5
with:
- python-version: 3.8
+ python-version: 3.11
- name: Bootstrap poetry
run: |
curl -sSL https://install.python-poetry.org | python - -y --version 1.5.1
@@ -76,7 +76,7 @@ jobs:
- name: Set up python
uses: actions/setup-python@v5
with:
- python-version: 3.8
+ python-version: 3.11
- name: Bootstrap poetry
run: |
curl -sSL https://install.python-poetry.org | python - -y --version 1.5.1
diff --git a/src/sayari/attributes/client.py b/src/sayari/attributes/client.py
index fd4aba9..7b99e66 100644
--- a/src/sayari/attributes/client.py
+++ b/src/sayari/attributes/client.py
@@ -5,6 +5,7 @@
from .types.add_attribute import AddAttribute
from ..core.request_options import RequestOptions
from .types.attribute_response import AttributeResponse
+from ..core.serialization import convert_and_respect_annotation_metadata
from ..core.pydantic_utilities import parse_obj_as
from ..shared_errors.errors.bad_request import BadRequest
from ..shared_errors.types.bad_request_response import BadRequestResponse
@@ -82,7 +83,7 @@ def post_attribute(
_response = self._client_wrapper.httpx_client.request(
"v1/attribute",
method="POST",
- json=request,
+ json=convert_and_respect_annotation_metadata(object_=request, annotation=AddAttribute, direction="write"),
request_options=request_options,
omit=OMIT,
)
@@ -217,7 +218,9 @@ def patch_attribute(
_response = self._client_wrapper.httpx_client.request(
f"v1/attribute/{jsonable_encoder(attribute_id)}",
method="PATCH",
- json=request,
+ json=convert_and_respect_annotation_metadata(
+ object_=request, annotation=UpdateAttribute, direction="write"
+ ),
request_options=request_options,
omit=OMIT,
)
@@ -502,7 +505,7 @@ async def main() -> None:
_response = await self._client_wrapper.httpx_client.request(
"v1/attribute",
method="POST",
- json=request,
+ json=convert_and_respect_annotation_metadata(object_=request, annotation=AddAttribute, direction="write"),
request_options=request_options,
omit=OMIT,
)
@@ -645,7 +648,9 @@ async def main() -> None:
_response = await self._client_wrapper.httpx_client.request(
f"v1/attribute/{jsonable_encoder(attribute_id)}",
method="PATCH",
- json=request,
+ json=convert_and_respect_annotation_metadata(
+ object_=request, annotation=UpdateAttribute, direction="write"
+ ),
request_options=request_options,
omit=OMIT,
)
diff --git a/src/sayari/core/__init__.py b/src/sayari/core/__init__.py
index 4213c34..f03aecb 100644
--- a/src/sayari/core/__init__.py
+++ b/src/sayari/core/__init__.py
@@ -3,7 +3,7 @@
from .api_error import ApiError
from .client_wrapper import AsyncClientWrapper, BaseClientWrapper, SyncClientWrapper
from .datetime_utils import serialize_datetime
-from .file import File, convert_file_dict_to_httpx_tuples
+from .file import File, convert_file_dict_to_httpx_tuples, with_content_type
from .http_client import AsyncHttpClient, HttpClient
from .jsonable_encoder import jsonable_encoder
from .pydantic_utilities import (
@@ -43,4 +43,5 @@
"universal_field_validator",
"universal_root_validator",
"update_forward_refs",
+ "with_content_type",
]
diff --git a/src/sayari/core/file.py b/src/sayari/core/file.py
index 6e0f92b..b4cbba3 100644
--- a/src/sayari/core/file.py
+++ b/src/sayari/core/file.py
@@ -1,30 +1,30 @@
# This file was auto-generated by Fern from our API Definition.
-import typing
+from typing import IO, Dict, List, Mapping, Optional, Tuple, Union, cast
# File typing inspired by the flexibility of types within the httpx library
# https://github.com/encode/httpx/blob/master/httpx/_types.py
-FileContent = typing.Union[typing.IO[bytes], bytes, str]
-File = typing.Union[
+FileContent = Union[IO[bytes], bytes, str]
+File = Union[
# file (or bytes)
FileContent,
# (filename, file (or bytes))
- typing.Tuple[typing.Optional[str], FileContent],
+ Tuple[Optional[str], FileContent],
# (filename, file (or bytes), content_type)
- typing.Tuple[typing.Optional[str], FileContent, typing.Optional[str]],
+ Tuple[Optional[str], FileContent, Optional[str]],
# (filename, file (or bytes), content_type, headers)
- typing.Tuple[
- typing.Optional[str],
+ Tuple[
+ Optional[str],
FileContent,
- typing.Optional[str],
- typing.Mapping[str, str],
+ Optional[str],
+ Mapping[str, str],
],
]
def convert_file_dict_to_httpx_tuples(
- d: typing.Dict[str, typing.Union[File, typing.List[File]]],
-) -> typing.List[typing.Tuple[str, File]]:
+ d: Dict[str, Union[File, List[File]]],
+) -> List[Tuple[str, File]]:
"""
The format we use is a list of tuples, where the first element is the
name of the file and the second is the file object. Typically HTTPX wants
@@ -41,3 +41,22 @@ def convert_file_dict_to_httpx_tuples(
else:
httpx_tuples.append((key, file_like))
return httpx_tuples
+
+
+def with_content_type(*, file: File, content_type: str) -> File:
+ """ """
+ if isinstance(file, tuple):
+ if len(file) == 2:
+ filename, content = cast(Tuple[Optional[str], FileContent], file) # type: ignore
+ return (filename, content, content_type)
+ elif len(file) == 3:
+ filename, content, _ = cast(Tuple[Optional[str], FileContent, Optional[str]], file) # type: ignore
+ return (filename, content, content_type)
+ elif len(file) == 4:
+ filename, content, _, headers = cast( # type: ignore
+ Tuple[Optional[str], FileContent, Optional[str], Mapping[str, str]], file
+ )
+ return (filename, content, content_type, headers)
+ else:
+ raise ValueError(f"Unexpected tuple length: {len(file)}")
+ return (None, file, content_type)
diff --git a/src/sayari/core/pydantic_utilities.py b/src/sayari/core/pydantic_utilities.py
index eb42918..a0875ac 100644
--- a/src/sayari/core/pydantic_utilities.py
+++ b/src/sayari/core/pydantic_utilities.py
@@ -10,6 +10,7 @@
import pydantic
from .datetime_utils import serialize_datetime
+from .serialization import convert_and_respect_annotation_metadata
IS_PYDANTIC_V2 = pydantic.VERSION.startswith("2.")
@@ -56,11 +57,12 @@
def parse_obj_as(type_: typing.Type[T], object_: typing.Any) -> T:
+ dealiased_object = convert_and_respect_annotation_metadata(object_=object_, annotation=type_, direction="read")
if IS_PYDANTIC_V2:
adapter = pydantic.TypeAdapter(type_) # type: ignore # Pydantic v2
- return adapter.validate_python(object_)
+ return adapter.validate_python(dealiased_object)
else:
- return pydantic.parse_obj_as(type_, object_)
+ return pydantic.parse_obj_as(type_, dealiased_object)
def to_jsonable_with_fallback(
@@ -75,11 +77,40 @@ def to_jsonable_with_fallback(
class UniversalBaseModel(pydantic.BaseModel):
- class Config:
- populate_by_name = True
- smart_union = True
- allow_population_by_field_name = True
- json_encoders = {dt.datetime: serialize_datetime}
+ if IS_PYDANTIC_V2:
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(
+ # Allow fields begining with `model_` to be used in the model
+ protected_namespaces=(),
+ ) # type: ignore # Pydantic v2
+
+ @pydantic.model_serializer(mode="wrap", when_used="json") # type: ignore # Pydantic v2
+ def serialize_model(self, handler: pydantic.SerializerFunctionWrapHandler) -> typing.Any: # type: ignore # Pydantic v2
+ serialized = handler(self)
+ data = {k: serialize_datetime(v) if isinstance(v, dt.datetime) else v for k, v in serialized.items()}
+ return data
+
+ else:
+
+ class Config:
+ smart_union = True
+ json_encoders = {dt.datetime: serialize_datetime}
+
+ @classmethod
+ def model_construct(
+ cls: type[Model], _fields_set: typing.Optional[typing.Set[str]] = None, **values: typing.Any
+ ) -> Model:
+ dealiased_object = convert_and_respect_annotation_metadata(object_=values, annotation=cls, direction="read")
+ return cls.construct(_fields_set, **dealiased_object)
+
+ @classmethod
+ def construct(
+ cls: type[Model], _fields_set: typing.Optional[typing.Set[str]] = None, **values: typing.Any
+ ) -> Model:
+ dealiased_object = convert_and_respect_annotation_metadata(object_=values, annotation=cls, direction="read")
+ if IS_PYDANTIC_V2:
+ return super().model_construct(_fields_set, **dealiased_object) # type: ignore # Pydantic v2
+ else:
+ return super().construct(_fields_set, **dealiased_object)
def json(self, **kwargs: typing.Any) -> str:
kwargs_with_defaults: typing.Any = {
@@ -97,30 +128,66 @@ def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]:
Override the default dict method to `exclude_unset` by default. This function patches
`exclude_unset` to work include fields within non-None default values.
"""
- _fields_set = self.__fields_set__
-
- fields = _get_model_fields(self.__class__)
- for name, field in fields.items():
- if name not in _fields_set:
- default = _get_field_default(field)
-
- # If the default values are non-null act like they've been set
- # This effectively allows exclude_unset to work like exclude_none where
- # the latter passes through intentionally set none values.
- if default != None:
- _fields_set.add(name)
-
- kwargs_with_defaults_exclude_unset: typing.Any = {
- "by_alias": True,
- "exclude_unset": True,
- "include": _fields_set,
- **kwargs,
- }
-
+ # Note: the logic here is multi-plexed given the levers exposed in Pydantic V1 vs V2
+ # Pydantic V1's .dict can be extremely slow, so we do not want to call it twice.
+ #
+ # We'd ideally do the same for Pydantic V2, but it shells out to a library to serialize models
+ # that we have less control over, and this is less intrusive than custom serializers for now.
if IS_PYDANTIC_V2:
- return super().model_dump(**kwargs_with_defaults_exclude_unset) # type: ignore # Pydantic v2
+ kwargs_with_defaults_exclude_unset: typing.Any = {
+ **kwargs,
+ "by_alias": True,
+ "exclude_unset": True,
+ "exclude_none": False,
+ }
+ kwargs_with_defaults_exclude_none: typing.Any = {
+ **kwargs,
+ "by_alias": True,
+ "exclude_none": True,
+ "exclude_unset": False,
+ }
+ dict_dump = deep_union_pydantic_dicts(
+ super().model_dump(**kwargs_with_defaults_exclude_unset), # type: ignore # Pydantic v2
+ super().model_dump(**kwargs_with_defaults_exclude_none), # type: ignore # Pydantic v2
+ )
+
else:
- return super().dict(**kwargs_with_defaults_exclude_unset)
+ _fields_set = self.__fields_set__
+
+ fields = _get_model_fields(self.__class__)
+ for name, field in fields.items():
+ if name not in _fields_set:
+ default = _get_field_default(field)
+
+ # If the default values are non-null act like they've been set
+ # This effectively allows exclude_unset to work like exclude_none where
+ # the latter passes through intentionally set none values.
+ if default != None:
+ _fields_set.add(name)
+
+ kwargs_with_defaults_exclude_unset_include_fields: typing.Any = {
+ "by_alias": True,
+ "exclude_unset": True,
+ "include": _fields_set,
+ **kwargs,
+ }
+
+ dict_dump = super().dict(**kwargs_with_defaults_exclude_unset_include_fields)
+
+ return convert_and_respect_annotation_metadata(object_=dict_dump, annotation=self.__class__, direction="write")
+
+
+def deep_union_pydantic_dicts(
+ source: typing.Dict[str, typing.Any], destination: typing.Dict[str, typing.Any]
+) -> typing.Dict[str, typing.Any]:
+ for key, value in source.items():
+ if isinstance(value, dict):
+ node = destination.setdefault(key, {})
+ deep_union_pydantic_dicts(value, node)
+ else:
+ destination[key] = value
+
+ return destination
if IS_PYDANTIC_V2:
@@ -147,11 +214,11 @@ def encode_by_type(o: typing.Any) -> typing.Any:
return encoder(o)
-def update_forward_refs(model: typing.Type["Model"]) -> None:
+def update_forward_refs(model: typing.Type["Model"], **localns: typing.Any) -> None:
if IS_PYDANTIC_V2:
model.model_rebuild(raise_errors=False) # type: ignore # Pydantic v2
else:
- model.update_forward_refs()
+ model.update_forward_refs(**localns)
# Mirrors Pydantic's internal typing
diff --git a/src/sayari/core/serialization.py b/src/sayari/core/serialization.py
index 36180ac..5605f1b 100644
--- a/src/sayari/core/serialization.py
+++ b/src/sayari/core/serialization.py
@@ -1,10 +1,13 @@
# This file was auto-generated by Fern from our API Definition.
import collections
+import inspect
import typing
import typing_extensions
+import pydantic
+
class FieldMetadata:
"""
@@ -29,6 +32,7 @@ def convert_and_respect_annotation_metadata(
object_: typing.Any,
annotation: typing.Any,
inner_type: typing.Optional[typing.Any] = None,
+ direction: typing.Literal["read", "write"],
) -> typing.Any:
"""
Respect the metadata annotations on a field, such as aliasing. This function effectively
@@ -56,44 +60,59 @@ def convert_and_respect_annotation_metadata(
inner_type = annotation
clean_type = _remove_annotations(inner_type)
- if typing_extensions.is_typeddict(clean_type) and isinstance(object_, typing.Mapping):
- return _convert_typeddict(object_, clean_type)
-
+ # Pydantic models
if (
- # If you're iterating on a string, do not bother to coerce it to a sequence.
- (not isinstance(object_, str))
- and (
- (
- (
- typing_extensions.get_origin(clean_type) == typing.List
- or typing_extensions.get_origin(clean_type) == list
- or clean_type == typing.List
+ inspect.isclass(clean_type)
+ and issubclass(clean_type, pydantic.BaseModel)
+ and isinstance(object_, typing.Mapping)
+ ):
+ return _convert_mapping(object_, clean_type, direction)
+ # TypedDicts
+ if typing_extensions.is_typeddict(clean_type) and isinstance(object_, typing.Mapping):
+ return _convert_mapping(object_, clean_type, direction)
+
+ # If you're iterating on a string, do not bother to coerce it to a sequence.
+ if not isinstance(object_, str):
+ if (
+ typing_extensions.get_origin(clean_type) == typing.Set
+ or typing_extensions.get_origin(clean_type) == set
+ or clean_type == typing.Set
+ ) and isinstance(object_, typing.Set):
+ inner_type = typing_extensions.get_args(clean_type)[0]
+ return {
+ convert_and_respect_annotation_metadata(
+ object_=item,
+ annotation=annotation,
+ inner_type=inner_type,
+ direction=direction,
)
- and isinstance(object_, typing.List)
+ for item in object_
+ }
+ elif (
+ (
+ typing_extensions.get_origin(clean_type) == typing.List
+ or typing_extensions.get_origin(clean_type) == list
+ or clean_type == typing.List
)
- or (
- (
- typing_extensions.get_origin(clean_type) == typing.Set
- or typing_extensions.get_origin(clean_type) == set
- or clean_type == typing.Set
- )
- and isinstance(object_, typing.Set)
+ and isinstance(object_, typing.List)
+ ) or (
+ (
+ typing_extensions.get_origin(clean_type) == typing.Sequence
+ or typing_extensions.get_origin(clean_type) == collections.abc.Sequence
+ or clean_type == typing.Sequence
)
- or (
- (
- typing_extensions.get_origin(clean_type) == typing.Sequence
- or typing_extensions.get_origin(clean_type) == collections.abc.Sequence
- or clean_type == typing.Sequence
+ and isinstance(object_, typing.Sequence)
+ ):
+ inner_type = typing_extensions.get_args(clean_type)[0]
+ return [
+ convert_and_respect_annotation_metadata(
+ object_=item,
+ annotation=annotation,
+ inner_type=inner_type,
+ direction=direction,
)
- and isinstance(object_, typing.Sequence)
- )
- )
- ):
- inner_type = typing_extensions.get_args(clean_type)[0]
- return [
- convert_and_respect_annotation_metadata(object_=item, annotation=annotation, inner_type=inner_type)
- for item in object_
- ]
+ for item in object_
+ ]
if typing_extensions.get_origin(clean_type) == typing.Union:
# We should be able to ~relatively~ safely try to convert keys against all
@@ -101,7 +120,12 @@ def convert_and_respect_annotation_metadata(
# of the same name to a different name from another member
# Or if another member aliases a field of the same name that another member does not.
for member in typing_extensions.get_args(clean_type):
- object_ = convert_and_respect_annotation_metadata(object_=object_, annotation=annotation, inner_type=member)
+ object_ = convert_and_respect_annotation_metadata(
+ object_=object_,
+ annotation=annotation,
+ inner_type=member,
+ direction=direction,
+ )
return object_
annotated_type = _get_annotation(annotation)
@@ -113,16 +137,34 @@ def convert_and_respect_annotation_metadata(
return object_
-def _convert_typeddict(object_: typing.Mapping[str, object], expected_type: typing.Any) -> typing.Mapping[str, object]:
+def _convert_mapping(
+ object_: typing.Mapping[str, object],
+ expected_type: typing.Any,
+ direction: typing.Literal["read", "write"],
+) -> typing.Mapping[str, object]:
converted_object: typing.Dict[str, object] = {}
annotations = typing_extensions.get_type_hints(expected_type, include_extras=True)
+ aliases_to_field_names = _get_alias_to_field_name(annotations)
for key, value in object_.items():
- type_ = annotations.get(key)
+ if direction == "read" and key in aliases_to_field_names:
+ dealiased_key = aliases_to_field_names.get(key)
+ if dealiased_key is not None:
+ type_ = annotations.get(dealiased_key)
+ else:
+ type_ = annotations.get(key)
+ # Note you can't get the annotation by the field name if you're in read mode, so you must check the aliases map
+ #
+ # So this is effectively saying if we're in write mode, and we don't have a type, or if we're in read mode and we don't have an alias
+ # then we can just pass the value through as is
if type_ is None:
converted_object[key] = value
+ elif direction == "read" and key not in aliases_to_field_names:
+ converted_object[key] = convert_and_respect_annotation_metadata(
+ object_=value, annotation=type_, direction=direction
+ )
else:
- converted_object[_alias_key(key, type_)] = convert_and_respect_annotation_metadata(
- object_=value, annotation=type_
+ converted_object[_alias_key(key, type_, direction, aliases_to_field_names)] = (
+ convert_and_respect_annotation_metadata(object_=value, annotation=type_, direction=direction)
)
return converted_object
@@ -156,7 +198,39 @@ def _remove_annotations(type_: typing.Any) -> typing.Any:
return type_
-def _alias_key(key: str, type_: typing.Any) -> str:
+def get_alias_to_field_mapping(type_: typing.Any) -> typing.Dict[str, str]:
+ annotations = typing_extensions.get_type_hints(type_, include_extras=True)
+ return _get_alias_to_field_name(annotations)
+
+
+def get_field_to_alias_mapping(type_: typing.Any) -> typing.Dict[str, str]:
+ annotations = typing_extensions.get_type_hints(type_, include_extras=True)
+ return _get_field_to_alias_name(annotations)
+
+
+def _get_alias_to_field_name(
+ field_to_hint: typing.Dict[str, typing.Any],
+) -> typing.Dict[str, str]:
+ aliases = {}
+ for field, hint in field_to_hint.items():
+ maybe_alias = _get_alias_from_type(hint)
+ if maybe_alias is not None:
+ aliases[maybe_alias] = field
+ return aliases
+
+
+def _get_field_to_alias_name(
+ field_to_hint: typing.Dict[str, typing.Any],
+) -> typing.Dict[str, str]:
+ aliases = {}
+ for field, hint in field_to_hint.items():
+ maybe_alias = _get_alias_from_type(hint)
+ if maybe_alias is not None:
+ aliases[field] = maybe_alias
+ return aliases
+
+
+def _get_alias_from_type(type_: typing.Any) -> typing.Optional[str]:
maybe_annotated_type = _get_annotation(type_)
if maybe_annotated_type is not None:
@@ -166,5 +240,15 @@ def _alias_key(key: str, type_: typing.Any) -> str:
for annotation in annotations:
if isinstance(annotation, FieldMetadata) and annotation.alias is not None:
return annotation.alias
+ return None
+
- return key
+def _alias_key(
+ key: str,
+ type_: typing.Any,
+ direction: typing.Literal["read", "write"],
+ aliases_to_field_names: typing.Dict[str, str],
+) -> str:
+ if direction == "read":
+ return aliases_to_field_names.get(key, key)
+ return _get_alias_from_type(type_=type_) or key
diff --git a/src/sayari/entity/types/entity_summary_response.py b/src/sayari/entity/types/entity_summary_response.py
index 2a9ba8c..6543a68 100644
--- a/src/sayari/entity/types/entity_summary_response.py
+++ b/src/sayari/entity/types/entity_summary_response.py
@@ -1,9 +1,13 @@
# This file was auto-generated by Fern from our API Definition.
+from __future__ import annotations
from ...shared_types.types.entity_details import EntityDetails
+from ...shared_types.types.entity_relationships import EntityRelationships
+from ...shared_types.types.relationship_data import RelationshipData
from ...core.pydantic_utilities import IS_PYDANTIC_V2
import typing
import pydantic
+from ...core.pydantic_utilities import update_forward_refs
class EntitySummaryResponse(EntityDetails):
@@ -1420,3 +1424,8 @@ class Config:
frozen = True
smart_union = True
extra = pydantic.Extra.allow
+
+
+update_forward_refs(EntityDetails, EntitySummaryResponse=EntitySummaryResponse)
+update_forward_refs(EntityRelationships, EntitySummaryResponse=EntitySummaryResponse)
+update_forward_refs(RelationshipData, EntitySummaryResponse=EntitySummaryResponse)
diff --git a/src/sayari/entity/types/get_entity_response.py b/src/sayari/entity/types/get_entity_response.py
index e60d401..085dd8f 100644
--- a/src/sayari/entity/types/get_entity_response.py
+++ b/src/sayari/entity/types/get_entity_response.py
@@ -1,9 +1,13 @@
# This file was auto-generated by Fern from our API Definition.
+from __future__ import annotations
from ...shared_types.types.entity_details import EntityDetails
+from ...shared_types.types.entity_relationships import EntityRelationships
+from ...shared_types.types.relationship_data import RelationshipData
from ...core.pydantic_utilities import IS_PYDANTIC_V2
import typing
import pydantic
+from ...core.pydantic_utilities import update_forward_refs
class GetEntityResponse(EntityDetails):
@@ -601,3 +605,8 @@ class Config:
frozen = True
smart_union = True
extra = pydantic.Extra.allow
+
+
+update_forward_refs(EntityDetails, GetEntityResponse=GetEntityResponse)
+update_forward_refs(EntityRelationships, GetEntityResponse=GetEntityResponse)
+update_forward_refs(RelationshipData, GetEntityResponse=GetEntityResponse)
diff --git a/src/sayari/generated_types/types/risk_intelligence_properties.py b/src/sayari/generated_types/types/risk_intelligence_properties.py
index 0812c0c..48b1634 100644
--- a/src/sayari/generated_types/types/risk_intelligence_properties.py
+++ b/src/sayari/generated_types/types/risk_intelligence_properties.py
@@ -3,6 +3,8 @@
from ...core.pydantic_utilities import UniversalBaseModel
import typing
import pydantic
+import typing_extensions
+from ...core.serialization import FieldMetadata
from .tag import Tag
from ...core.pydantic_utilities import IS_PYDANTIC_V2
@@ -23,7 +25,7 @@ class RiskIntelligenceProperties(UniversalBaseModel):
start date
"""
- list_: typing.Optional[str] = pydantic.Field(alias="list", default=None)
+ list_: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="list")] = pydantic.Field(default=None)
"""
Official list where the entity's risk information or enforcement action is recorded
"""
diff --git a/src/sayari/info/types/usage_response.py b/src/sayari/info/types/usage_response.py
index 259fdc5..97b6c5b 100644
--- a/src/sayari/info/types/usage_response.py
+++ b/src/sayari/info/types/usage_response.py
@@ -3,6 +3,8 @@
from ...core.pydantic_utilities import UniversalBaseModel
from .usage_info import UsageInfo
import pydantic
+import typing_extensions
+from ...core.serialization import FieldMetadata
from ...core.pydantic_utilities import IS_PYDANTIC_V2
import typing
@@ -13,7 +15,7 @@ class UsageResponse(UniversalBaseModel):
Usage information for each endpoint
"""
- from_: str = pydantic.Field(alias="from")
+ from_: typing_extensions.Annotated[str, FieldMetadata(alias="from")] = pydantic.Field()
"""
The start date of the returned usage information.
"""
diff --git a/src/sayari/metadata/types/user_info.py b/src/sayari/metadata/types/user_info.py
index 0cc270c..05bfb87 100644
--- a/src/sayari/metadata/types/user_info.py
+++ b/src/sayari/metadata/types/user_info.py
@@ -2,7 +2,9 @@
from ...core.pydantic_utilities import UniversalBaseModel
import pydantic
+import typing_extensions
import typing
+from ...core.serialization import FieldMetadata
from ...core.pydantic_utilities import IS_PYDANTIC_V2
@@ -12,7 +14,9 @@ class UserInfo(UniversalBaseModel):
Currently logged in user ID
"""
- group_display_names: typing.Optional[str] = pydantic.Field(alias="groupDisplayNames", default=None)
+ group_display_names: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="groupDisplayNames")] = (
+ pydantic.Field(default=None)
+ )
"""
Name of the sayari organization tied to credentials
"""
diff --git a/src/sayari/project/client.py b/src/sayari/project/client.py
index 3a7d737..01a3201 100644
--- a/src/sayari/project/client.py
+++ b/src/sayari/project/client.py
@@ -5,6 +5,7 @@
from .types.create_project_request import CreateProjectRequest
from ..core.request_options import RequestOptions
from .types.create_project_response import CreateProjectResponse
+from ..core.serialization import convert_and_respect_annotation_metadata
from ..core.pydantic_utilities import parse_obj_as
from ..shared_errors.errors.bad_request import BadRequest
from ..shared_errors.types.bad_request_response import BadRequestResponse
@@ -76,7 +77,9 @@ def create_project(
_response = self._client_wrapper.httpx_client.request(
"v1/projects",
method="POST",
- json=request,
+ json=convert_and_respect_annotation_metadata(
+ object_=request, annotation=CreateProjectRequest, direction="write"
+ ),
request_options=request_options,
omit=OMIT,
)
@@ -386,7 +389,9 @@ def get_project_entities(
"shipped_hs_codes": shipped_hs_codes,
"translation": translation,
"sort": sort,
- "filters": jsonable_encoder(filters),
+ "filters": convert_and_respect_annotation_metadata(
+ object_=filters, annotation=ProjectEntitiesFilter, direction="write"
+ ),
"aggregations": aggregations,
},
headers={
@@ -624,7 +629,9 @@ async def main() -> None:
_response = await self._client_wrapper.httpx_client.request(
"v1/projects",
method="POST",
- json=request,
+ json=convert_and_respect_annotation_metadata(
+ object_=request, annotation=CreateProjectRequest, direction="write"
+ ),
request_options=request_options,
omit=OMIT,
)
@@ -950,7 +957,9 @@ async def main() -> None:
"shipped_hs_codes": shipped_hs_codes,
"translation": translation,
"sort": sort,
- "filters": jsonable_encoder(filters),
+ "filters": convert_and_respect_annotation_metadata(
+ object_=filters, annotation=ProjectEntitiesFilter, direction="write"
+ ),
"aggregations": aggregations,
},
headers={
diff --git a/src/sayari/project/types/project_entities_filter.py b/src/sayari/project/types/project_entities_filter.py
index 8fc03ca..f980951 100644
--- a/src/sayari/project/types/project_entities_filter.py
+++ b/src/sayari/project/types/project_entities_filter.py
@@ -6,6 +6,8 @@
import pydantic
from .upstream_tiers import UpstreamTiers
from ...generated_types.types.country import Country
+import typing_extensions
+from ...core.serialization import FieldMetadata
from ...generated_types.types.company_status import CompanyStatus
from ...core.pydantic_utilities import IS_PYDANTIC_V2
@@ -46,32 +48,44 @@ class ProjectEntitiesFilter(UniversalBaseModel):
Filter by HS code, HS code description, or business description.
"""
- label_fuzzy: typing.Optional[typing.List[str]] = pydantic.Field(alias="label.fuzzy", default=None)
+ label_fuzzy: typing_extensions.Annotated[typing.Optional[typing.List[str]], FieldMetadata(alias="label.fuzzy")] = (
+ pydantic.Field(default=None)
+ )
"""
Filter by entity label with fuzzy matching.
"""
- city_fuzzy: typing.Optional[typing.List[str]] = pydantic.Field(alias="city.fuzzy", default=None)
+ city_fuzzy: typing_extensions.Annotated[typing.Optional[typing.List[str]], FieldMetadata(alias="city.fuzzy")] = (
+ pydantic.Field(default=None)
+ )
"""
Filter by entity city with fuzzy matching.
"""
- state_fuzzy: typing.Optional[typing.List[str]] = pydantic.Field(alias="state.fuzzy", default=None)
+ state_fuzzy: typing_extensions.Annotated[typing.Optional[typing.List[str]], FieldMetadata(alias="state.fuzzy")] = (
+ pydantic.Field(default=None)
+ )
"""
Filter by entity address state with fuzzy matching.
"""
- identifier_fuzzy: typing.Optional[typing.List[str]] = pydantic.Field(alias="identifier.fuzzy", default=None)
+ identifier_fuzzy: typing_extensions.Annotated[
+ typing.Optional[typing.List[str]], FieldMetadata(alias="identifier.fuzzy")
+ ] = pydantic.Field(default=None)
"""
Filter by entity identifier attributes with fuzzy matching.
"""
- source_exact: typing.Optional[typing.List[str]] = pydantic.Field(alias="source.exact", default=None)
+ source_exact: typing_extensions.Annotated[
+ typing.Optional[typing.List[str]], FieldMetadata(alias="source.exact")
+ ] = pydantic.Field(default=None)
"""
Filter by entity source ID.
"""
- status_exact: typing.Optional[typing.List[CompanyStatus]] = pydantic.Field(alias="status.exact", default=None)
+ status_exact: typing_extensions.Annotated[
+ typing.Optional[typing.List[CompanyStatus]], FieldMetadata(alias="status.exact")
+ ] = pydantic.Field(default=None)
"""
Filter by entity [company status](/sayari-library/ontology/enumerated-types#company-status).
"""
@@ -81,7 +95,9 @@ class ProjectEntitiesFilter(UniversalBaseModel):
Filter by a geographical bounding box. The value is a pipe-delimited set of four values representing the top, left, bottom, and right sides of the bounding box, in that order. The pipes should be URL-encoded as `%7C`. The top coordinate must greater than the bottom coordinate, and the left coordinate must be less than the right coordinate. A sample is `55.680357237879136|-71.53607290158526|41.10876347746233|-40.963927098414736`
"""
- custom_field_name: typing.Optional[typing.List[str]] = pydantic.Field(alias="custom_{field name}", default=None)
+ custom_field_name: typing_extensions.Annotated[
+ typing.Optional[typing.List[str]], FieldMetadata(alias="custom_{field name}")
+ ] = pydantic.Field(default=None)
"""
This property is in beta and is subject to change. It is provided for early access and testing purposes only. custom user key/value pairs (key must be prefixed with "custom\_" and value must be "string" type)
"""
diff --git a/src/sayari/resolution/client.py b/src/sayari/resolution/client.py
index 4d199b8..f516c91 100644
--- a/src/sayari/resolution/client.py
+++ b/src/sayari/resolution/client.py
@@ -24,6 +24,7 @@
from json.decoder import JSONDecodeError
from ..core.api_error import ApiError
from .types.resolution_body import ResolutionBody
+from ..core.serialization import convert_and_respect_annotation_metadata
from .types.resolution_persisted_response import ResolutionPersistedResponse
from ..core.jsonable_encoder import jsonable_encoder
from ..core.client_wrapper import AsyncClientWrapper
@@ -268,7 +269,7 @@ def resolution_post(
"limit": limit,
"offset": offset,
},
- json=request,
+ json=convert_and_respect_annotation_metadata(object_=request, annotation=ResolutionBody, direction="write"),
request_options=request_options,
omit=OMIT,
)
@@ -402,7 +403,7 @@ def resolution_persisted(
"limit": limit,
"offset": offset,
},
- json=request,
+ json=convert_and_respect_annotation_metadata(object_=request, annotation=ResolutionBody, direction="write"),
request_options=request_options,
omit=OMIT,
)
@@ -733,7 +734,7 @@ async def main() -> None:
"limit": limit,
"offset": offset,
},
- json=request,
+ json=convert_and_respect_annotation_metadata(object_=request, annotation=ResolutionBody, direction="write"),
request_options=request_options,
omit=OMIT,
)
@@ -875,7 +876,7 @@ async def main() -> None:
"limit": limit,
"offset": offset,
},
- json=request,
+ json=convert_and_respect_annotation_metadata(object_=request, annotation=ResolutionBody, direction="write"),
request_options=request_options,
omit=OMIT,
)
diff --git a/src/sayari/resolution/types/resolution_persisted_response_fields.py b/src/sayari/resolution/types/resolution_persisted_response_fields.py
index 0ef5d14..1bdc1c9 100644
--- a/src/sayari/resolution/types/resolution_persisted_response_fields.py
+++ b/src/sayari/resolution/types/resolution_persisted_response_fields.py
@@ -1,13 +1,17 @@
# This file was auto-generated by Fern from our API Definition.
from .resolution_response_fields import ResolutionResponseFields
+import typing_extensions
import typing
+from ...core.serialization import FieldMetadata
import pydantic
from ...core.pydantic_utilities import IS_PYDANTIC_V2
class ResolutionPersistedResponseFields(ResolutionResponseFields):
- custom_field_name: typing.Optional[str] = pydantic.Field(alias="custom_{field name}", default=None)
+ custom_field_name: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="custom_{field name}")] = (
+ pydantic.Field(default=None)
+ )
"""
This property is in beta and is subject to change. It is provided for early access and testing purposes only. custom user key/value pairs (key must be prefixed with "custom\_" and value must be "string" type)
"""
diff --git a/src/sayari/resource/client.py b/src/sayari/resource/client.py
index 6ff8c72..ac3f5a7 100644
--- a/src/sayari/resource/client.py
+++ b/src/sayari/resource/client.py
@@ -5,6 +5,7 @@
from .types.save_entity_request import SaveEntityRequest
from ..core.request_options import RequestOptions
from .types.save_entity_response import SaveEntityResponse
+from ..core.serialization import convert_and_respect_annotation_metadata
from ..core.pydantic_utilities import parse_obj_as
from ..shared_errors.errors.bad_request import BadRequest
from ..shared_errors.types.bad_request_response import BadRequestResponse
@@ -71,7 +72,9 @@ def save_entity(
_response = self._client_wrapper.httpx_client.request(
"v1/resource/entity",
method="POST",
- json=request,
+ json=convert_and_respect_annotation_metadata(
+ object_=request, annotation=SaveEntityRequest, direction="write"
+ ),
request_options=request_options,
omit=OMIT,
)
@@ -311,7 +314,9 @@ async def main() -> None:
_response = await self._client_wrapper.httpx_client.request(
"v1/resource/entity",
method="POST",
- json=request,
+ json=convert_and_respect_annotation_metadata(
+ object_=request, annotation=SaveEntityRequest, direction="write"
+ ),
request_options=request_options,
omit=OMIT,
)
diff --git a/src/sayari/search/client.py b/src/sayari/search/client.py
index f3226eb..c28d22f 100644
--- a/src/sayari/search/client.py
+++ b/src/sayari/search/client.py
@@ -6,6 +6,7 @@
from .types.filter_list import FilterList
from ..core.request_options import RequestOptions
from .types.entity_search_response import EntitySearchResponse
+from ..core.serialization import convert_and_respect_annotation_metadata
from ..core.pydantic_utilities import parse_obj_as
from ..shared_errors.errors.bad_request import BadRequest
from ..shared_errors.types.bad_request_response import BadRequestResponse
@@ -104,7 +105,9 @@ def search_entity(
json={
"q": q,
"fields": fields,
- "filter": filter,
+ "filter": convert_and_respect_annotation_metadata(
+ object_=filter, annotation=FilterList, direction="write"
+ ),
"facets": facets,
"geo_facets": geo_facets,
"advanced": advanced,
@@ -400,7 +403,9 @@ def search_record(
json={
"q": q,
"fields": fields,
- "filter": filter,
+ "filter": convert_and_respect_annotation_metadata(
+ object_=filter, annotation=FilterList, direction="write"
+ ),
"facets": facets,
"advanced": advanced,
},
@@ -707,7 +712,9 @@ async def main() -> None:
json={
"q": q,
"fields": fields,
- "filter": filter,
+ "filter": convert_and_respect_annotation_metadata(
+ object_=filter, annotation=FilterList, direction="write"
+ ),
"facets": facets,
"geo_facets": geo_facets,
"advanced": advanced,
@@ -1019,7 +1026,9 @@ async def main() -> None:
json={
"q": q,
"fields": fields,
- "filter": filter,
+ "filter": convert_and_respect_annotation_metadata(
+ object_=filter, annotation=FilterList, direction="write"
+ ),
"facets": facets,
"advanced": advanced,
},
diff --git a/src/sayari/search/types/entity_search_response.py b/src/sayari/search/types/entity_search_response.py
index c730ffd..774fba2 100644
--- a/src/sayari/search/types/entity_search_response.py
+++ b/src/sayari/search/types/entity_search_response.py
@@ -1,10 +1,15 @@
# This file was auto-generated by Fern from our API Definition.
+from __future__ import annotations
from ...base_types.types.paginated_response import PaginatedResponse
+from ...shared_types.types.entity_details import EntityDetails
+from ...shared_types.types.entity_relationships import EntityRelationships
+from ...shared_types.types.relationship_data import RelationshipData
import typing
from .search_results import SearchResults
from ...core.pydantic_utilities import IS_PYDANTIC_V2
import pydantic
+from ...core.pydantic_utilities import update_forward_refs
class EntitySearchResponse(PaginatedResponse):
@@ -194,3 +199,8 @@ class Config:
frozen = True
smart_union = True
extra = pydantic.Extra.allow
+
+
+update_forward_refs(EntityDetails, EntitySearchResponse=EntitySearchResponse)
+update_forward_refs(EntityRelationships, EntitySearchResponse=EntitySearchResponse)
+update_forward_refs(RelationshipData, EntitySearchResponse=EntitySearchResponse)
diff --git a/src/sayari/search/types/search_results.py b/src/sayari/search/types/search_results.py
index 03887f5..3e9b165 100644
--- a/src/sayari/search/types/search_results.py
+++ b/src/sayari/search/types/search_results.py
@@ -1,11 +1,15 @@
# This file was auto-generated by Fern from our API Definition.
+from __future__ import annotations
from ...shared_types.types.entity_details import EntityDetails
+from ...shared_types.types.entity_relationships import EntityRelationships
+from ...shared_types.types.relationship_data import RelationshipData
import typing
from .coordinates import Coordinates
from ...shared_types.types.entity_matches import EntityMatches
from ...core.pydantic_utilities import IS_PYDANTIC_V2
import pydantic
+from ...core.pydantic_utilities import update_forward_refs
class SearchResults(EntityDetails):
@@ -20,3 +24,8 @@ class Config:
frozen = True
smart_union = True
extra = pydantic.Extra.allow
+
+
+update_forward_refs(EntityDetails, SearchResults=SearchResults)
+update_forward_refs(EntityRelationships, SearchResults=SearchResults)
+update_forward_refs(RelationshipData, SearchResults=SearchResults)
diff --git a/src/sayari/shared_types/types/entity_details.py b/src/sayari/shared_types/types/entity_details.py
index 377de32..9653527 100644
--- a/src/sayari/shared_types/types/entity_details.py
+++ b/src/sayari/shared_types/types/entity_details.py
@@ -60,5 +60,8 @@ class Config:
from .entity_relationships import EntityRelationships # noqa: E402
+from .relationship_data import RelationshipData # noqa: E402
+update_forward_refs(EntityRelationships, EntityDetails=EntityDetails)
+update_forward_refs(RelationshipData, EntityDetails=EntityDetails)
update_forward_refs(EntityDetails)
diff --git a/src/sayari/shared_types/types/entity_relationships.py b/src/sayari/shared_types/types/entity_relationships.py
index d5b9e16..0df6aec 100644
--- a/src/sayari/shared_types/types/entity_relationships.py
+++ b/src/sayari/shared_types/types/entity_relationships.py
@@ -26,6 +26,9 @@ class Config:
extra = pydantic.Extra.allow
+from .entity_details import EntityDetails # noqa: E402
from .relationship_data import RelationshipData # noqa: E402
+update_forward_refs(EntityDetails, EntityRelationships=EntityRelationships)
+update_forward_refs(RelationshipData, EntityRelationships=EntityRelationships)
update_forward_refs(EntityRelationships)
diff --git a/src/sayari/shared_types/types/relationship_data.py b/src/sayari/shared_types/types/relationship_data.py
index b81f911..d299b68 100644
--- a/src/sayari/shared_types/types/relationship_data.py
+++ b/src/sayari/shared_types/types/relationship_data.py
@@ -35,5 +35,8 @@ class Config:
from .entity_details import EntityDetails # noqa: E402
+from .entity_relationships import EntityRelationships # noqa: E402
+update_forward_refs(EntityDetails, RelationshipData=RelationshipData)
+update_forward_refs(EntityRelationships, RelationshipData=RelationshipData)
update_forward_refs(RelationshipData)
diff --git a/src/sayari/supply_chain/client.py b/src/sayari/supply_chain/client.py
index 4cd131a..80e6330 100644
--- a/src/sayari/supply_chain/client.py
+++ b/src/sayari/supply_chain/client.py
@@ -117,14 +117,14 @@ def upstream_trade_traversal(
f"v1/supply_chain/upstream/{jsonable_encoder(id)}",
method="GET",
params={
- "risk": jsonable_encoder(risk),
- "-risk": jsonable_encoder(not_risk),
- "countries": jsonable_encoder(countries),
- "-countries": jsonable_encoder(not_countries),
- "product": jsonable_encoder(product),
- "-product": jsonable_encoder(not_product),
- "component": jsonable_encoder(component),
- "-component": jsonable_encoder(not_component),
+ "risk": risk,
+ "-risk": not_risk,
+ "countries": countries,
+ "-countries": not_countries,
+ "product": product,
+ "-product": not_product,
+ "component": component,
+ "-component": not_component,
"min_date": min_date,
"max_date": max_date,
"max_depth": max_depth,
@@ -307,14 +307,14 @@ async def main() -> None:
f"v1/supply_chain/upstream/{jsonable_encoder(id)}",
method="GET",
params={
- "risk": jsonable_encoder(risk),
- "-risk": jsonable_encoder(not_risk),
- "countries": jsonable_encoder(countries),
- "-countries": jsonable_encoder(not_countries),
- "product": jsonable_encoder(product),
- "-product": jsonable_encoder(not_product),
- "component": jsonable_encoder(component),
- "-component": jsonable_encoder(not_component),
+ "risk": risk,
+ "-risk": not_risk,
+ "countries": countries,
+ "-countries": not_countries,
+ "product": product,
+ "-product": not_product,
+ "component": component,
+ "-component": not_component,
"min_date": min_date,
"max_date": max_date,
"max_depth": max_depth,
diff --git a/src/sayari/trade/client.py b/src/sayari/trade/client.py
index 539eece..4f5f897 100644
--- a/src/sayari/trade/client.py
+++ b/src/sayari/trade/client.py
@@ -5,6 +5,7 @@
from .types.trade_filter_list import TradeFilterList
from ..core.request_options import RequestOptions
from .types.shipment_search_response import ShipmentSearchResponse
+from ..core.serialization import convert_and_respect_annotation_metadata
from ..core.pydantic_utilities import parse_obj_as
from ..shared_errors.errors.bad_request import BadRequest
from ..shared_errors.types.bad_request_response import BadRequestResponse
@@ -89,7 +90,9 @@ def search_shipments(
},
json={
"q": q,
- "filter": filter,
+ "filter": convert_and_respect_annotation_metadata(
+ object_=filter, annotation=TradeFilterList, direction="write"
+ ),
"facets": facets,
},
request_options=request_options,
@@ -218,7 +221,9 @@ def search_suppliers(
},
json={
"q": q,
- "filter": filter,
+ "filter": convert_and_respect_annotation_metadata(
+ object_=filter, annotation=TradeFilterList, direction="write"
+ ),
"facets": facets,
},
request_options=request_options,
@@ -347,7 +352,9 @@ def search_buyers(
},
json={
"q": q,
- "filter": filter,
+ "filter": convert_and_respect_annotation_metadata(
+ object_=filter, annotation=TradeFilterList, direction="write"
+ ),
"facets": facets,
},
request_options=request_options,
@@ -489,7 +496,9 @@ async def main() -> None:
},
json={
"q": q,
- "filter": filter,
+ "filter": convert_and_respect_annotation_metadata(
+ object_=filter, annotation=TradeFilterList, direction="write"
+ ),
"facets": facets,
},
request_options=request_options,
@@ -626,7 +635,9 @@ async def main() -> None:
},
json={
"q": q,
- "filter": filter,
+ "filter": convert_and_respect_annotation_metadata(
+ object_=filter, annotation=TradeFilterList, direction="write"
+ ),
"facets": facets,
},
request_options=request_options,
@@ -763,7 +774,9 @@ async def main() -> None:
},
json={
"q": q,
- "filter": filter,
+ "filter": convert_and_respect_annotation_metadata(
+ object_=filter, annotation=TradeFilterList, direction="write"
+ ),
"facets": facets,
},
request_options=request_options,
diff --git a/src/sayari/trade/types/buyer_search_response.py b/src/sayari/trade/types/buyer_search_response.py
index 57f965e..97fa17f 100644
--- a/src/sayari/trade/types/buyer_search_response.py
+++ b/src/sayari/trade/types/buyer_search_response.py
@@ -1,10 +1,15 @@
# This file was auto-generated by Fern from our API Definition.
+from __future__ import annotations
from ...base_types.types.paginated_response import PaginatedResponse
+from ...shared_types.types.entity_details import EntityDetails
+from ...shared_types.types.entity_relationships import EntityRelationships
+from ...shared_types.types.relationship_data import RelationshipData
import typing
from .supplier_or_buyer import SupplierOrBuyer
from ...core.pydantic_utilities import IS_PYDANTIC_V2
import pydantic
+from ...core.pydantic_utilities import update_forward_refs
class BuyerSearchResponse(PaginatedResponse):
@@ -167,3 +172,8 @@ class Config:
frozen = True
smart_union = True
extra = pydantic.Extra.allow
+
+
+update_forward_refs(EntityDetails, BuyerSearchResponse=BuyerSearchResponse)
+update_forward_refs(EntityRelationships, BuyerSearchResponse=BuyerSearchResponse)
+update_forward_refs(RelationshipData, BuyerSearchResponse=BuyerSearchResponse)
diff --git a/src/sayari/trade/types/supplier_metadata.py b/src/sayari/trade/types/supplier_metadata.py
index 0642024..83c84db 100644
--- a/src/sayari/trade/types/supplier_metadata.py
+++ b/src/sayari/trade/types/supplier_metadata.py
@@ -1,16 +1,20 @@
# This file was auto-generated by Fern from our API Definition.
from ...core.pydantic_utilities import UniversalBaseModel
+import typing_extensions
import typing
-import pydantic
+from ...core.serialization import FieldMetadata
from .hs_code import HsCode
from ...core.pydantic_utilities import IS_PYDANTIC_V2
+import pydantic
class SupplierMetadata(UniversalBaseModel):
- latest_shipment_date: typing.Optional[str] = pydantic.Field(alias="latestShipmentDate", default=None)
+ latest_shipment_date: typing_extensions.Annotated[
+ typing.Optional[str], FieldMetadata(alias="latestShipmentDate")
+ ] = None
shipments: int
- hs_codes: typing.List[HsCode] = pydantic.Field(alias="hsCodes")
+ hs_codes: typing_extensions.Annotated[typing.List[HsCode], FieldMetadata(alias="hsCodes")]
if IS_PYDANTIC_V2:
model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
diff --git a/src/sayari/trade/types/supplier_or_buyer.py b/src/sayari/trade/types/supplier_or_buyer.py
index b0ddf57..eae8a11 100644
--- a/src/sayari/trade/types/supplier_or_buyer.py
+++ b/src/sayari/trade/types/supplier_or_buyer.py
@@ -1,10 +1,14 @@
# This file was auto-generated by Fern from our API Definition.
+from __future__ import annotations
from ...shared_types.types.entity_details import EntityDetails
+from ...shared_types.types.entity_relationships import EntityRelationships
+from ...shared_types.types.relationship_data import RelationshipData
from .supplier_metadata import SupplierMetadata
from ...core.pydantic_utilities import IS_PYDANTIC_V2
import typing
import pydantic
+from ...core.pydantic_utilities import update_forward_refs
class SupplierOrBuyer(EntityDetails):
@@ -18,3 +22,8 @@ class Config:
frozen = True
smart_union = True
extra = pydantic.Extra.allow
+
+
+update_forward_refs(EntityDetails, SupplierOrBuyer=SupplierOrBuyer)
+update_forward_refs(EntityRelationships, SupplierOrBuyer=SupplierOrBuyer)
+update_forward_refs(RelationshipData, SupplierOrBuyer=SupplierOrBuyer)
diff --git a/src/sayari/trade/types/supplier_search_response.py b/src/sayari/trade/types/supplier_search_response.py
index c80dbef..5acb848 100644
--- a/src/sayari/trade/types/supplier_search_response.py
+++ b/src/sayari/trade/types/supplier_search_response.py
@@ -1,10 +1,15 @@
# This file was auto-generated by Fern from our API Definition.
+from __future__ import annotations
from ...base_types.types.paginated_response import PaginatedResponse
+from ...shared_types.types.entity_details import EntityDetails
+from ...shared_types.types.entity_relationships import EntityRelationships
+from ...shared_types.types.relationship_data import RelationshipData
import typing
from .supplier_or_buyer import SupplierOrBuyer
from ...core.pydantic_utilities import IS_PYDANTIC_V2
import pydantic
+from ...core.pydantic_utilities import update_forward_refs
class SupplierSearchResponse(PaginatedResponse):
@@ -112,3 +117,8 @@ class Config:
frozen = True
smart_union = True
extra = pydantic.Extra.allow
+
+
+update_forward_refs(EntityDetails, SupplierSearchResponse=SupplierSearchResponse)
+update_forward_refs(EntityRelationships, SupplierSearchResponse=SupplierSearchResponse)
+update_forward_refs(RelationshipData, SupplierSearchResponse=SupplierSearchResponse)
diff --git a/src/sayari/traversal/types/shortest_path_data.py b/src/sayari/traversal/types/shortest_path_data.py
index c424ab7..cc2076b 100644
--- a/src/sayari/traversal/types/shortest_path_data.py
+++ b/src/sayari/traversal/types/shortest_path_data.py
@@ -1,11 +1,15 @@
# This file was auto-generated by Fern from our API Definition.
+from __future__ import annotations
from ...core.pydantic_utilities import UniversalBaseModel
from ...shared_types.types.entity_details import EntityDetails
+from ...shared_types.types.entity_relationships import EntityRelationships
+from ...shared_types.types.relationship_data import RelationshipData
import typing
from .traversal_path import TraversalPath
from ...core.pydantic_utilities import IS_PYDANTIC_V2
import pydantic
+from ...core.pydantic_utilities import update_forward_refs
class ShortestPathData(UniversalBaseModel):
@@ -21,3 +25,8 @@ class Config:
frozen = True
smart_union = True
extra = pydantic.Extra.allow
+
+
+update_forward_refs(EntityDetails, ShortestPathData=ShortestPathData)
+update_forward_refs(EntityRelationships, ShortestPathData=ShortestPathData)
+update_forward_refs(RelationshipData, ShortestPathData=ShortestPathData)
diff --git a/src/sayari/traversal/types/shortest_path_response.py b/src/sayari/traversal/types/shortest_path_response.py
index 44fb22b..2cad6d3 100644
--- a/src/sayari/traversal/types/shortest_path_response.py
+++ b/src/sayari/traversal/types/shortest_path_response.py
@@ -1,10 +1,15 @@
# This file was auto-generated by Fern from our API Definition.
+from __future__ import annotations
from ...core.pydantic_utilities import UniversalBaseModel
+from ...shared_types.types.entity_details import EntityDetails
+from ...shared_types.types.entity_relationships import EntityRelationships
+from ...shared_types.types.relationship_data import RelationshipData
import typing
from .shortest_path_data import ShortestPathData
from ...core.pydantic_utilities import IS_PYDANTIC_V2
import pydantic
+from ...core.pydantic_utilities import update_forward_refs
class ShortestPathResponse(UniversalBaseModel):
@@ -438,3 +443,8 @@ class Config:
frozen = True
smart_union = True
extra = pydantic.Extra.allow
+
+
+update_forward_refs(EntityDetails, ShortestPathResponse=ShortestPathResponse)
+update_forward_refs(EntityRelationships, ShortestPathResponse=ShortestPathResponse)
+update_forward_refs(RelationshipData, ShortestPathResponse=ShortestPathResponse)
diff --git a/src/sayari/traversal/types/traversal_data.py b/src/sayari/traversal/types/traversal_data.py
index 58b7644..8b7f798 100644
--- a/src/sayari/traversal/types/traversal_data.py
+++ b/src/sayari/traversal/types/traversal_data.py
@@ -1,11 +1,15 @@
# This file was auto-generated by Fern from our API Definition.
+from __future__ import annotations
from ...core.pydantic_utilities import UniversalBaseModel
from ...shared_types.types.entity_details import EntityDetails
+from ...shared_types.types.entity_relationships import EntityRelationships
+from ...shared_types.types.relationship_data import RelationshipData
import typing
from .traversal_path import TraversalPath
from ...core.pydantic_utilities import IS_PYDANTIC_V2
import pydantic
+from ...core.pydantic_utilities import update_forward_refs
class TraversalData(UniversalBaseModel):
@@ -21,3 +25,8 @@ class Config:
frozen = True
smart_union = True
extra = pydantic.Extra.allow
+
+
+update_forward_refs(EntityDetails, TraversalData=TraversalData)
+update_forward_refs(EntityRelationships, TraversalData=TraversalData)
+update_forward_refs(RelationshipData, TraversalData=TraversalData)
diff --git a/src/sayari/traversal/types/traversal_path.py b/src/sayari/traversal/types/traversal_path.py
index d8d57f0..5db9634 100644
--- a/src/sayari/traversal/types/traversal_path.py
+++ b/src/sayari/traversal/types/traversal_path.py
@@ -1,12 +1,16 @@
# This file was auto-generated by Fern from our API Definition.
+from __future__ import annotations
from ...core.pydantic_utilities import UniversalBaseModel
from ...shared_types.types.entity_details import EntityDetails
+from ...shared_types.types.entity_relationships import EntityRelationships
+from ...shared_types.types.relationship_data import RelationshipData
import typing
from ...generated_types.types.relationships import Relationships
from .traversal_relationship_data import TraversalRelationshipData
from ...core.pydantic_utilities import IS_PYDANTIC_V2
import pydantic
+from ...core.pydantic_utilities import update_forward_refs
class TraversalPath(UniversalBaseModel):
@@ -22,3 +26,8 @@ class Config:
frozen = True
smart_union = True
extra = pydantic.Extra.allow
+
+
+update_forward_refs(EntityDetails, TraversalPath=TraversalPath)
+update_forward_refs(EntityRelationships, TraversalPath=TraversalPath)
+update_forward_refs(RelationshipData, TraversalPath=TraversalPath)
diff --git a/src/sayari/traversal/types/traversal_response.py b/src/sayari/traversal/types/traversal_response.py
index d9b11f8..aafc135 100644
--- a/src/sayari/traversal/types/traversal_response.py
+++ b/src/sayari/traversal/types/traversal_response.py
@@ -1,12 +1,17 @@
# This file was auto-generated by Fern from our API Definition.
+from __future__ import annotations
from ...core.pydantic_utilities import UniversalBaseModel
+from ...shared_types.types.entity_details import EntityDetails
+from ...shared_types.types.entity_relationships import EntityRelationships
+from ...shared_types.types.relationship_data import RelationshipData
import typing
from ...generated_types.types.relationships import Relationships
from ...generated_types.types.country import Country
from .traversal_data import TraversalData
from ...core.pydantic_utilities import IS_PYDANTIC_V2
import pydantic
+from ...core.pydantic_utilities import update_forward_refs
class TraversalResponse(UniversalBaseModel):
@@ -209,3 +214,8 @@ class Config:
frozen = True
smart_union = True
extra = pydantic.Extra.allow
+
+
+update_forward_refs(EntityDetails, TraversalResponse=TraversalResponse)
+update_forward_refs(EntityRelationships, TraversalResponse=TraversalResponse)
+update_forward_refs(RelationshipData, TraversalResponse=TraversalResponse)
diff --git a/tests/utils/test_serialization.py b/tests/utils/test_serialization.py
index 3c9f39d..19b795e 100644
--- a/tests/utils/test_serialization.py
+++ b/tests/utils/test_serialization.py
@@ -18,7 +18,9 @@ def test_convert_and_respect_annotation_metadata() -> None:
"literal": "lit_one",
"any": "any",
}
- converted = convert_and_respect_annotation_metadata(object_=data, annotation=ObjectWithOptionalFieldParams)
+ converted = convert_and_respect_annotation_metadata(
+ object_=data, annotation=ObjectWithOptionalFieldParams, direction="write"
+ )
assert converted == {"string": "string", "long": 12345, "bool": True, "literal": "lit_one", "any": "any"}
@@ -27,7 +29,9 @@ def test_convert_and_respect_annotation_metadata_in_list() -> None:
{"string": "string", "long_": 12345, "bool_": True, "literal": "lit_one", "any": "any"},
{"string": "another string", "long_": 67890, "list_": [], "literal": "lit_one", "any": "any"},
]
- converted = convert_and_respect_annotation_metadata(object_=data, annotation=List[ObjectWithOptionalFieldParams])
+ converted = convert_and_respect_annotation_metadata(
+ object_=data, annotation=List[ObjectWithOptionalFieldParams], direction="write"
+ )
assert converted == [
{"string": "string", "long": 12345, "bool": True, "literal": "lit_one", "any": "any"},
@@ -43,7 +47,9 @@ def test_convert_and_respect_annotation_metadata_in_nested_object() -> None:
"literal": "lit_one",
"any": "any",
}
- converted = convert_and_respect_annotation_metadata(object_=data, annotation=ObjectWithOptionalFieldParams)
+ converted = convert_and_respect_annotation_metadata(
+ object_=data, annotation=ObjectWithOptionalFieldParams, direction="write"
+ )
assert converted == {
"string": "string",
@@ -55,12 +61,12 @@ def test_convert_and_respect_annotation_metadata_in_nested_object() -> None:
def test_convert_and_respect_annotation_metadata_in_union() -> None:
- converted = convert_and_respect_annotation_metadata(object_=UNION_TEST, annotation=ShapeParams)
+ converted = convert_and_respect_annotation_metadata(object_=UNION_TEST, annotation=ShapeParams, direction="write")
assert converted == UNION_TEST_CONVERTED
def test_convert_and_respect_annotation_metadata_with_empty_object() -> None:
data: Any = {}
- converted = convert_and_respect_annotation_metadata(object_=data, annotation=ShapeParams)
+ converted = convert_and_respect_annotation_metadata(object_=data, annotation=ShapeParams, direction="write")
assert converted == data