Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improvement: improve .dict speed by limiting dict calls #4302

Merged
merged 9 commits into from
Aug 14, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
8 changes: 1 addition & 7 deletions generators/python/core_utilities/fastapi/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
from .datetime_utils import serialize_datetime
from .exceptions import FernHTTPException, UnauthorizedException
from .pydantic_utilities import (
IS_PYDANTIC_V2,
UniversalBaseModel,
deep_union_pydantic_dicts,
parse_obj_as,
)
from .pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel, parse_obj_as
from .route_args import route_args
from .security import BearerToken

Expand All @@ -15,7 +10,6 @@
"BearerToken",
"route_args",
"serialize_datetime",
"deep_union_pydantic_dicts",
"parse_obj_as",
"UniversalBaseModel",
"IS_PYDANTIC_V2",
Expand Down
74 changes: 48 additions & 26 deletions generators/python/core_utilities/fastapi/pydantic_utilities.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# This file was auto-generated by Fern from our API Definition.

# nopycln: file
import datetime as dt
import typing
Expand Down Expand Up @@ -53,19 +55,6 @@
Model = typing.TypeVar("Model", bound=pydantic.BaseModel)


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


def parse_obj_as(type_: typing.Type[T], object_: typing.Any) -> T:
if IS_PYDANTIC_V2:
adapter = pydantic.TypeAdapter(type_) # type: ignore # Pydantic v2
Expand Down Expand Up @@ -104,27 +93,34 @@ def json(self, **kwargs: typing.Any) -> str:
return super().json(**kwargs_with_defaults)

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,
**kwargs,
}
kwargs_with_defaults_exclude_none: typing.Any = {
"by_alias": True,
"exclude_none": True,
"include": _fields_set,
**kwargs,
}

if IS_PYDANTIC_V2:
return 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
)
return super().model_dump(**kwargs_with_defaults_exclude_unset) # type: ignore # Pydantic v2
else:
return deep_union_pydantic_dicts(
super().dict(**kwargs_with_defaults_exclude_unset),
super().dict(**kwargs_with_defaults_exclude_none),
)
return super().dict(**kwargs_with_defaults_exclude_unset)


if IS_PYDANTIC_V2:
Expand Down Expand Up @@ -184,3 +180,29 @@ def decorator(func: AnyCallable) -> AnyCallable:
return pydantic.validator(field_name, pre=pre)(func) # type: ignore # Pydantic v1

return decorator


PydanticField = typing.Union[ModelField, pydantic.fields.FieldInfo]


def _get_model_fields(
model: typing.Type["Model"],
) -> typing.Mapping[str, PydanticField]:
if IS_PYDANTIC_V2:
return model.model_fields # type: ignore # Pydantic v2
else:
return model.__fields__ # type: ignore # Pydantic v1


def _get_field_default(field: PydanticField) -> typing.Any:
try:
value = field.get_default() # type: ignore # Pydantic < v1.10.15
except:
value = field.default
if IS_PYDANTIC_V2:
from pydantic_core import PydanticUndefined

if value == PydanticUndefined:
return None
return value
return value
74 changes: 48 additions & 26 deletions generators/python/core_utilities/pydantic/pydantic_utilities.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# This file was auto-generated by Fern from our API Definition.

# nopycln: file
import datetime as dt
import typing
Expand Down Expand Up @@ -53,19 +55,6 @@
Model = typing.TypeVar("Model", bound=pydantic.BaseModel)


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


def parse_obj_as(type_: typing.Type[T], object_: typing.Any) -> T:
if IS_PYDANTIC_V2:
adapter = pydantic.TypeAdapter(type_) # type: ignore # Pydantic v2
Expand Down Expand Up @@ -104,27 +93,34 @@ def json(self, **kwargs: typing.Any) -> str:
return super().json(**kwargs_with_defaults)

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,
**kwargs,
}
kwargs_with_defaults_exclude_none: typing.Any = {
"by_alias": True,
"exclude_none": True,
"include": _fields_set,
**kwargs,
}

if IS_PYDANTIC_V2:
return 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
)
return super().model_dump(**kwargs_with_defaults_exclude_unset) # type: ignore # Pydantic v2
else:
return deep_union_pydantic_dicts(
super().dict(**kwargs_with_defaults_exclude_unset),
super().dict(**kwargs_with_defaults_exclude_none),
)
return super().dict(**kwargs_with_defaults_exclude_unset)


if IS_PYDANTIC_V2:
Expand Down Expand Up @@ -184,3 +180,29 @@ def decorator(func: AnyCallable) -> AnyCallable:
return pydantic.validator(field_name, pre=pre)(func) # type: ignore # Pydantic v1

return decorator


PydanticField = typing.Union[ModelField, pydantic.fields.FieldInfo]


def _get_model_fields(
model: typing.Type["Model"],
) -> typing.Mapping[str, PydanticField]:
if IS_PYDANTIC_V2:
return model.model_fields # type: ignore # Pydantic v2
else:
return model.__fields__ # type: ignore # Pydantic v1


def _get_field_default(field: PydanticField) -> typing.Any:
try:
value = field.get_default() # type: ignore # Pydantic < v1.10.15
except:
value = field.default
if IS_PYDANTIC_V2:
from pydantic_core import PydanticUndefined

if value == PydanticUndefined:
return None
return value
return value
74 changes: 48 additions & 26 deletions generators/python/core_utilities/sdk/pydantic_utilities.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# This file was auto-generated by Fern from our API Definition.

# nopycln: file
import datetime as dt
import typing
Expand Down Expand Up @@ -53,19 +55,6 @@
Model = typing.TypeVar("Model", bound=pydantic.BaseModel)


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


def parse_obj_as(type_: typing.Type[T], object_: typing.Any) -> T:
if IS_PYDANTIC_V2:
adapter = pydantic.TypeAdapter(type_) # type: ignore # Pydantic v2
Expand Down Expand Up @@ -104,27 +93,34 @@ def json(self, **kwargs: typing.Any) -> str:
return super().json(**kwargs_with_defaults)

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,
**kwargs,
}
kwargs_with_defaults_exclude_none: typing.Any = {
"by_alias": True,
"exclude_none": True,
"include": _fields_set,
**kwargs,
}

if IS_PYDANTIC_V2:
return 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
)
return super().model_dump(**kwargs_with_defaults_exclude_unset) # type: ignore # Pydantic v2
else:
return deep_union_pydantic_dicts(
super().dict(**kwargs_with_defaults_exclude_unset),
super().dict(**kwargs_with_defaults_exclude_none),
)
return super().dict(**kwargs_with_defaults_exclude_unset)


if IS_PYDANTIC_V2:
Expand Down Expand Up @@ -184,3 +180,29 @@ def decorator(func: AnyCallable) -> AnyCallable:
return pydantic.validator(field_name, pre=pre)(func) # type: ignore # Pydantic v1

return decorator


PydanticField = typing.Union[ModelField, pydantic.fields.FieldInfo]


def _get_model_fields(
model: typing.Type["Model"],
) -> typing.Mapping[str, PydanticField]:
if IS_PYDANTIC_V2:
return model.model_fields # type: ignore # Pydantic v2
else:
return model.__fields__ # type: ignore # Pydantic v1


def _get_field_default(field: PydanticField) -> typing.Any:
try:
value = field.get_default() # type: ignore # Pydantic < v1.10.15
except:
value = field.default
if IS_PYDANTIC_V2:
from pydantic_core import PydanticUndefined

if value == PydanticUndefined:
return None
return value
return value
Loading
Loading