From ee45b971f98140e50d0690aff224b343b44501b1 Mon Sep 17 00:00:00 2001 From: jameschua Date: Sat, 20 May 2023 17:46:16 +0100 Subject: [PATCH 01/32] work so far --- .../experimental/pydantic/conversion.py | 1 - .../experimental/pydantic/error_type.py | 20 +++++++++++-------- strawberry/experimental/pydantic/fields.py | 6 ++---- strawberry/experimental/pydantic/utils.py | 5 ++--- strawberry/experimental/pydantic/v2_compat.py | 15 ++++++++++++++ 5 files changed, 31 insertions(+), 16 deletions(-) create mode 100644 strawberry/experimental/pydantic/v2_compat.py diff --git a/strawberry/experimental/pydantic/conversion.py b/strawberry/experimental/pydantic/conversion.py index bc0f787948..e138e1e807 100644 --- a/strawberry/experimental/pydantic/conversion.py +++ b/strawberry/experimental/pydantic/conversion.py @@ -9,7 +9,6 @@ from strawberry.union import StrawberryUnion if TYPE_CHECKING: - from strawberry.field import StrawberryField from strawberry.type import StrawberryType diff --git a/strawberry/experimental/pydantic/error_type.py b/strawberry/experimental/pydantic/error_type.py index adcdd5cdf4..5757517acb 100644 --- a/strawberry/experimental/pydantic/error_type.py +++ b/strawberry/experimental/pydantic/error_type.py @@ -16,7 +16,6 @@ ) from pydantic import BaseModel -from pydantic.utils import lenient_issubclass from strawberry.auto import StrawberryAuto from strawberry.experimental.pydantic.utils import ( @@ -24,10 +23,13 @@ get_strawberry_type_from_model, normalize_type, ) +from strawberry.experimental.pydantic.v2_compat import lenient_issubclass from strawberry.object_type import _process_type, _wrap_dataclass from strawberry.types.type_resolver import _get_fields from strawberry.utils.typing import get_list_annotation, is_list + + from .exceptions import MissingFieldsListError if TYPE_CHECKING: @@ -40,6 +42,8 @@ def get_type_for_field(field: ModelField) -> Union[Any, Type[None], Type[List]]: return field_type_to_type(type_) + + def field_type_to_type(type_: Type) -> Union[Any, List[Any], None]: error_class: Any = str strawberry_type: Any = error_class @@ -63,13 +67,13 @@ def field_type_to_type(type_: Type) -> Union[Any, List[Any], None]: def error_type( - model: Type[BaseModel], - *, - fields: Optional[List[str]] = None, - name: Optional[str] = None, - description: Optional[str] = None, - directives: Optional[Sequence[object]] = (), - all_fields: bool = False, + model: Type[BaseModel], + *, + fields: Optional[List[str]] = None, + name: Optional[str] = None, + description: Optional[str] = None, + directives: Optional[Sequence[object]] = (), + all_fields: bool = False, ) -> Callable[..., Type]: def wrap(cls: Type) -> Type: model_fields = model.__fields__ diff --git a/strawberry/experimental/pydantic/fields.py b/strawberry/experimental/pydantic/fields.py index cfa3a6be2c..24d2b60b36 100644 --- a/strawberry/experimental/pydantic/fields.py +++ b/strawberry/experimental/pydantic/fields.py @@ -5,9 +5,8 @@ import pydantic from pydantic import BaseModel -from pydantic.typing import get_args, get_origin, is_new_type, new_type_supertype -from pydantic.utils import lenient_issubclass - +from strawberry.experimental.pydantic.v2_compat import lenient_issubclass, get_args, get_origin, is_new_type, \ + new_type_supertype from strawberry.experimental.pydantic.exceptions import ( UnregisteredTypeException, UnsupportedTypeError, @@ -70,7 +69,6 @@ "RedisDsn": str, } - FIELDS_MAP = { getattr(pydantic, field_name): type for field_name, type in ATTR_TO_TYPE_MAP.items() diff --git a/strawberry/experimental/pydantic/utils.py b/strawberry/experimental/pydantic/utils.py index e863a47e16..0368fd84f9 100644 --- a/strawberry/experimental/pydantic/utils.py +++ b/strawberry/experimental/pydantic/utils.py @@ -14,7 +14,6 @@ cast, ) -from pydantic.utils import smart_deepcopy from strawberry.experimental.pydantic.exceptions import ( AutoFieldsNotInBaseModelError, @@ -76,7 +75,7 @@ def to_tuple(self) -> Tuple[str, Type, dataclasses.Field]: def get_default_factory_for_field( - field: ModelField, + field: ModelField, ) -> Union[NoArgAnyCallable, dataclasses._MISSING_TYPE]: """ Gets the default factory for a pydantic field. @@ -128,7 +127,7 @@ def get_default_factory_for_field( def ensure_all_auto_fields_in_pydantic( - model: Type[BaseModel], auto_fields: Set[str], cls_name: str + model: Type[BaseModel], auto_fields: Set[str], cls_name: str ) -> Union[NoReturn, None]: # Raise error if user defined a strawberry.auto field not present in the model non_existing_fields = list(auto_fields - model.__fields__.keys()) diff --git a/strawberry/experimental/pydantic/v2_compat.py b/strawberry/experimental/pydantic/v2_compat.py new file mode 100644 index 0000000000..7d27fa593d --- /dev/null +++ b/strawberry/experimental/pydantic/v2_compat.py @@ -0,0 +1,15 @@ +import pydantic + +if pydantic.VERSION[0] == '2': + from pydantic._internal._utils import smart_deepcopy + from pydantic._internal._utils import lenient_issubclass + from typing_extensions import get_args, get_origin + from pydantic._internal._typing_extra import is_new_type + def new_type_supertype(type_): + return type_.__supertype__ +else: + from pydantic.utils import smart_deepcopy + from pydantic.utils import lenient_issubclass + from pydantic.typing import get_args, get_origin, is_new_type, new_type_supertype + +__all__ = ["smart_deepcopy", "lenient_issubclass"] From 70c9423c339e61625b31ea0ff8693054418ef6df Mon Sep 17 00:00:00 2001 From: jameschua Date: Sat, 22 Jul 2023 14:23:20 -0700 Subject: [PATCH 02/32] add modelfield --- 2.0.0 | 0 strawberry/experimental/pydantic/object_type.py | 3 ++- strawberry/experimental/pydantic/v2_compat.py | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 2.0.0 diff --git a/2.0.0 b/2.0.0 new file mode 100644 index 0000000000..e69de29bb2 diff --git a/strawberry/experimental/pydantic/object_type.py b/strawberry/experimental/pydantic/object_type.py index a469d24fac..54d2aa562a 100644 --- a/strawberry/experimental/pydantic/object_type.py +++ b/strawberry/experimental/pydantic/object_type.py @@ -34,10 +34,11 @@ from strawberry.object_type import _process_type, _wrap_dataclass from strawberry.types.type_resolver import _get_fields from strawberry.utils.dataclasses import add_custom_init_fn +from strawberry.experimental.pydantic.v2_compat import ModelField if TYPE_CHECKING: from graphql import GraphQLResolveInfo - from pydantic.fields import ModelField + def get_type_for_field(field: ModelField, is_input: bool): # noqa: ANN201 diff --git a/strawberry/experimental/pydantic/v2_compat.py b/strawberry/experimental/pydantic/v2_compat.py index 7d27fa593d..6940ed4e8b 100644 --- a/strawberry/experimental/pydantic/v2_compat.py +++ b/strawberry/experimental/pydantic/v2_compat.py @@ -5,11 +5,13 @@ from pydantic._internal._utils import lenient_issubclass from typing_extensions import get_args, get_origin from pydantic._internal._typing_extra import is_new_type + from pydantic.v1.fields import ModelField as ModelField def new_type_supertype(type_): return type_.__supertype__ else: from pydantic.utils import smart_deepcopy from pydantic.utils import lenient_issubclass from pydantic.typing import get_args, get_origin, is_new_type, new_type_supertype + from pydantic.fields import ModelField as ModelField __all__ = ["smart_deepcopy", "lenient_issubclass"] From fe529080d1df0bc1eee2618ab5c5db02062e89af Mon Sep 17 00:00:00 2001 From: jameschua Date: Sat, 22 Jul 2023 14:59:22 -0700 Subject: [PATCH 03/32] it works kinda --- strawberry/experimental/__init__.py | 3 +- .../experimental/pydantic/error_type.py | 4 +- strawberry/experimental/pydantic/fields.py | 45 ++++++++---- .../experimental/pydantic/object_type.py | 22 +++--- strawberry/experimental/pydantic/utils.py | 3 +- strawberry/experimental/pydantic/v2_compat.py | 68 ++++++++++++++++++- 6 files changed, 113 insertions(+), 32 deletions(-) diff --git a/strawberry/experimental/__init__.py b/strawberry/experimental/__init__.py index 6386ad81d7..27fa5bbb0e 100644 --- a/strawberry/experimental/__init__.py +++ b/strawberry/experimental/__init__.py @@ -1,6 +1,7 @@ try: from . import pydantic -except ImportError: +except ImportError as e: + print("ImportError: ", e) pass else: __all__ = ["pydantic"] diff --git a/strawberry/experimental/pydantic/error_type.py b/strawberry/experimental/pydantic/error_type.py index 5757517acb..06406ccab4 100644 --- a/strawberry/experimental/pydantic/error_type.py +++ b/strawberry/experimental/pydantic/error_type.py @@ -23,7 +23,7 @@ get_strawberry_type_from_model, normalize_type, ) -from strawberry.experimental.pydantic.v2_compat import lenient_issubclass +from strawberry.experimental.pydantic.v2_compat import lenient_issubclass, get_model_fields from strawberry.object_type import _process_type, _wrap_dataclass from strawberry.types.type_resolver import _get_fields from strawberry.utils.typing import get_list_annotation, is_list @@ -76,7 +76,7 @@ def error_type( all_fields: bool = False, ) -> Callable[..., Type]: def wrap(cls: Type) -> Type: - model_fields = model.__fields__ + model_fields = get_model_fields(model) fields_set = set(fields) if fields else set() if fields: diff --git a/strawberry/experimental/pydantic/fields.py b/strawberry/experimental/pydantic/fields.py index 0f3af5a6c5..693b78c9da 100644 --- a/strawberry/experimental/pydantic/fields.py +++ b/strawberry/experimental/pydantic/fields.py @@ -5,8 +5,14 @@ import pydantic from pydantic import BaseModel -from strawberry.experimental.pydantic.v2_compat import lenient_issubclass, get_args, get_origin, is_new_type, \ - new_type_supertype +from strawberry.experimental.pydantic.v2_compat import ( + lenient_issubclass, + get_args, + get_origin, + is_new_type, + new_type_supertype, + IS_PYDANTIC_V2, +) from strawberry.experimental.pydantic.exceptions import ( UnregisteredTypeException, UnsupportedTypeError, @@ -69,22 +75,31 @@ "RedisDsn": str, } -FIELDS_MAP = { - getattr(pydantic, field_name): type - for field_name, type in ATTR_TO_TYPE_MAP.items() - if hasattr(pydantic, field_name) -} +"""TODO: +Most of these fields are not supported by pydantic V2 +""" +FIELDS_MAP = ( + { + getattr(pydantic, field_name): type + for field_name, type in ATTR_TO_TYPE_MAP.items() + if hasattr(pydantic, field_name) + } + if not IS_PYDANTIC_V2 + else {} +) def get_basic_type(type_: Any) -> Type[Any]: - if lenient_issubclass(type_, pydantic.ConstrainedInt): - return int - if lenient_issubclass(type_, pydantic.ConstrainedFloat): - return float - if lenient_issubclass(type_, pydantic.ConstrainedStr): - return str - if lenient_issubclass(type_, pydantic.ConstrainedList): - return List[get_basic_type(type_.item_type)] # type: ignore + if not IS_PYDANTIC_V2: + # only pydantic v1 has these + if lenient_issubclass(type_, pydantic.ConstrainedInt): + return int + if lenient_issubclass(type_, pydantic.ConstrainedFloat): + return float + if lenient_issubclass(type_, pydantic.ConstrainedStr): + return str + if lenient_issubclass(type_, pydantic.ConstrainedList): + return List[get_basic_type(type_.item_type)] # type: ignore if type_ in FIELDS_MAP: type_ = FIELDS_MAP.get(type_) diff --git a/strawberry/experimental/pydantic/object_type.py b/strawberry/experimental/pydantic/object_type.py index e269d070b1..247ce3c6c2 100644 --- a/strawberry/experimental/pydantic/object_type.py +++ b/strawberry/experimental/pydantic/object_type.py @@ -30,29 +30,31 @@ get_default_factory_for_field, get_private_fields, ) +from strawberry.experimental.pydantic.v2_compat import CompatModelField, get_model_fields, IS_PYDANTIC_V2 from strawberry.field import StrawberryField from strawberry.object_type import _process_type, _wrap_dataclass from strawberry.types.type_resolver import _get_fields from strawberry.utils.dataclasses import add_custom_init_fn -from strawberry.experimental.pydantic.v2_compat import ModelField if TYPE_CHECKING: from graphql import GraphQLResolveInfo -def get_type_for_field(field: ModelField, is_input: bool): # noqa: ANN201 +def get_type_for_field(field: CompatModelField, is_input: bool): # noqa: ANN201 outer_type = field.outer_type_ replaced_type = replace_types_recursively(outer_type, is_input) - should_add_optional: bool = field.allow_none - if should_add_optional: - return Optional[replaced_type] - else: - return replaced_type + if not IS_PYDANTIC_V2: + # only pydantic v1 has this Optional logic + should_add_optional: bool = field.allow_none + if should_add_optional: + return Optional[replaced_type] + + return replaced_type def _build_dataclass_creation_fields( - field: ModelField, + field: CompatModelField, is_input: bool, existing_fields: Dict[str, StrawberryField], auto_fields_set: Set[str], @@ -86,7 +88,7 @@ def _build_dataclass_creation_fields( default=dataclasses.MISSING, default_factory=get_default_factory_for_field(field), type_annotation=StrawberryAnnotation.from_annotation(field_type), - description=field.field_info.description, + description=field.description, deprecation_reason=( existing_field.deprecation_reason if existing_field else None ), @@ -124,7 +126,7 @@ def type( use_pydantic_alias: bool = True, ) -> Callable[..., Type[StrawberryTypeFromPydantic[PydanticModel]]]: def wrap(cls: Any) -> Type[StrawberryTypeFromPydantic[PydanticModel]]: - model_fields = model.__fields__ + model_fields = get_model_fields(model) original_fields_set = set(fields) if fields else set() if fields: diff --git a/strawberry/experimental/pydantic/utils.py b/strawberry/experimental/pydantic/utils.py index b9d474c57c..5ed254d5f1 100644 --- a/strawberry/experimental/pydantic/utils.py +++ b/strawberry/experimental/pydantic/utils.py @@ -20,6 +20,7 @@ BothDefaultAndDefaultFactoryDefinedError, UnregisteredTypeException, ) +from strawberry.experimental.pydantic.v2_compat import CompatModelField, smart_deepcopy from strawberry.private import is_private from strawberry.unset import UNSET from strawberry.utils.typing import ( @@ -69,7 +70,7 @@ def to_tuple(self) -> Tuple[str, Type, dataclasses.Field]: def get_default_factory_for_field( - field: ModelField, + field: CompatModelField, ) -> Union[NoArgAnyCallable, dataclasses._MISSING_TYPE]: """ Gets the default factory for a pydantic field. diff --git a/strawberry/experimental/pydantic/v2_compat.py b/strawberry/experimental/pydantic/v2_compat.py index 6940ed4e8b..0d56bbda3d 100644 --- a/strawberry/experimental/pydantic/v2_compat.py +++ b/strawberry/experimental/pydantic/v2_compat.py @@ -1,17 +1,79 @@ +from dataclasses import dataclass +from typing import Dict, Type, Any, Optional, Callable + import pydantic +from pydantic import BaseModel +from pydantic.v1.typing import NoArgAnyCallable +from pydantic.version import VERSION as PYDANTIC_VERSION + +IS_PYDANTIC_V2: bool = PYDANTIC_VERSION.startswith("2.") + + +@dataclass +class CompatModelField: + name: str + outer_type_: Any + default: Any + default_factory: Optional[Callable[[], Any]] + required: bool + alias: str + allow_none: bool + has_alias: bool + description: str + -if pydantic.VERSION[0] == '2': +if pydantic.VERSION[0] == "2": from pydantic._internal._utils import smart_deepcopy from pydantic._internal._utils import lenient_issubclass from typing_extensions import get_args, get_origin from pydantic._internal._typing_extra import is_new_type - from pydantic.v1.fields import ModelField as ModelField + from pydantic.v1.fields import ModelField + from pydantic.fields import FieldInfo + def new_type_supertype(type_): return type_.__supertype__ + + def get_model_fields(model: Type[BaseModel]) -> Dict[str, CompatModelField]: + field_info: dict[str, FieldInfo] = model.model_fields + new_fields = {} + # Convert it into CompatModelField + for name, field in field_info.items(): + new_fields[name] = CompatModelField( + name=name, + outer_type_=field.annotation, + default=field.default, + default_factory=field.default_factory, + required=field.is_required(), + alias=field.alias, + # v2 doesn't have allow_none + allow_none=False, + has_alias=field is not None, + description=field.description, + ) + return new_fields + else: from pydantic.utils import smart_deepcopy from pydantic.utils import lenient_issubclass from pydantic.typing import get_args, get_origin, is_new_type, new_type_supertype - from pydantic.fields import ModelField as ModelField + from pydantic import ModelField + + def get_model_fields(model: Type[BaseModel]) -> Dict[str, CompatModelField]: + new_fields = {} + # Convert it into CompatModelField + for name, field in model.__fields__.items(): + new_fields[name] = CompatModelField( + name=name, + outer_type_=field.type_, + default=field.default, + default_factory=field.default_factory, + required=field.required, + alias=field.alias, + allow_none=field.allow_none, + has_alias=field.has_alias, + description=field.field_info.description, + ) + return new_fields + __all__ = ["smart_deepcopy", "lenient_issubclass"] From 356a5fbd352c73b61ade50ca18d99d3283a159d6 Mon Sep 17 00:00:00 2001 From: jameschua Date: Sat, 22 Jul 2023 15:06:20 -0700 Subject: [PATCH 04/32] fix missing type --- strawberry/experimental/pydantic/utils.py | 10 +++++----- strawberry/experimental/pydantic/v2_compat.py | 6 ++++++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/strawberry/experimental/pydantic/utils.py b/strawberry/experimental/pydantic/utils.py index 5ed254d5f1..9f595dde88 100644 --- a/strawberry/experimental/pydantic/utils.py +++ b/strawberry/experimental/pydantic/utils.py @@ -20,7 +20,7 @@ BothDefaultAndDefaultFactoryDefinedError, UnregisteredTypeException, ) -from strawberry.experimental.pydantic.v2_compat import CompatModelField, smart_deepcopy +from strawberry.experimental.pydantic.v2_compat import CompatModelField, smart_deepcopy, PYDANTIC_MISSING_TYPE from strawberry.private import is_private from strawberry.unset import UNSET from strawberry.utils.typing import ( @@ -70,7 +70,7 @@ def to_tuple(self) -> Tuple[str, Type, dataclasses.Field]: def get_default_factory_for_field( - field: CompatModelField, + field: CompatModelField, ) -> Union[NoArgAnyCallable, dataclasses._MISSING_TYPE]: """ Gets the default factory for a pydantic field. @@ -83,10 +83,10 @@ def get_default_factory_for_field( # replace dataclasses.MISSING with our own UNSET to make comparisons easier default_factory = ( field.default_factory - if field.default_factory is not dataclasses.MISSING + if field.default_factory is not PYDANTIC_MISSING_TYPE else UNSET ) - default = field.default if field.default is not dataclasses.MISSING else UNSET + default = field.default if field.default is not PYDANTIC_MISSING_TYPE else UNSET has_factory = default_factory is not None and default_factory is not UNSET has_default = default is not None and default is not UNSET @@ -122,7 +122,7 @@ def get_default_factory_for_field( def ensure_all_auto_fields_in_pydantic( - model: Type[BaseModel], auto_fields: Set[str], cls_name: str + model: Type[BaseModel], auto_fields: Set[str], cls_name: str ) -> Union[NoReturn, None]: # Raise error if user defined a strawberry.auto field not present in the model non_existing_fields = list(auto_fields - model.__fields__.keys()) diff --git a/strawberry/experimental/pydantic/v2_compat.py b/strawberry/experimental/pydantic/v2_compat.py index 0d56bbda3d..23bb314fb9 100644 --- a/strawberry/experimental/pydantic/v2_compat.py +++ b/strawberry/experimental/pydantic/v2_compat.py @@ -1,3 +1,4 @@ +import dataclasses from dataclasses import dataclass from typing import Dict, Type, Any, Optional, Callable @@ -5,6 +6,7 @@ from pydantic import BaseModel from pydantic.v1.typing import NoArgAnyCallable from pydantic.version import VERSION as PYDANTIC_VERSION +from pydantic_core import PydanticUndefined IS_PYDANTIC_V2: bool = PYDANTIC_VERSION.startswith("2.") @@ -30,6 +32,8 @@ class CompatModelField: from pydantic.v1.fields import ModelField from pydantic.fields import FieldInfo + PYDANTIC_MISSING_TYPE = PydanticUndefined + def new_type_supertype(type_): return type_.__supertype__ @@ -58,6 +62,8 @@ def get_model_fields(model: Type[BaseModel]) -> Dict[str, CompatModelField]: from pydantic.typing import get_args, get_origin, is_new_type, new_type_supertype from pydantic import ModelField + PYDANTIC_MISSING_TYPE = dataclasses.MISSING + def get_model_fields(model: Type[BaseModel]) -> Dict[str, CompatModelField]: new_fields = {} # Convert it into CompatModelField From 0c45267b24da69b1737ae70d048ecc0b63db412a Mon Sep 17 00:00:00 2001 From: jameschua Date: Sat, 22 Jul 2023 15:29:50 -0700 Subject: [PATCH 05/32] fix default tesT --- strawberry/experimental/pydantic/utils.py | 7 ++- tests/experimental/pydantic/test_basic.py | 3 +- .../experimental/pydantic/test_conversion.py | 58 ++++++++++++++----- 3 files changed, 48 insertions(+), 20 deletions(-) diff --git a/strawberry/experimental/pydantic/utils.py b/strawberry/experimental/pydantic/utils.py index 9f595dde88..382b31d587 100644 --- a/strawberry/experimental/pydantic/utils.py +++ b/strawberry/experimental/pydantic/utils.py @@ -20,7 +20,8 @@ BothDefaultAndDefaultFactoryDefinedError, UnregisteredTypeException, ) -from strawberry.experimental.pydantic.v2_compat import CompatModelField, smart_deepcopy, PYDANTIC_MISSING_TYPE +from strawberry.experimental.pydantic.v2_compat import CompatModelField, smart_deepcopy, PYDANTIC_MISSING_TYPE, \ + get_model_fields from strawberry.private import is_private from strawberry.unset import UNSET from strawberry.utils.typing import ( @@ -71,7 +72,7 @@ def to_tuple(self) -> Tuple[str, Type, dataclasses.Field]: def get_default_factory_for_field( field: CompatModelField, -) -> Union[NoArgAnyCallable, dataclasses._MISSING_TYPE]: +) -> Union[NoArgAnyCallable, PYDANTIC_MISSING_TYPE]: """ Gets the default factory for a pydantic field. @@ -125,7 +126,7 @@ def ensure_all_auto_fields_in_pydantic( model: Type[BaseModel], auto_fields: Set[str], cls_name: str ) -> Union[NoReturn, None]: # Raise error if user defined a strawberry.auto field not present in the model - non_existing_fields = list(auto_fields - model.__fields__.keys()) + non_existing_fields = list(auto_fields - get_model_fields(model).keys()) if non_existing_fields: raise AutoFieldsNotInBaseModelError( diff --git a/tests/experimental/pydantic/test_basic.py b/tests/experimental/pydantic/test_basic.py index f5b7280dec..3f8a8a8259 100644 --- a/tests/experimental/pydantic/test_basic.py +++ b/tests/experimental/pydantic/test_basic.py @@ -625,7 +625,8 @@ class Work(pydantic.BaseModel): class User(pydantic.BaseModel): name: str - work: Optional[Work] + # Note that pydantic v2 requires an explicit default of None for Optionals + work: Optional[Work] = None class Group(pydantic.BaseModel): users: List[User] diff --git a/tests/experimental/pydantic/test_conversion.py b/tests/experimental/pydantic/test_conversion.py index 5303be0562..75da6aee57 100644 --- a/tests/experimental/pydantic/test_conversion.py +++ b/tests/experimental/pydantic/test_conversion.py @@ -7,8 +7,6 @@ import pytest from pydantic import BaseConfig, BaseModel, Field, ValidationError -from pydantic.fields import ModelField -from pydantic.typing import NoArgAnyCallable import strawberry from strawberry.experimental.pydantic.exceptions import ( @@ -16,9 +14,19 @@ BothDefaultAndDefaultFactoryDefinedError, ) from strawberry.experimental.pydantic.utils import get_default_factory_for_field +from strawberry.experimental.pydantic.v2_compat import ( + IS_PYDANTIC_V2, + CompatModelField, + PYDANTIC_MISSING_TYPE, +) from strawberry.type import StrawberryList, StrawberryOptional from strawberry.types.types import StrawberryObjectDefinition +if IS_PYDANTIC_V2: + from pydantic.v1.fields import ModelField +else: + from pydantic.fields import ModelField + def test_can_use_type_standalone(): class User(BaseModel): @@ -839,15 +847,19 @@ class UserType: def test_get_default_factory_for_field(): def _get_field( - default: Any = dataclasses.MISSING, default_factory: Any = dataclasses.MISSING - ) -> ModelField: - return ModelField( + default: Any = PYDANTIC_MISSING_TYPE, + default_factory: Any = PYDANTIC_MISSING_TYPE, + ) -> CompatModelField: + return CompatModelField( name="a", - type_=str, - class_validators={}, - model_config=BaseConfig, + outer_type_=str, default=default, default_factory=default_factory, + alias="a", + allow_none=False, + description="", + has_alias=False, + required=True, ) field = _get_field() @@ -867,7 +879,7 @@ def factory_func(): field = _get_field(mutable_default) created_factory = get_default_factory_for_field(field) - created_factory = cast(NoArgAnyCallable, created_factory) + created_factory = created_factory # should return a factory that copies the default parameter assert created_factory() == mutable_default @@ -885,13 +897,27 @@ def factory_func(): def test_convert_input_types_to_pydantic_default_and_default_factory(): # Pydantic should raise an error if the user specifies both default # and default_factory. this checks for a regression on their side - with pytest.raises( - ValueError, - match=("cannot specify both default and default_factory"), - ): - - class User(BaseModel): - password: Optional[str] = Field(default=None, default_factory=lambda: None) + if IS_PYDANTIC_V2: + with pytest.raises( + TypeError, + match=("cannot specify both default and default_factory"), + ): + + class User(BaseModel): + password: Optional[str] = Field( + default=None, default_factory=lambda: None + ) + + else: + with pytest.raises( + ValueError, + match=("cannot specify both default and default_factory"), + ): + + class User(BaseModel): + password: Optional[str] = Field( + default=None, default_factory=lambda: None + ) def test_can_convert_pydantic_type_to_strawberry_with_additional_field_resolvers(): From 37b8c2e88304abedb77496970de916d83f257872 Mon Sep 17 00:00:00 2001 From: jameschua Date: Sat, 22 Jul 2023 15:40:44 -0700 Subject: [PATCH 06/32] skip tests for constrained types --- pyproject.toml | 2 ++ strawberry/experimental/pydantic/v2_compat.py | 1 + tests/experimental/pydantic/test_fields.py | 20 ++++++++++++++++--- tests/experimental/pydantic/utils.py | 6 ++++++ 4 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 tests/experimental/pydantic/utils.py diff --git a/pyproject.toml b/pyproject.toml index f35e3dfe58..801bbea7bb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -167,6 +167,8 @@ markers = [ "sanic", "starlette", "starlite", + "skip_on_", + "pydantic_v1" ] asyncio_mode = "auto" filterwarnings = [ diff --git a/strawberry/experimental/pydantic/v2_compat.py b/strawberry/experimental/pydantic/v2_compat.py index 23bb314fb9..6560dcf974 100644 --- a/strawberry/experimental/pydantic/v2_compat.py +++ b/strawberry/experimental/pydantic/v2_compat.py @@ -9,6 +9,7 @@ from pydantic_core import PydanticUndefined IS_PYDANTIC_V2: bool = PYDANTIC_VERSION.startswith("2.") +IS_PYDANTIC_V1: bool = not IS_PYDANTIC_V2 @dataclass diff --git a/tests/experimental/pydantic/test_fields.py b/tests/experimental/pydantic/test_fields.py index d553318766..3eae755be2 100644 --- a/tests/experimental/pydantic/test_fields.py +++ b/tests/experimental/pydantic/test_fields.py @@ -7,10 +7,13 @@ from pydantic import BaseModel, ValidationError, conlist import strawberry +from strawberry.experimental.pydantic.v2_compat import IS_PYDANTIC_V1 from strawberry.type import StrawberryOptional from strawberry.types.types import StrawberryObjectDefinition +from tests.experimental.pydantic.utils import needs_pydanticv2, needs_pydanticv1 +@needs_pydanticv1 @pytest.mark.parametrize( ("pydantic_type", "field_type"), [ @@ -30,7 +33,9 @@ (pydantic.HttpUrl, str), (pydantic.PostgresDsn, str), (pydantic.RedisDsn, str), - ], + ] + if IS_PYDANTIC_V1 + else [], ) def test_types(pydantic_type, field_type): class Model(pydantic.BaseModel): @@ -49,9 +54,10 @@ class Type: assert field.type is field_type +@needs_pydanticv1 @pytest.mark.parametrize( ("pydantic_type", "field_type"), - [(pydantic.NoneStr, str)], + [(pydantic.NoneStr, str)] if IS_PYDANTIC_V1 else [], ) def test_types_optional(pydantic_type, field_type): class Model(pydantic.BaseModel): @@ -71,6 +77,7 @@ class Type: assert field.type.of_type is field_type +@needs_pydanticv2 def test_conint(): class Model(pydantic.BaseModel): field: pydantic.conint(lt=100) @@ -88,6 +95,7 @@ class Type: assert field.type is int +@needs_pydanticv1 def test_confloat(): class Model(pydantic.BaseModel): field: pydantic.confloat(lt=100.5) @@ -105,6 +113,7 @@ class Type: assert field.type is float +@needs_pydanticv1 def test_constr(): class Model(pydantic.BaseModel): field: pydantic.constr(max_length=100) @@ -122,6 +131,7 @@ class Type: assert field.type is str +@needs_pydanticv1 def test_constrained_list(): class User(BaseModel): friends: conlist(str, min_items=1) @@ -149,6 +159,7 @@ class UserType: data.to_pydantic() +@needs_pydanticv1 def test_constrained_list_nested(): class User(BaseModel): friends: conlist(conlist(int, min_items=1), min_items=1) @@ -164,6 +175,7 @@ class UserType: ) +@needs_pydanticv1 @pytest.mark.parametrize( "pydantic_type", [ @@ -176,7 +188,9 @@ class UserType: pydantic.PaymentCardNumber, pydantic.ByteSize, # pydantic.JsonWrapper, - ], + ] + if IS_PYDANTIC_V1 + else [], ) def test_unsupported_types(pydantic_type): class Model(pydantic.BaseModel): diff --git a/tests/experimental/pydantic/utils.py b/tests/experimental/pydantic/utils.py new file mode 100644 index 0000000000..e99b37f0e3 --- /dev/null +++ b/tests/experimental/pydantic/utils.py @@ -0,0 +1,6 @@ +import pytest + +from strawberry.experimental.pydantic.v2_compat import IS_PYDANTIC_V2 + +needs_pydanticv2 = pytest.mark.skipif(not IS_PYDANTIC_V2, reason="requires Pydantic v2") +needs_pydanticv1 = pytest.mark.skipif(IS_PYDANTIC_V2, reason="requires Pydantic v1") \ No newline at end of file From f45d576ccfd2dcb6f3140d91f62fb197968ee809 Mon Sep 17 00:00:00 2001 From: jameschua Date: Sat, 22 Jul 2023 15:54:10 -0700 Subject: [PATCH 07/32] add tests pass? --- strawberry/experimental/pydantic/fields.py | 11 +++- .../pydantic/schema/test_mutation.py | 52 ++++++++++++++----- 2 files changed, 49 insertions(+), 14 deletions(-) diff --git a/strawberry/experimental/pydantic/fields.py b/strawberry/experimental/pydantic/fields.py index 693b78c9da..b5b14e1008 100644 --- a/strawberry/experimental/pydantic/fields.py +++ b/strawberry/experimental/pydantic/fields.py @@ -1,6 +1,7 @@ import builtins +import types from decimal import Decimal -from typing import Any, List, Optional, Type +from typing import Any, List, Optional, Type, Union from uuid import UUID import pydantic @@ -21,6 +22,7 @@ try: from typing import GenericAlias as TypingGenericAlias # type: ignore + from types import UnionType as TypingUnionType # type: ignore except ImportError: import sys @@ -30,6 +32,10 @@ TypingGenericAlias = () else: raise + if sys.version_info < (3, 10): + TypingUnionType = () + else: + raise ATTR_TO_TYPE_MAP = { "NoneStr": Optional[str], @@ -138,7 +144,8 @@ def replace_types_recursively(type_: Any, is_input: bool) -> Any: if isinstance(replaced_type, TypingGenericAlias): return TypingGenericAlias(origin, converted) - + if isinstance(replaced_type, TypingUnionType): + return Union[converted] replaced_type = replaced_type.copy_with(converted) if isinstance(replaced_type, StrawberryObjectDefinition): diff --git a/tests/experimental/pydantic/schema/test_mutation.py b/tests/experimental/pydantic/schema/test_mutation.py index 5ae48f65a3..06bb00cba6 100644 --- a/tests/experimental/pydantic/schema/test_mutation.py +++ b/tests/experimental/pydantic/schema/test_mutation.py @@ -3,6 +3,7 @@ import pydantic import strawberry +from strawberry.experimental.pydantic.v2_compat import IS_PYDANTIC_V2 def test_mutation(): @@ -79,10 +80,20 @@ def create_user(self, input: CreateUserInput) -> UserType: result = schema.execute_sync(query) - assert result.errors[0].message == ( - "1 validation error for User\nname\n ensure this value has at " - "least 2 characters (type=value_error.any_str.min_length; limit_value=2)" - ) + if IS_PYDANTIC_V2: + assert result.errors[0].message == ( + "1 validation error for User\n" + "name\n" + " String should have at least 2 characters [type=string_too_short, " + "input_value='P', input_type=str]\n" + " For further information visit " + "https://errors.pydantic.dev/2.0.3/v/string_too_short" + ) + else: + assert result.errors[0].message == ( + "1 validation error for User\nname\n ensure this value has at " + "least 2 characters (type=value_error.any_str.min_length; limit_value=2)" + ) def test_mutation_with_validation_of_nested_model(): @@ -131,11 +142,22 @@ def create_user(self, input: CreateUserInput) -> UserType: result = schema.execute_sync(query) - assert result.errors[0].message == ( - "1 validation error for HobbyInputModel\nname\n" - " ensure this value has at least 2 characters " - "(type=value_error.any_str.min_length; limit_value=2)" - ) + if IS_PYDANTIC_V2: + assert result.errors[0].message == ( + "1 validation error for HobbyInputModel\n" + "name\n" + " String should have at least 2 characters [type=string_too_short, " + "input_value='P', input_type=str]\n" + " For further information visit " + "https://errors.pydantic.dev/2.0.3/v/string_too_short" + ) + + else: + assert result.errors[0].message == ( + "1 validation error for HobbyInputModel\nname\n" + " ensure this value has at least 2 characters " + "(type=value_error.any_str.min_length; limit_value=2)" + ) def test_mutation_with_validation_and_error_type(): @@ -194,6 +216,12 @@ def create_user(self, input: CreateUserInput) -> Union[UserType, UserError]: assert result.errors is None assert result.data["createUser"].get("name") is None - assert result.data["createUser"]["nameErrors"] == [ - ("ensure this value has at least 2 characters") - ] + + if IS_PYDANTIC_V2: + assert result.data["createUser"]["nameErrors"] == [ + ("String should have at least 2 characters") + ] + else: + assert result.data["createUser"]["nameErrors"] == [ + ("ensure this value has at least 2 characters") + ] From dc0b9dd4f81606c1bd98a9ed169926d52160d1a0 Mon Sep 17 00:00:00 2001 From: jameschua Date: Sat, 22 Jul 2023 15:56:46 -0700 Subject: [PATCH 08/32] ruff --- strawberry/experimental/__init__.py | 1 - .../experimental/pydantic/conversion.py | 2 +- .../experimental/pydantic/error_type.py | 7 ++++--- strawberry/experimental/pydantic/fields.py | 18 ++++++++-------- .../experimental/pydantic/object_type.py | 6 +++++- strawberry/experimental/pydantic/utils.py | 10 +++++---- strawberry/experimental/pydantic/v2_compat.py | 21 +++++++------------ strawberry/ext/mypy_plugin.py | 4 ++-- strawberry/test/client.py | 4 ++-- tests/cli/snapshots/unions.py | 3 ++- tests/cli/snapshots/unions_py38.py | 3 ++- .../cli/snapshots/unions_typing_extension.py | 3 ++- .../experimental/pydantic/test_conversion.py | 10 ++++----- tests/experimental/pydantic/test_fields.py | 2 +- tests/experimental/pydantic/utils.py | 2 +- tests/http/clients/base.py | 4 ++-- tests/test_dataloaders.py | 2 +- 17 files changed, 53 insertions(+), 49 deletions(-) diff --git a/strawberry/experimental/__init__.py b/strawberry/experimental/__init__.py index 27fa5bbb0e..0dffcbb051 100644 --- a/strawberry/experimental/__init__.py +++ b/strawberry/experimental/__init__.py @@ -1,7 +1,6 @@ try: from . import pydantic except ImportError as e: - print("ImportError: ", e) pass else: __all__ = ["pydantic"] diff --git a/strawberry/experimental/pydantic/conversion.py b/strawberry/experimental/pydantic/conversion.py index 05e9544372..c1f4f9dbaf 100644 --- a/strawberry/experimental/pydantic/conversion.py +++ b/strawberry/experimental/pydantic/conversion.py @@ -13,7 +13,7 @@ from strawberry.union import StrawberryUnion if TYPE_CHECKING: - from strawberry.type import StrawberryType + from strawberry.type import StrawberryField, StrawberryType def _convert_from_pydantic_to_strawberry_type( diff --git a/strawberry/experimental/pydantic/error_type.py b/strawberry/experimental/pydantic/error_type.py index 06406ccab4..967885f1bc 100644 --- a/strawberry/experimental/pydantic/error_type.py +++ b/strawberry/experimental/pydantic/error_type.py @@ -23,13 +23,14 @@ get_strawberry_type_from_model, normalize_type, ) -from strawberry.experimental.pydantic.v2_compat import lenient_issubclass, get_model_fields +from strawberry.experimental.pydantic.v2_compat import ( + get_model_fields, + lenient_issubclass, +) from strawberry.object_type import _process_type, _wrap_dataclass from strawberry.types.type_resolver import _get_fields from strawberry.utils.typing import get_list_annotation, is_list - - from .exceptions import MissingFieldsListError if TYPE_CHECKING: diff --git a/strawberry/experimental/pydantic/fields.py b/strawberry/experimental/pydantic/fields.py index b5b14e1008..2cbf42f62c 100644 --- a/strawberry/experimental/pydantic/fields.py +++ b/strawberry/experimental/pydantic/fields.py @@ -1,28 +1,28 @@ import builtins -import types from decimal import Decimal from typing import Any, List, Optional, Type, Union from uuid import UUID import pydantic from pydantic import BaseModel + +from strawberry.experimental.pydantic.exceptions import ( + UnregisteredTypeException, + UnsupportedTypeError, +) from strawberry.experimental.pydantic.v2_compat import ( - lenient_issubclass, + IS_PYDANTIC_V2, get_args, get_origin, is_new_type, + lenient_issubclass, new_type_supertype, - IS_PYDANTIC_V2, -) -from strawberry.experimental.pydantic.exceptions import ( - UnregisteredTypeException, - UnsupportedTypeError, ) from strawberry.types.types import StrawberryObjectDefinition try: - from typing import GenericAlias as TypingGenericAlias # type: ignore from types import UnionType as TypingUnionType # type: ignore + from typing import GenericAlias as TypingGenericAlias # type: ignore except ImportError: import sys @@ -82,7 +82,7 @@ } """TODO: -Most of these fields are not supported by pydantic V2 +Most of these fields are not supported by pydantic V2 """ FIELDS_MAP = ( { diff --git a/strawberry/experimental/pydantic/object_type.py b/strawberry/experimental/pydantic/object_type.py index 247ce3c6c2..b10e479286 100644 --- a/strawberry/experimental/pydantic/object_type.py +++ b/strawberry/experimental/pydantic/object_type.py @@ -30,7 +30,11 @@ get_default_factory_for_field, get_private_fields, ) -from strawberry.experimental.pydantic.v2_compat import CompatModelField, get_model_fields, IS_PYDANTIC_V2 +from strawberry.experimental.pydantic.v2_compat import ( + IS_PYDANTIC_V2, + CompatModelField, + get_model_fields, +) from strawberry.field import StrawberryField from strawberry.object_type import _process_type, _wrap_dataclass from strawberry.types.type_resolver import _get_fields diff --git a/strawberry/experimental/pydantic/utils.py b/strawberry/experimental/pydantic/utils.py index 382b31d587..1453667680 100644 --- a/strawberry/experimental/pydantic/utils.py +++ b/strawberry/experimental/pydantic/utils.py @@ -14,14 +14,17 @@ cast, ) - from strawberry.experimental.pydantic.exceptions import ( AutoFieldsNotInBaseModelError, BothDefaultAndDefaultFactoryDefinedError, UnregisteredTypeException, ) -from strawberry.experimental.pydantic.v2_compat import CompatModelField, smart_deepcopy, PYDANTIC_MISSING_TYPE, \ - get_model_fields +from strawberry.experimental.pydantic.v2_compat import ( + PYDANTIC_MISSING_TYPE, + CompatModelField, + get_model_fields, + smart_deepcopy, +) from strawberry.private import is_private from strawberry.unset import UNSET from strawberry.utils.typing import ( @@ -33,7 +36,6 @@ if TYPE_CHECKING: from pydantic import BaseModel - from pydantic.fields import ModelField from pydantic.typing import NoArgAnyCallable diff --git a/strawberry/experimental/pydantic/v2_compat.py b/strawberry/experimental/pydantic/v2_compat.py index 6560dcf974..d887f8ec18 100644 --- a/strawberry/experimental/pydantic/v2_compat.py +++ b/strawberry/experimental/pydantic/v2_compat.py @@ -1,13 +1,15 @@ import dataclasses from dataclasses import dataclass -from typing import Dict, Type, Any, Optional, Callable +from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, Type import pydantic from pydantic import BaseModel -from pydantic.v1.typing import NoArgAnyCallable from pydantic.version import VERSION as PYDANTIC_VERSION from pydantic_core import PydanticUndefined +if TYPE_CHECKING: + from pydantic.fields import FieldInfo + IS_PYDANTIC_V2: bool = PYDANTIC_VERSION.startswith("2.") IS_PYDANTIC_V1: bool = not IS_PYDANTIC_V2 @@ -26,16 +28,12 @@ class CompatModelField: if pydantic.VERSION[0] == "2": - from pydantic._internal._utils import smart_deepcopy - from pydantic._internal._utils import lenient_issubclass - from typing_extensions import get_args, get_origin - from pydantic._internal._typing_extra import is_new_type - from pydantic.v1.fields import ModelField - from pydantic.fields import FieldInfo + + from pydantic._internal._utils import lenient_issubclass, smart_deepcopy PYDANTIC_MISSING_TYPE = PydanticUndefined - def new_type_supertype(type_): + def new_type_supertype(type_: Any) -> Any: return type_.__supertype__ def get_model_fields(model: Type[BaseModel]) -> Dict[str, CompatModelField]: @@ -58,10 +56,7 @@ def get_model_fields(model: Type[BaseModel]) -> Dict[str, CompatModelField]: return new_fields else: - from pydantic.utils import smart_deepcopy - from pydantic.utils import lenient_issubclass - from pydantic.typing import get_args, get_origin, is_new_type, new_type_supertype - from pydantic import ModelField + from pydantic.utils import lenient_issubclass, smart_deepcopy PYDANTIC_MISSING_TYPE = dataclasses.MISSING diff --git a/strawberry/ext/mypy_plugin.py b/strawberry/ext/mypy_plugin.py index 1da6f7f44e..82095cf4d7 100644 --- a/strawberry/ext/mypy_plugin.py +++ b/strawberry/ext/mypy_plugin.py @@ -409,9 +409,9 @@ def strawberry_pydantic_class_callback(ctx: ClassDefContext) -> None: pydantic_fields: Set[PydanticModelField] = set() try: - for _name, data in model_type.type.metadata[PYDANTIC_METADATA_KEY][ + for data in model_type.type.metadata[PYDANTIC_METADATA_KEY][ "fields" - ].items(): + ].values(): field = PydanticModelField.deserialize(ctx.cls.info, data) pydantic_fields.add(field) except KeyError: diff --git a/strawberry/test/client.py b/strawberry/test/client.py index 093f46abda..4ef79354e4 100644 --- a/strawberry/test/client.py +++ b/strawberry/test/client.py @@ -136,7 +136,7 @@ def _build_multipart_file_map( # In case of folders the variables will look like # `{"folder": {"files": ...]}}` if isinstance(values, dict): - folder_key = list(values.keys())[0] + folder_key = next(iter(values.keys())) reference += f".{folder_key}" # the list of file is inside the folder keyword variable_values = variable_values[folder_key] @@ -146,7 +146,7 @@ def _build_multipart_file_map( # copying `files` as when we map a file we must discard from the dict _kwargs = files.copy() for index, _ in enumerate(variable_values): - k = list(_kwargs.keys())[0] + k = next(iter(_kwargs.keys())) _kwargs.pop(k) map.setdefault(k, []) map[k].append(f"variables.{reference}.{index}") diff --git a/tests/cli/snapshots/unions.py b/tests/cli/snapshots/unions.py index 2f03e0bb4b..d725469ce5 100644 --- a/tests/cli/snapshots/unions.py +++ b/tests/cli/snapshots/unions.py @@ -1,6 +1,7 @@ -import strawberry from typing import Annotated +import strawberry + # create a few types and then a union type diff --git a/tests/cli/snapshots/unions_py38.py b/tests/cli/snapshots/unions_py38.py index 4fd0143c69..b7ead3da65 100644 --- a/tests/cli/snapshots/unions_py38.py +++ b/tests/cli/snapshots/unions_py38.py @@ -1,6 +1,7 @@ -import strawberry from typing import Annotated, Union +import strawberry + # create a few types and then a union type diff --git a/tests/cli/snapshots/unions_typing_extension.py b/tests/cli/snapshots/unions_typing_extension.py index 11c5f01cfb..088fab1d24 100644 --- a/tests/cli/snapshots/unions_typing_extension.py +++ b/tests/cli/snapshots/unions_typing_extension.py @@ -1,6 +1,7 @@ -import strawberry from typing_extensions import Annotated +import strawberry + # create a few types and then a union type diff --git a/tests/experimental/pydantic/test_conversion.py b/tests/experimental/pydantic/test_conversion.py index 75da6aee57..ffdbe6bcf5 100644 --- a/tests/experimental/pydantic/test_conversion.py +++ b/tests/experimental/pydantic/test_conversion.py @@ -3,10 +3,10 @@ import re import sys from enum import Enum -from typing import Any, Dict, List, NewType, Optional, Union, cast +from typing import Any, Dict, List, NewType, Optional, Union import pytest -from pydantic import BaseConfig, BaseModel, Field, ValidationError +from pydantic import BaseModel, Field, ValidationError import strawberry from strawberry.experimental.pydantic.exceptions import ( @@ -16,16 +16,16 @@ from strawberry.experimental.pydantic.utils import get_default_factory_for_field from strawberry.experimental.pydantic.v2_compat import ( IS_PYDANTIC_V2, - CompatModelField, PYDANTIC_MISSING_TYPE, + CompatModelField, ) from strawberry.type import StrawberryList, StrawberryOptional from strawberry.types.types import StrawberryObjectDefinition if IS_PYDANTIC_V2: - from pydantic.v1.fields import ModelField + pass else: - from pydantic.fields import ModelField + pass def test_can_use_type_standalone(): diff --git a/tests/experimental/pydantic/test_fields.py b/tests/experimental/pydantic/test_fields.py index 3eae755be2..33f386f8d9 100644 --- a/tests/experimental/pydantic/test_fields.py +++ b/tests/experimental/pydantic/test_fields.py @@ -10,7 +10,7 @@ from strawberry.experimental.pydantic.v2_compat import IS_PYDANTIC_V1 from strawberry.type import StrawberryOptional from strawberry.types.types import StrawberryObjectDefinition -from tests.experimental.pydantic.utils import needs_pydanticv2, needs_pydanticv1 +from tests.experimental.pydantic.utils import needs_pydanticv1, needs_pydanticv2 @needs_pydanticv1 diff --git a/tests/experimental/pydantic/utils.py b/tests/experimental/pydantic/utils.py index e99b37f0e3..e53458225c 100644 --- a/tests/experimental/pydantic/utils.py +++ b/tests/experimental/pydantic/utils.py @@ -3,4 +3,4 @@ from strawberry.experimental.pydantic.v2_compat import IS_PYDANTIC_V2 needs_pydanticv2 = pytest.mark.skipif(not IS_PYDANTIC_V2, reason="requires Pydantic v2") -needs_pydanticv1 = pytest.mark.skipif(IS_PYDANTIC_V2, reason="requires Pydantic v1") \ No newline at end of file +needs_pydanticv1 = pytest.mark.skipif(IS_PYDANTIC_V2, reason="requires Pydantic v1") diff --git a/tests/http/clients/base.py b/tests/http/clients/base.py index 840c4af4cf..da4afef762 100644 --- a/tests/http/clients/base.py +++ b/tests/http/clients/base.py @@ -156,7 +156,7 @@ def _build_multipart_file_map( files_map: Dict[str, List[str]] = {} for key, values in variables.items(): if isinstance(values, dict): - folder_key = list(values.keys())[0] + folder_key = next(iter(values.keys())) key += f".{folder_key}" # noqa: PLW2901 # the list of file is inside the folder keyword values = values[folder_key] # noqa: PLW2901 @@ -166,7 +166,7 @@ def _build_multipart_file_map( # copying `files` as when we map a file we must discard from the dict _kwargs = files.copy() for index, _ in enumerate(values): - k = list(_kwargs.keys())[0] + k = next(iter(_kwargs.keys())) _kwargs.pop(k) files_map.setdefault(k, []) files_map[k].append(f"variables.{key}.{index}") diff --git a/tests/test_dataloaders.py b/tests/test_dataloaders.py index b639cf029e..8b2b0cb570 100644 --- a/tests/test_dataloaders.py +++ b/tests/test_dataloaders.py @@ -363,7 +363,7 @@ async def idx(keys: List[int]) -> List[int]: async def test_cache_override(): class TestCache(AbstractCache[int, int]): def __init__(self): - self.cache: Dict[int, "Future[int]"] = {} + self.cache: Dict[int, Future[int]] = {} def get(self, key: int) -> Optional["Future[int]"]: return self.cache.get(key) From 1171abc3602c2cabc3acc446b4cb9e21e3a46fcc Mon Sep 17 00:00:00 2001 From: jameschua Date: Sat, 22 Jul 2023 15:59:23 -0700 Subject: [PATCH 09/32] Revert "ruff" This reverts commit dc0b9dd4f81606c1bd98a9ed169926d52160d1a0. --- strawberry/experimental/__init__.py | 1 + .../experimental/pydantic/conversion.py | 2 +- .../experimental/pydantic/error_type.py | 7 +++---- strawberry/experimental/pydantic/fields.py | 18 ++++++++-------- .../experimental/pydantic/object_type.py | 6 +----- strawberry/experimental/pydantic/utils.py | 10 ++++----- strawberry/experimental/pydantic/v2_compat.py | 21 ++++++++++++------- strawberry/ext/mypy_plugin.py | 4 ++-- strawberry/test/client.py | 4 ++-- tests/cli/snapshots/unions.py | 3 +-- tests/cli/snapshots/unions_py38.py | 3 +-- .../cli/snapshots/unions_typing_extension.py | 3 +-- .../experimental/pydantic/test_conversion.py | 10 ++++----- tests/experimental/pydantic/test_fields.py | 2 +- tests/experimental/pydantic/utils.py | 2 +- tests/http/clients/base.py | 4 ++-- tests/test_dataloaders.py | 2 +- 17 files changed, 49 insertions(+), 53 deletions(-) diff --git a/strawberry/experimental/__init__.py b/strawberry/experimental/__init__.py index 0dffcbb051..27fa5bbb0e 100644 --- a/strawberry/experimental/__init__.py +++ b/strawberry/experimental/__init__.py @@ -1,6 +1,7 @@ try: from . import pydantic except ImportError as e: + print("ImportError: ", e) pass else: __all__ = ["pydantic"] diff --git a/strawberry/experimental/pydantic/conversion.py b/strawberry/experimental/pydantic/conversion.py index c1f4f9dbaf..05e9544372 100644 --- a/strawberry/experimental/pydantic/conversion.py +++ b/strawberry/experimental/pydantic/conversion.py @@ -13,7 +13,7 @@ from strawberry.union import StrawberryUnion if TYPE_CHECKING: - from strawberry.type import StrawberryField, StrawberryType + from strawberry.type import StrawberryType def _convert_from_pydantic_to_strawberry_type( diff --git a/strawberry/experimental/pydantic/error_type.py b/strawberry/experimental/pydantic/error_type.py index 967885f1bc..06406ccab4 100644 --- a/strawberry/experimental/pydantic/error_type.py +++ b/strawberry/experimental/pydantic/error_type.py @@ -23,14 +23,13 @@ get_strawberry_type_from_model, normalize_type, ) -from strawberry.experimental.pydantic.v2_compat import ( - get_model_fields, - lenient_issubclass, -) +from strawberry.experimental.pydantic.v2_compat import lenient_issubclass, get_model_fields from strawberry.object_type import _process_type, _wrap_dataclass from strawberry.types.type_resolver import _get_fields from strawberry.utils.typing import get_list_annotation, is_list + + from .exceptions import MissingFieldsListError if TYPE_CHECKING: diff --git a/strawberry/experimental/pydantic/fields.py b/strawberry/experimental/pydantic/fields.py index 2cbf42f62c..b5b14e1008 100644 --- a/strawberry/experimental/pydantic/fields.py +++ b/strawberry/experimental/pydantic/fields.py @@ -1,28 +1,28 @@ import builtins +import types from decimal import Decimal from typing import Any, List, Optional, Type, Union from uuid import UUID import pydantic from pydantic import BaseModel - -from strawberry.experimental.pydantic.exceptions import ( - UnregisteredTypeException, - UnsupportedTypeError, -) from strawberry.experimental.pydantic.v2_compat import ( - IS_PYDANTIC_V2, + lenient_issubclass, get_args, get_origin, is_new_type, - lenient_issubclass, new_type_supertype, + IS_PYDANTIC_V2, +) +from strawberry.experimental.pydantic.exceptions import ( + UnregisteredTypeException, + UnsupportedTypeError, ) from strawberry.types.types import StrawberryObjectDefinition try: - from types import UnionType as TypingUnionType # type: ignore from typing import GenericAlias as TypingGenericAlias # type: ignore + from types import UnionType as TypingUnionType # type: ignore except ImportError: import sys @@ -82,7 +82,7 @@ } """TODO: -Most of these fields are not supported by pydantic V2 +Most of these fields are not supported by pydantic V2 """ FIELDS_MAP = ( { diff --git a/strawberry/experimental/pydantic/object_type.py b/strawberry/experimental/pydantic/object_type.py index b10e479286..247ce3c6c2 100644 --- a/strawberry/experimental/pydantic/object_type.py +++ b/strawberry/experimental/pydantic/object_type.py @@ -30,11 +30,7 @@ get_default_factory_for_field, get_private_fields, ) -from strawberry.experimental.pydantic.v2_compat import ( - IS_PYDANTIC_V2, - CompatModelField, - get_model_fields, -) +from strawberry.experimental.pydantic.v2_compat import CompatModelField, get_model_fields, IS_PYDANTIC_V2 from strawberry.field import StrawberryField from strawberry.object_type import _process_type, _wrap_dataclass from strawberry.types.type_resolver import _get_fields diff --git a/strawberry/experimental/pydantic/utils.py b/strawberry/experimental/pydantic/utils.py index 1453667680..382b31d587 100644 --- a/strawberry/experimental/pydantic/utils.py +++ b/strawberry/experimental/pydantic/utils.py @@ -14,17 +14,14 @@ cast, ) + from strawberry.experimental.pydantic.exceptions import ( AutoFieldsNotInBaseModelError, BothDefaultAndDefaultFactoryDefinedError, UnregisteredTypeException, ) -from strawberry.experimental.pydantic.v2_compat import ( - PYDANTIC_MISSING_TYPE, - CompatModelField, - get_model_fields, - smart_deepcopy, -) +from strawberry.experimental.pydantic.v2_compat import CompatModelField, smart_deepcopy, PYDANTIC_MISSING_TYPE, \ + get_model_fields from strawberry.private import is_private from strawberry.unset import UNSET from strawberry.utils.typing import ( @@ -36,6 +33,7 @@ if TYPE_CHECKING: from pydantic import BaseModel + from pydantic.fields import ModelField from pydantic.typing import NoArgAnyCallable diff --git a/strawberry/experimental/pydantic/v2_compat.py b/strawberry/experimental/pydantic/v2_compat.py index d887f8ec18..6560dcf974 100644 --- a/strawberry/experimental/pydantic/v2_compat.py +++ b/strawberry/experimental/pydantic/v2_compat.py @@ -1,15 +1,13 @@ import dataclasses from dataclasses import dataclass -from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, Type +from typing import Dict, Type, Any, Optional, Callable import pydantic from pydantic import BaseModel +from pydantic.v1.typing import NoArgAnyCallable from pydantic.version import VERSION as PYDANTIC_VERSION from pydantic_core import PydanticUndefined -if TYPE_CHECKING: - from pydantic.fields import FieldInfo - IS_PYDANTIC_V2: bool = PYDANTIC_VERSION.startswith("2.") IS_PYDANTIC_V1: bool = not IS_PYDANTIC_V2 @@ -28,12 +26,16 @@ class CompatModelField: if pydantic.VERSION[0] == "2": - - from pydantic._internal._utils import lenient_issubclass, smart_deepcopy + from pydantic._internal._utils import smart_deepcopy + from pydantic._internal._utils import lenient_issubclass + from typing_extensions import get_args, get_origin + from pydantic._internal._typing_extra import is_new_type + from pydantic.v1.fields import ModelField + from pydantic.fields import FieldInfo PYDANTIC_MISSING_TYPE = PydanticUndefined - def new_type_supertype(type_: Any) -> Any: + def new_type_supertype(type_): return type_.__supertype__ def get_model_fields(model: Type[BaseModel]) -> Dict[str, CompatModelField]: @@ -56,7 +58,10 @@ def get_model_fields(model: Type[BaseModel]) -> Dict[str, CompatModelField]: return new_fields else: - from pydantic.utils import lenient_issubclass, smart_deepcopy + from pydantic.utils import smart_deepcopy + from pydantic.utils import lenient_issubclass + from pydantic.typing import get_args, get_origin, is_new_type, new_type_supertype + from pydantic import ModelField PYDANTIC_MISSING_TYPE = dataclasses.MISSING diff --git a/strawberry/ext/mypy_plugin.py b/strawberry/ext/mypy_plugin.py index 82095cf4d7..1da6f7f44e 100644 --- a/strawberry/ext/mypy_plugin.py +++ b/strawberry/ext/mypy_plugin.py @@ -409,9 +409,9 @@ def strawberry_pydantic_class_callback(ctx: ClassDefContext) -> None: pydantic_fields: Set[PydanticModelField] = set() try: - for data in model_type.type.metadata[PYDANTIC_METADATA_KEY][ + for _name, data in model_type.type.metadata[PYDANTIC_METADATA_KEY][ "fields" - ].values(): + ].items(): field = PydanticModelField.deserialize(ctx.cls.info, data) pydantic_fields.add(field) except KeyError: diff --git a/strawberry/test/client.py b/strawberry/test/client.py index 4ef79354e4..093f46abda 100644 --- a/strawberry/test/client.py +++ b/strawberry/test/client.py @@ -136,7 +136,7 @@ def _build_multipart_file_map( # In case of folders the variables will look like # `{"folder": {"files": ...]}}` if isinstance(values, dict): - folder_key = next(iter(values.keys())) + folder_key = list(values.keys())[0] reference += f".{folder_key}" # the list of file is inside the folder keyword variable_values = variable_values[folder_key] @@ -146,7 +146,7 @@ def _build_multipart_file_map( # copying `files` as when we map a file we must discard from the dict _kwargs = files.copy() for index, _ in enumerate(variable_values): - k = next(iter(_kwargs.keys())) + k = list(_kwargs.keys())[0] _kwargs.pop(k) map.setdefault(k, []) map[k].append(f"variables.{reference}.{index}") diff --git a/tests/cli/snapshots/unions.py b/tests/cli/snapshots/unions.py index d725469ce5..2f03e0bb4b 100644 --- a/tests/cli/snapshots/unions.py +++ b/tests/cli/snapshots/unions.py @@ -1,6 +1,5 @@ -from typing import Annotated - import strawberry +from typing import Annotated # create a few types and then a union type diff --git a/tests/cli/snapshots/unions_py38.py b/tests/cli/snapshots/unions_py38.py index b7ead3da65..4fd0143c69 100644 --- a/tests/cli/snapshots/unions_py38.py +++ b/tests/cli/snapshots/unions_py38.py @@ -1,6 +1,5 @@ -from typing import Annotated, Union - import strawberry +from typing import Annotated, Union # create a few types and then a union type diff --git a/tests/cli/snapshots/unions_typing_extension.py b/tests/cli/snapshots/unions_typing_extension.py index 088fab1d24..11c5f01cfb 100644 --- a/tests/cli/snapshots/unions_typing_extension.py +++ b/tests/cli/snapshots/unions_typing_extension.py @@ -1,6 +1,5 @@ -from typing_extensions import Annotated - import strawberry +from typing_extensions import Annotated # create a few types and then a union type diff --git a/tests/experimental/pydantic/test_conversion.py b/tests/experimental/pydantic/test_conversion.py index ffdbe6bcf5..75da6aee57 100644 --- a/tests/experimental/pydantic/test_conversion.py +++ b/tests/experimental/pydantic/test_conversion.py @@ -3,10 +3,10 @@ import re import sys from enum import Enum -from typing import Any, Dict, List, NewType, Optional, Union +from typing import Any, Dict, List, NewType, Optional, Union, cast import pytest -from pydantic import BaseModel, Field, ValidationError +from pydantic import BaseConfig, BaseModel, Field, ValidationError import strawberry from strawberry.experimental.pydantic.exceptions import ( @@ -16,16 +16,16 @@ from strawberry.experimental.pydantic.utils import get_default_factory_for_field from strawberry.experimental.pydantic.v2_compat import ( IS_PYDANTIC_V2, - PYDANTIC_MISSING_TYPE, CompatModelField, + PYDANTIC_MISSING_TYPE, ) from strawberry.type import StrawberryList, StrawberryOptional from strawberry.types.types import StrawberryObjectDefinition if IS_PYDANTIC_V2: - pass + from pydantic.v1.fields import ModelField else: - pass + from pydantic.fields import ModelField def test_can_use_type_standalone(): diff --git a/tests/experimental/pydantic/test_fields.py b/tests/experimental/pydantic/test_fields.py index 33f386f8d9..3eae755be2 100644 --- a/tests/experimental/pydantic/test_fields.py +++ b/tests/experimental/pydantic/test_fields.py @@ -10,7 +10,7 @@ from strawberry.experimental.pydantic.v2_compat import IS_PYDANTIC_V1 from strawberry.type import StrawberryOptional from strawberry.types.types import StrawberryObjectDefinition -from tests.experimental.pydantic.utils import needs_pydanticv1, needs_pydanticv2 +from tests.experimental.pydantic.utils import needs_pydanticv2, needs_pydanticv1 @needs_pydanticv1 diff --git a/tests/experimental/pydantic/utils.py b/tests/experimental/pydantic/utils.py index e53458225c..e99b37f0e3 100644 --- a/tests/experimental/pydantic/utils.py +++ b/tests/experimental/pydantic/utils.py @@ -3,4 +3,4 @@ from strawberry.experimental.pydantic.v2_compat import IS_PYDANTIC_V2 needs_pydanticv2 = pytest.mark.skipif(not IS_PYDANTIC_V2, reason="requires Pydantic v2") -needs_pydanticv1 = pytest.mark.skipif(IS_PYDANTIC_V2, reason="requires Pydantic v1") +needs_pydanticv1 = pytest.mark.skipif(IS_PYDANTIC_V2, reason="requires Pydantic v1") \ No newline at end of file diff --git a/tests/http/clients/base.py b/tests/http/clients/base.py index da4afef762..840c4af4cf 100644 --- a/tests/http/clients/base.py +++ b/tests/http/clients/base.py @@ -156,7 +156,7 @@ def _build_multipart_file_map( files_map: Dict[str, List[str]] = {} for key, values in variables.items(): if isinstance(values, dict): - folder_key = next(iter(values.keys())) + folder_key = list(values.keys())[0] key += f".{folder_key}" # noqa: PLW2901 # the list of file is inside the folder keyword values = values[folder_key] # noqa: PLW2901 @@ -166,7 +166,7 @@ def _build_multipart_file_map( # copying `files` as when we map a file we must discard from the dict _kwargs = files.copy() for index, _ in enumerate(values): - k = next(iter(_kwargs.keys())) + k = list(_kwargs.keys())[0] _kwargs.pop(k) files_map.setdefault(k, []) files_map[k].append(f"variables.{key}.{index}") diff --git a/tests/test_dataloaders.py b/tests/test_dataloaders.py index 8b2b0cb570..b639cf029e 100644 --- a/tests/test_dataloaders.py +++ b/tests/test_dataloaders.py @@ -363,7 +363,7 @@ async def idx(keys: List[int]) -> List[int]: async def test_cache_override(): class TestCache(AbstractCache[int, int]): def __init__(self): - self.cache: Dict[int, Future[int]] = {} + self.cache: Dict[int, "Future[int]"] = {} def get(self, key: int) -> Optional["Future[int]"]: return self.cache.get(key) From 43dcf1d83194060901dc03856f444bb8827e1a34 Mon Sep 17 00:00:00 2001 From: jameschua Date: Sat, 22 Jul 2023 16:05:31 -0700 Subject: [PATCH 10/32] make most of mypy happy --- .../experimental/pydantic/conversion.py | 1 + .../experimental/pydantic/error_type.py | 7 ++----- strawberry/experimental/pydantic/fields.py | 2 +- strawberry/experimental/pydantic/utils.py | 3 +-- strawberry/experimental/pydantic/v2_compat.py | 20 +++++++++++++------ 5 files changed, 19 insertions(+), 14 deletions(-) diff --git a/strawberry/experimental/pydantic/conversion.py b/strawberry/experimental/pydantic/conversion.py index 05e9544372..727c371eb1 100644 --- a/strawberry/experimental/pydantic/conversion.py +++ b/strawberry/experimental/pydantic/conversion.py @@ -14,6 +14,7 @@ if TYPE_CHECKING: from strawberry.type import StrawberryType + from strawberry.field import StrawberryField def _convert_from_pydantic_to_strawberry_type( diff --git a/strawberry/experimental/pydantic/error_type.py b/strawberry/experimental/pydantic/error_type.py index 06406ccab4..b71121fd67 100644 --- a/strawberry/experimental/pydantic/error_type.py +++ b/strawberry/experimental/pydantic/error_type.py @@ -23,7 +23,7 @@ get_strawberry_type_from_model, normalize_type, ) -from strawberry.experimental.pydantic.v2_compat import lenient_issubclass, get_model_fields +from strawberry.experimental.pydantic.v2_compat import lenient_issubclass, get_model_fields, CompatModelField from strawberry.object_type import _process_type, _wrap_dataclass from strawberry.types.type_resolver import _get_fields from strawberry.utils.typing import get_list_annotation, is_list @@ -32,11 +32,8 @@ from .exceptions import MissingFieldsListError -if TYPE_CHECKING: - from pydantic.fields import ModelField - -def get_type_for_field(field: ModelField) -> Union[Any, Type[None], Type[List]]: +def get_type_for_field(field: CompatModelField) -> Union[Any, Type[None], Type[List]]: type_ = field.outer_type_ type_ = normalize_type(type_) return field_type_to_type(type_) diff --git a/strawberry/experimental/pydantic/fields.py b/strawberry/experimental/pydantic/fields.py index b5b14e1008..de13ae9da6 100644 --- a/strawberry/experimental/pydantic/fields.py +++ b/strawberry/experimental/pydantic/fields.py @@ -22,7 +22,7 @@ try: from typing import GenericAlias as TypingGenericAlias # type: ignore - from types import UnionType as TypingUnionType # type: ignore + from types import UnionType as TypingUnionType except ImportError: import sys diff --git a/strawberry/experimental/pydantic/utils.py b/strawberry/experimental/pydantic/utils.py index 382b31d587..f47ca9ea70 100644 --- a/strawberry/experimental/pydantic/utils.py +++ b/strawberry/experimental/pydantic/utils.py @@ -33,7 +33,6 @@ if TYPE_CHECKING: from pydantic import BaseModel - from pydantic.fields import ModelField from pydantic.typing import NoArgAnyCallable @@ -72,7 +71,7 @@ def to_tuple(self) -> Tuple[str, Type, dataclasses.Field]: def get_default_factory_for_field( field: CompatModelField, -) -> Union[NoArgAnyCallable, PYDANTIC_MISSING_TYPE]: +) -> Union[NoArgAnyCallable, dataclasses._MISSING_TYPE]: """ Gets the default factory for a pydantic field. diff --git a/strawberry/experimental/pydantic/v2_compat.py b/strawberry/experimental/pydantic/v2_compat.py index 6560dcf974..2097a586a2 100644 --- a/strawberry/experimental/pydantic/v2_compat.py +++ b/strawberry/experimental/pydantic/v2_compat.py @@ -4,7 +4,6 @@ import pydantic from pydantic import BaseModel -from pydantic.v1.typing import NoArgAnyCallable from pydantic.version import VERSION as PYDANTIC_VERSION from pydantic_core import PydanticUndefined @@ -19,10 +18,10 @@ class CompatModelField: default: Any default_factory: Optional[Callable[[], Any]] required: bool - alias: str + alias: Optional[str] allow_none: bool has_alias: bool - description: str + description: Optional[str] if pydantic.VERSION[0] == "2": @@ -33,7 +32,7 @@ class CompatModelField: from pydantic.v1.fields import ModelField from pydantic.fields import FieldInfo - PYDANTIC_MISSING_TYPE = PydanticUndefined + PYDANTIC_MISSING_TYPE: Type = PydanticUndefined def new_type_supertype(type_): return type_.__supertype__ @@ -58,7 +57,7 @@ def get_model_fields(model: Type[BaseModel]) -> Dict[str, CompatModelField]: return new_fields else: - from pydantic.utils import smart_deepcopy + from pydantic.utils import smart_deepcopy # type: ignore from pydantic.utils import lenient_issubclass from pydantic.typing import get_args, get_origin, is_new_type, new_type_supertype from pydantic import ModelField @@ -83,4 +82,13 @@ def get_model_fields(model: Type[BaseModel]) -> Dict[str, CompatModelField]: return new_fields -__all__ = ["smart_deepcopy", "lenient_issubclass"] +__all__ = [ + "smart_deepcopy", + "lenient_issubclass", + "get_args", + "get_origin", + "is_new_type", + "new_type_supertype", + "get_model_fields", + "PYDANTIC_MISSING_TYPE", +] From 969112bae26507cd6c177d9957f9d6781bfdd2da Mon Sep 17 00:00:00 2001 From: jameschua Date: Sat, 22 Jul 2023 16:08:38 -0700 Subject: [PATCH 11/32] make linters and mypy happy --- strawberry/experimental/__init__.py | 1 - .../experimental/pydantic/conversion.py | 2 +- .../experimental/pydantic/error_type.py | 9 ++--- strawberry/experimental/pydantic/fields.py | 18 +++++----- .../experimental/pydantic/object_type.py | 6 +++- strawberry/experimental/pydantic/utils.py | 9 +++-- strawberry/experimental/pydantic/v2_compat.py | 33 +++++++++++-------- strawberry/ext/mypy_plugin.py | 4 +-- strawberry/test/client.py | 4 +-- tests/cli/snapshots/unions.py | 3 +- tests/cli/snapshots/unions_py38.py | 3 +- .../cli/snapshots/unions_typing_extension.py | 3 +- .../experimental/pydantic/test_conversion.py | 10 +++--- tests/experimental/pydantic/test_fields.py | 2 +- tests/experimental/pydantic/utils.py | 2 +- tests/http/clients/base.py | 4 +-- tests/test_dataloaders.py | 2 +- 17 files changed, 66 insertions(+), 49 deletions(-) diff --git a/strawberry/experimental/__init__.py b/strawberry/experimental/__init__.py index 27fa5bbb0e..0dffcbb051 100644 --- a/strawberry/experimental/__init__.py +++ b/strawberry/experimental/__init__.py @@ -1,7 +1,6 @@ try: from . import pydantic except ImportError as e: - print("ImportError: ", e) pass else: __all__ = ["pydantic"] diff --git a/strawberry/experimental/pydantic/conversion.py b/strawberry/experimental/pydantic/conversion.py index 727c371eb1..bb2af2c8d3 100644 --- a/strawberry/experimental/pydantic/conversion.py +++ b/strawberry/experimental/pydantic/conversion.py @@ -13,8 +13,8 @@ from strawberry.union import StrawberryUnion if TYPE_CHECKING: - from strawberry.type import StrawberryType from strawberry.field import StrawberryField + from strawberry.type import StrawberryType def _convert_from_pydantic_to_strawberry_type( diff --git a/strawberry/experimental/pydantic/error_type.py b/strawberry/experimental/pydantic/error_type.py index b71121fd67..9bef546e0c 100644 --- a/strawberry/experimental/pydantic/error_type.py +++ b/strawberry/experimental/pydantic/error_type.py @@ -3,7 +3,6 @@ import dataclasses import warnings from typing import ( - TYPE_CHECKING, Any, Callable, List, @@ -23,13 +22,15 @@ get_strawberry_type_from_model, normalize_type, ) -from strawberry.experimental.pydantic.v2_compat import lenient_issubclass, get_model_fields, CompatModelField +from strawberry.experimental.pydantic.v2_compat import ( + CompatModelField, + get_model_fields, + lenient_issubclass, +) from strawberry.object_type import _process_type, _wrap_dataclass from strawberry.types.type_resolver import _get_fields from strawberry.utils.typing import get_list_annotation, is_list - - from .exceptions import MissingFieldsListError diff --git a/strawberry/experimental/pydantic/fields.py b/strawberry/experimental/pydantic/fields.py index de13ae9da6..dc54bdf8a6 100644 --- a/strawberry/experimental/pydantic/fields.py +++ b/strawberry/experimental/pydantic/fields.py @@ -1,28 +1,28 @@ import builtins -import types from decimal import Decimal from typing import Any, List, Optional, Type, Union from uuid import UUID import pydantic from pydantic import BaseModel + +from strawberry.experimental.pydantic.exceptions import ( + UnregisteredTypeException, + UnsupportedTypeError, +) from strawberry.experimental.pydantic.v2_compat import ( - lenient_issubclass, + IS_PYDANTIC_V2, get_args, get_origin, is_new_type, + lenient_issubclass, new_type_supertype, - IS_PYDANTIC_V2, -) -from strawberry.experimental.pydantic.exceptions import ( - UnregisteredTypeException, - UnsupportedTypeError, ) from strawberry.types.types import StrawberryObjectDefinition try: - from typing import GenericAlias as TypingGenericAlias # type: ignore from types import UnionType as TypingUnionType + from typing import GenericAlias as TypingGenericAlias # type: ignore except ImportError: import sys @@ -82,7 +82,7 @@ } """TODO: -Most of these fields are not supported by pydantic V2 +Most of these fields are not supported by pydantic V2 """ FIELDS_MAP = ( { diff --git a/strawberry/experimental/pydantic/object_type.py b/strawberry/experimental/pydantic/object_type.py index 247ce3c6c2..b10e479286 100644 --- a/strawberry/experimental/pydantic/object_type.py +++ b/strawberry/experimental/pydantic/object_type.py @@ -30,7 +30,11 @@ get_default_factory_for_field, get_private_fields, ) -from strawberry.experimental.pydantic.v2_compat import CompatModelField, get_model_fields, IS_PYDANTIC_V2 +from strawberry.experimental.pydantic.v2_compat import ( + IS_PYDANTIC_V2, + CompatModelField, + get_model_fields, +) from strawberry.field import StrawberryField from strawberry.object_type import _process_type, _wrap_dataclass from strawberry.types.type_resolver import _get_fields diff --git a/strawberry/experimental/pydantic/utils.py b/strawberry/experimental/pydantic/utils.py index f47ca9ea70..1ae59e9965 100644 --- a/strawberry/experimental/pydantic/utils.py +++ b/strawberry/experimental/pydantic/utils.py @@ -14,14 +14,17 @@ cast, ) - from strawberry.experimental.pydantic.exceptions import ( AutoFieldsNotInBaseModelError, BothDefaultAndDefaultFactoryDefinedError, UnregisteredTypeException, ) -from strawberry.experimental.pydantic.v2_compat import CompatModelField, smart_deepcopy, PYDANTIC_MISSING_TYPE, \ - get_model_fields +from strawberry.experimental.pydantic.v2_compat import ( + PYDANTIC_MISSING_TYPE, + CompatModelField, + get_model_fields, + smart_deepcopy, +) from strawberry.private import is_private from strawberry.unset import UNSET from strawberry.utils.typing import ( diff --git a/strawberry/experimental/pydantic/v2_compat.py b/strawberry/experimental/pydantic/v2_compat.py index 2097a586a2..9a2a7d70fa 100644 --- a/strawberry/experimental/pydantic/v2_compat.py +++ b/strawberry/experimental/pydantic/v2_compat.py @@ -1,12 +1,15 @@ import dataclasses from dataclasses import dataclass -from typing import Dict, Type, Any, Optional, Callable +from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, Type import pydantic from pydantic import BaseModel from pydantic.version import VERSION as PYDANTIC_VERSION from pydantic_core import PydanticUndefined +if TYPE_CHECKING: + from pydantic.fields import FieldInfo + IS_PYDANTIC_V2: bool = PYDANTIC_VERSION.startswith("2.") IS_PYDANTIC_V1: bool = not IS_PYDANTIC_V2 @@ -25,16 +28,14 @@ class CompatModelField: if pydantic.VERSION[0] == "2": - from pydantic._internal._utils import smart_deepcopy - from pydantic._internal._utils import lenient_issubclass from typing_extensions import get_args, get_origin + from pydantic._internal._typing_extra import is_new_type - from pydantic.v1.fields import ModelField - from pydantic.fields import FieldInfo + from pydantic._internal._utils import lenient_issubclass, smart_deepcopy - PYDANTIC_MISSING_TYPE: Type = PydanticUndefined + PYDANTIC_MISSING_TYPE = PydanticUndefined - def new_type_supertype(type_): + def new_type_supertype(type_: Any) -> Any: return type_.__supertype__ def get_model_fields(model: Type[BaseModel]) -> Dict[str, CompatModelField]: @@ -57,17 +58,23 @@ def get_model_fields(model: Type[BaseModel]) -> Dict[str, CompatModelField]: return new_fields else: - from pydantic.utils import smart_deepcopy # type: ignore - from pydantic.utils import lenient_issubclass - from pydantic.typing import get_args, get_origin, is_new_type, new_type_supertype - from pydantic import ModelField + from pydantic.typing import ( # type: ignore[no-redef] + get_args, + get_origin, + is_new_type, + new_type_supertype, + ) + from pydantic.utils import ( + lenient_issubclass, # type: ignore[no-redef] + smart_deepcopy, # type: ignore[no-redef] + ) - PYDANTIC_MISSING_TYPE = dataclasses.MISSING + PYDANTIC_MISSING_TYPE = dataclasses.MISSING # type: ignore[assignment] def get_model_fields(model: Type[BaseModel]) -> Dict[str, CompatModelField]: new_fields = {} # Convert it into CompatModelField - for name, field in model.__fields__.items(): + for name, field in model.__fields__.items(): # type: ignore[attr-defined] new_fields[name] = CompatModelField( name=name, outer_type_=field.type_, diff --git a/strawberry/ext/mypy_plugin.py b/strawberry/ext/mypy_plugin.py index 1da6f7f44e..82095cf4d7 100644 --- a/strawberry/ext/mypy_plugin.py +++ b/strawberry/ext/mypy_plugin.py @@ -409,9 +409,9 @@ def strawberry_pydantic_class_callback(ctx: ClassDefContext) -> None: pydantic_fields: Set[PydanticModelField] = set() try: - for _name, data in model_type.type.metadata[PYDANTIC_METADATA_KEY][ + for data in model_type.type.metadata[PYDANTIC_METADATA_KEY][ "fields" - ].items(): + ].values(): field = PydanticModelField.deserialize(ctx.cls.info, data) pydantic_fields.add(field) except KeyError: diff --git a/strawberry/test/client.py b/strawberry/test/client.py index 093f46abda..4ef79354e4 100644 --- a/strawberry/test/client.py +++ b/strawberry/test/client.py @@ -136,7 +136,7 @@ def _build_multipart_file_map( # In case of folders the variables will look like # `{"folder": {"files": ...]}}` if isinstance(values, dict): - folder_key = list(values.keys())[0] + folder_key = next(iter(values.keys())) reference += f".{folder_key}" # the list of file is inside the folder keyword variable_values = variable_values[folder_key] @@ -146,7 +146,7 @@ def _build_multipart_file_map( # copying `files` as when we map a file we must discard from the dict _kwargs = files.copy() for index, _ in enumerate(variable_values): - k = list(_kwargs.keys())[0] + k = next(iter(_kwargs.keys())) _kwargs.pop(k) map.setdefault(k, []) map[k].append(f"variables.{reference}.{index}") diff --git a/tests/cli/snapshots/unions.py b/tests/cli/snapshots/unions.py index 2f03e0bb4b..d725469ce5 100644 --- a/tests/cli/snapshots/unions.py +++ b/tests/cli/snapshots/unions.py @@ -1,6 +1,7 @@ -import strawberry from typing import Annotated +import strawberry + # create a few types and then a union type diff --git a/tests/cli/snapshots/unions_py38.py b/tests/cli/snapshots/unions_py38.py index 4fd0143c69..b7ead3da65 100644 --- a/tests/cli/snapshots/unions_py38.py +++ b/tests/cli/snapshots/unions_py38.py @@ -1,6 +1,7 @@ -import strawberry from typing import Annotated, Union +import strawberry + # create a few types and then a union type diff --git a/tests/cli/snapshots/unions_typing_extension.py b/tests/cli/snapshots/unions_typing_extension.py index 11c5f01cfb..088fab1d24 100644 --- a/tests/cli/snapshots/unions_typing_extension.py +++ b/tests/cli/snapshots/unions_typing_extension.py @@ -1,6 +1,7 @@ -import strawberry from typing_extensions import Annotated +import strawberry + # create a few types and then a union type diff --git a/tests/experimental/pydantic/test_conversion.py b/tests/experimental/pydantic/test_conversion.py index 75da6aee57..ffdbe6bcf5 100644 --- a/tests/experimental/pydantic/test_conversion.py +++ b/tests/experimental/pydantic/test_conversion.py @@ -3,10 +3,10 @@ import re import sys from enum import Enum -from typing import Any, Dict, List, NewType, Optional, Union, cast +from typing import Any, Dict, List, NewType, Optional, Union import pytest -from pydantic import BaseConfig, BaseModel, Field, ValidationError +from pydantic import BaseModel, Field, ValidationError import strawberry from strawberry.experimental.pydantic.exceptions import ( @@ -16,16 +16,16 @@ from strawberry.experimental.pydantic.utils import get_default_factory_for_field from strawberry.experimental.pydantic.v2_compat import ( IS_PYDANTIC_V2, - CompatModelField, PYDANTIC_MISSING_TYPE, + CompatModelField, ) from strawberry.type import StrawberryList, StrawberryOptional from strawberry.types.types import StrawberryObjectDefinition if IS_PYDANTIC_V2: - from pydantic.v1.fields import ModelField + pass else: - from pydantic.fields import ModelField + pass def test_can_use_type_standalone(): diff --git a/tests/experimental/pydantic/test_fields.py b/tests/experimental/pydantic/test_fields.py index 3eae755be2..33f386f8d9 100644 --- a/tests/experimental/pydantic/test_fields.py +++ b/tests/experimental/pydantic/test_fields.py @@ -10,7 +10,7 @@ from strawberry.experimental.pydantic.v2_compat import IS_PYDANTIC_V1 from strawberry.type import StrawberryOptional from strawberry.types.types import StrawberryObjectDefinition -from tests.experimental.pydantic.utils import needs_pydanticv2, needs_pydanticv1 +from tests.experimental.pydantic.utils import needs_pydanticv1, needs_pydanticv2 @needs_pydanticv1 diff --git a/tests/experimental/pydantic/utils.py b/tests/experimental/pydantic/utils.py index e99b37f0e3..e53458225c 100644 --- a/tests/experimental/pydantic/utils.py +++ b/tests/experimental/pydantic/utils.py @@ -3,4 +3,4 @@ from strawberry.experimental.pydantic.v2_compat import IS_PYDANTIC_V2 needs_pydanticv2 = pytest.mark.skipif(not IS_PYDANTIC_V2, reason="requires Pydantic v2") -needs_pydanticv1 = pytest.mark.skipif(IS_PYDANTIC_V2, reason="requires Pydantic v1") \ No newline at end of file +needs_pydanticv1 = pytest.mark.skipif(IS_PYDANTIC_V2, reason="requires Pydantic v1") diff --git a/tests/http/clients/base.py b/tests/http/clients/base.py index 840c4af4cf..da4afef762 100644 --- a/tests/http/clients/base.py +++ b/tests/http/clients/base.py @@ -156,7 +156,7 @@ def _build_multipart_file_map( files_map: Dict[str, List[str]] = {} for key, values in variables.items(): if isinstance(values, dict): - folder_key = list(values.keys())[0] + folder_key = next(iter(values.keys())) key += f".{folder_key}" # noqa: PLW2901 # the list of file is inside the folder keyword values = values[folder_key] # noqa: PLW2901 @@ -166,7 +166,7 @@ def _build_multipart_file_map( # copying `files` as when we map a file we must discard from the dict _kwargs = files.copy() for index, _ in enumerate(values): - k = list(_kwargs.keys())[0] + k = next(iter(_kwargs.keys())) _kwargs.pop(k) files_map.setdefault(k, []) files_map[k].append(f"variables.{key}.{index}") diff --git a/tests/test_dataloaders.py b/tests/test_dataloaders.py index b639cf029e..8b2b0cb570 100644 --- a/tests/test_dataloaders.py +++ b/tests/test_dataloaders.py @@ -363,7 +363,7 @@ async def idx(keys: List[int]) -> List[int]: async def test_cache_override(): class TestCache(AbstractCache[int, int]): def __init__(self): - self.cache: Dict[int, "Future[int]"] = {} + self.cache: Dict[int, Future[int]] = {} def get(self, key: int) -> Optional["Future[int]"]: return self.cache.get(key) From 107ea3cd47ee49226252b5502a03d332b47b2e54 Mon Sep 17 00:00:00 2001 From: jameschua Date: Sat, 22 Jul 2023 16:12:23 -0700 Subject: [PATCH 12/32] fix pydantic v1 import --- noxfile.py | 2 +- strawberry/experimental/pydantic/v2_compat.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/noxfile.py b/noxfile.py index e2b4f64c4f..136f023c7b 100644 --- a/noxfile.py +++ b/noxfile.py @@ -106,7 +106,7 @@ def tests_integrations(session: Session, integration: str) -> None: @session(python=["3.11"], name="Pydantic tests", tags=["tests"]) # TODO: add pydantic 2.0 here :) -@nox.parametrize("pydantic", ["1.10"]) +@nox.parametrize("pydantic", ["1.10", "2.0.3"]) def test_pydantic(session: Session, pydantic: str) -> None: session.run_always("poetry", "install", external=True) diff --git a/strawberry/experimental/pydantic/v2_compat.py b/strawberry/experimental/pydantic/v2_compat.py index 9a2a7d70fa..5c105f7f1d 100644 --- a/strawberry/experimental/pydantic/v2_compat.py +++ b/strawberry/experimental/pydantic/v2_compat.py @@ -5,7 +5,6 @@ import pydantic from pydantic import BaseModel from pydantic.version import VERSION as PYDANTIC_VERSION -from pydantic_core import PydanticUndefined if TYPE_CHECKING: from pydantic.fields import FieldInfo @@ -32,6 +31,7 @@ class CompatModelField: from pydantic._internal._typing_extra import is_new_type from pydantic._internal._utils import lenient_issubclass, smart_deepcopy + from pydantic_core import PydanticUndefined PYDANTIC_MISSING_TYPE = PydanticUndefined From 612a30c961c711c59d742347ad16d3d6dae710c0 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 22 Jul 2023 23:12:50 +0000 Subject: [PATCH 13/32] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- strawberry/experimental/pydantic/error_type.py | 16 +++++++--------- strawberry/experimental/pydantic/object_type.py | 1 - strawberry/experimental/pydantic/v2_compat.py | 4 ++-- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/strawberry/experimental/pydantic/error_type.py b/strawberry/experimental/pydantic/error_type.py index 9bef546e0c..6c46d4e588 100644 --- a/strawberry/experimental/pydantic/error_type.py +++ b/strawberry/experimental/pydantic/error_type.py @@ -40,8 +40,6 @@ def get_type_for_field(field: CompatModelField) -> Union[Any, Type[None], Type[L return field_type_to_type(type_) - - def field_type_to_type(type_: Type) -> Union[Any, List[Any], None]: error_class: Any = str strawberry_type: Any = error_class @@ -65,13 +63,13 @@ def field_type_to_type(type_: Type) -> Union[Any, List[Any], None]: def error_type( - model: Type[BaseModel], - *, - fields: Optional[List[str]] = None, - name: Optional[str] = None, - description: Optional[str] = None, - directives: Optional[Sequence[object]] = (), - all_fields: bool = False, + model: Type[BaseModel], + *, + fields: Optional[List[str]] = None, + name: Optional[str] = None, + description: Optional[str] = None, + directives: Optional[Sequence[object]] = (), + all_fields: bool = False, ) -> Callable[..., Type]: def wrap(cls: Type) -> Type: model_fields = get_model_fields(model) diff --git a/strawberry/experimental/pydantic/object_type.py b/strawberry/experimental/pydantic/object_type.py index b10e479286..b3da183c69 100644 --- a/strawberry/experimental/pydantic/object_type.py +++ b/strawberry/experimental/pydantic/object_type.py @@ -44,7 +44,6 @@ from graphql import GraphQLResolveInfo - def get_type_for_field(field: CompatModelField, is_input: bool): # noqa: ANN201 outer_type = field.outer_type_ replaced_type = replace_types_recursively(outer_type, is_input) diff --git a/strawberry/experimental/pydantic/v2_compat.py b/strawberry/experimental/pydantic/v2_compat.py index 5c105f7f1d..e935372ba5 100644 --- a/strawberry/experimental/pydantic/v2_compat.py +++ b/strawberry/experimental/pydantic/v2_compat.py @@ -69,12 +69,12 @@ def get_model_fields(model: Type[BaseModel]) -> Dict[str, CompatModelField]: smart_deepcopy, # type: ignore[no-redef] ) - PYDANTIC_MISSING_TYPE = dataclasses.MISSING # type: ignore[assignment] + PYDANTIC_MISSING_TYPE = dataclasses.MISSING # type: ignore[assignment] def get_model_fields(model: Type[BaseModel]) -> Dict[str, CompatModelField]: new_fields = {} # Convert it into CompatModelField - for name, field in model.__fields__.items(): # type: ignore[attr-defined] + for name, field in model.__fields__.items(): # type: ignore[attr-defined] new_fields[name] = CompatModelField( name=name, outer_type_=field.type_, From 50d71fb0c369eabfbe1034da539c63c0d2c2aa9f Mon Sep 17 00:00:00 2001 From: jameschua Date: Sat, 22 Jul 2023 16:16:30 -0700 Subject: [PATCH 14/32] remove extra ruff --- pyproject.toml | 2 -- strawberry/experimental/__init__.py | 2 +- strawberry/ext/mypy_plugin.py | 4 ++-- strawberry/test/client.py | 4 ++-- tests/cli/snapshots/unions.py | 3 +-- tests/cli/snapshots/unions_typing_extension.py | 3 +-- 6 files changed, 7 insertions(+), 11 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 801bbea7bb..f35e3dfe58 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -167,8 +167,6 @@ markers = [ "sanic", "starlette", "starlite", - "skip_on_", - "pydantic_v1" ] asyncio_mode = "auto" filterwarnings = [ diff --git a/strawberry/experimental/__init__.py b/strawberry/experimental/__init__.py index 0dffcbb051..6386ad81d7 100644 --- a/strawberry/experimental/__init__.py +++ b/strawberry/experimental/__init__.py @@ -1,6 +1,6 @@ try: from . import pydantic -except ImportError as e: +except ImportError: pass else: __all__ = ["pydantic"] diff --git a/strawberry/ext/mypy_plugin.py b/strawberry/ext/mypy_plugin.py index 82095cf4d7..1da6f7f44e 100644 --- a/strawberry/ext/mypy_plugin.py +++ b/strawberry/ext/mypy_plugin.py @@ -409,9 +409,9 @@ def strawberry_pydantic_class_callback(ctx: ClassDefContext) -> None: pydantic_fields: Set[PydanticModelField] = set() try: - for data in model_type.type.metadata[PYDANTIC_METADATA_KEY][ + for _name, data in model_type.type.metadata[PYDANTIC_METADATA_KEY][ "fields" - ].values(): + ].items(): field = PydanticModelField.deserialize(ctx.cls.info, data) pydantic_fields.add(field) except KeyError: diff --git a/strawberry/test/client.py b/strawberry/test/client.py index 4ef79354e4..093f46abda 100644 --- a/strawberry/test/client.py +++ b/strawberry/test/client.py @@ -136,7 +136,7 @@ def _build_multipart_file_map( # In case of folders the variables will look like # `{"folder": {"files": ...]}}` if isinstance(values, dict): - folder_key = next(iter(values.keys())) + folder_key = list(values.keys())[0] reference += f".{folder_key}" # the list of file is inside the folder keyword variable_values = variable_values[folder_key] @@ -146,7 +146,7 @@ def _build_multipart_file_map( # copying `files` as when we map a file we must discard from the dict _kwargs = files.copy() for index, _ in enumerate(variable_values): - k = next(iter(_kwargs.keys())) + k = list(_kwargs.keys())[0] _kwargs.pop(k) map.setdefault(k, []) map[k].append(f"variables.{reference}.{index}") diff --git a/tests/cli/snapshots/unions.py b/tests/cli/snapshots/unions.py index d725469ce5..2f03e0bb4b 100644 --- a/tests/cli/snapshots/unions.py +++ b/tests/cli/snapshots/unions.py @@ -1,6 +1,5 @@ -from typing import Annotated - import strawberry +from typing import Annotated # create a few types and then a union type diff --git a/tests/cli/snapshots/unions_typing_extension.py b/tests/cli/snapshots/unions_typing_extension.py index 088fab1d24..11c5f01cfb 100644 --- a/tests/cli/snapshots/unions_typing_extension.py +++ b/tests/cli/snapshots/unions_typing_extension.py @@ -1,6 +1,5 @@ -from typing_extensions import Annotated - import strawberry +from typing_extensions import Annotated # create a few types and then a union type From e5673c1e27423db0b8571ccbbef7d340277735ed Mon Sep 17 00:00:00 2001 From: jameschua Date: Sat, 22 Jul 2023 16:27:04 -0700 Subject: [PATCH 15/32] fix tests for pydantic v1 --- strawberry/experimental/pydantic/v2_compat.py | 5 ++++- tests/experimental/pydantic/test_conversion.py | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/strawberry/experimental/pydantic/v2_compat.py b/strawberry/experimental/pydantic/v2_compat.py index e935372ba5..eede049931 100644 --- a/strawberry/experimental/pydantic/v2_compat.py +++ b/strawberry/experimental/pydantic/v2_compat.py @@ -16,6 +16,7 @@ @dataclass class CompatModelField: name: str + type_: Any outer_type_: Any default: Any default_factory: Optional[Callable[[], Any]] @@ -45,6 +46,7 @@ def get_model_fields(model: Type[BaseModel]) -> Dict[str, CompatModelField]: for name, field in field_info.items(): new_fields[name] = CompatModelField( name=name, + type_=field.annotation, outer_type_=field.annotation, default=field.default, default_factory=field.default_factory, @@ -77,7 +79,8 @@ def get_model_fields(model: Type[BaseModel]) -> Dict[str, CompatModelField]: for name, field in model.__fields__.items(): # type: ignore[attr-defined] new_fields[name] = CompatModelField( name=name, - outer_type_=field.type_, + type_=field.type_, + outer_type_=field.outer_type_, default=field.default, default_factory=field.default_factory, required=field.required, diff --git a/tests/experimental/pydantic/test_conversion.py b/tests/experimental/pydantic/test_conversion.py index ffdbe6bcf5..1269782626 100644 --- a/tests/experimental/pydantic/test_conversion.py +++ b/tests/experimental/pydantic/test_conversion.py @@ -852,6 +852,7 @@ def _get_field( ) -> CompatModelField: return CompatModelField( name="a", + type_=str, outer_type_=str, default=default, default_factory=default_factory, From 16c674d71938befd0eeafbda1a5a4ef19a59df26 Mon Sep 17 00:00:00 2001 From: jameschua Date: Sat, 22 Jul 2023 16:32:33 -0700 Subject: [PATCH 16/32] remove weird stuff ruff added --- tests/cli/snapshots/unions_py38.py | 3 +-- tests/http/clients/base.py | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/cli/snapshots/unions_py38.py b/tests/cli/snapshots/unions_py38.py index b7ead3da65..4fd0143c69 100644 --- a/tests/cli/snapshots/unions_py38.py +++ b/tests/cli/snapshots/unions_py38.py @@ -1,6 +1,5 @@ -from typing import Annotated, Union - import strawberry +from typing import Annotated, Union # create a few types and then a union type diff --git a/tests/http/clients/base.py b/tests/http/clients/base.py index da4afef762..840c4af4cf 100644 --- a/tests/http/clients/base.py +++ b/tests/http/clients/base.py @@ -156,7 +156,7 @@ def _build_multipart_file_map( files_map: Dict[str, List[str]] = {} for key, values in variables.items(): if isinstance(values, dict): - folder_key = next(iter(values.keys())) + folder_key = list(values.keys())[0] key += f".{folder_key}" # noqa: PLW2901 # the list of file is inside the folder keyword values = values[folder_key] # noqa: PLW2901 @@ -166,7 +166,7 @@ def _build_multipart_file_map( # copying `files` as when we map a file we must discard from the dict _kwargs = files.copy() for index, _ in enumerate(values): - k = next(iter(_kwargs.keys())) + k = list(_kwargs.keys())[0] _kwargs.pop(k) files_map.setdefault(k, []) files_map[k].append(f"variables.{key}.{index}") From 94d48447fc1be1c1f394ed18d56d78f1c96e10a3 Mon Sep 17 00:00:00 2001 From: jameschua Date: Sat, 22 Jul 2023 16:35:17 -0700 Subject: [PATCH 17/32] add release file --- RELEASE.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 RELEASE.md diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 0000000000..d1248d7dad --- /dev/null +++ b/RELEASE.md @@ -0,0 +1,7 @@ +Release type: minor + +Adds initial support for pydantic V2. + +This is extremely experimental for wider initial testing. + +We do not encourage using this in production systems yet. \ No newline at end of file From a1163646e2eef90fdd1b5b66cdab4957b8682f97 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 22 Jul 2023 23:35:42 +0000 Subject: [PATCH 18/32] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- RELEASE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE.md b/RELEASE.md index d1248d7dad..66894765cd 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -4,4 +4,4 @@ Adds initial support for pydantic V2. This is extremely experimental for wider initial testing. -We do not encourage using this in production systems yet. \ No newline at end of file +We do not encourage using this in production systems yet. From 58e2f6f3bf3a658826ece1b5886af8d7b4ec203b Mon Sep 17 00:00:00 2001 From: jameschua Date: Sat, 22 Jul 2023 16:36:59 -0700 Subject: [PATCH 19/32] bump pydantic in pyproject.toml --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index f35e3dfe58..16888aaf97 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,7 +48,7 @@ flask = {version = ">=1.1", optional = true} opentelemetry-api = {version = "<2", optional = true} opentelemetry-sdk = {version = "<2", optional = true} chalice = {version = "^1.22", optional = true} -pydantic = {version = "<2", optional = true} +pydantic = {version = ">2", optional = true} python-multipart = {version = ">=0.0.5,<0.0.7", optional = true} sanic = {version = ">=20.12.2", optional = true} aiohttp = {version = "^3.7.4.post0", optional = true} From 7696efd3b9d1d205f0d026d060844af3f2f5d77d Mon Sep 17 00:00:00 2001 From: jameschua Date: Sat, 22 Jul 2023 16:42:37 -0700 Subject: [PATCH 20/32] upgrade pydantic lock file --- poetry.lock | 202 ++++++++++++++++++++++++++++++++++++------------- pyproject.toml | 4 +- 2 files changed, 150 insertions(+), 56 deletions(-) diff --git a/poetry.lock b/poetry.lock index dbb635b72a..85e7fe367c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -135,6 +135,20 @@ files = [ [package.dependencies] frozenlist = ">=1.1.0" +[[package]] +name = "annotated-types" +version = "0.5.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.7" +files = [ + {file = "annotated_types-0.5.0-py3-none-any.whl", hash = "sha256:58da39888f92c276ad970249761ebea80ba544b77acddaa1a4d6cf78287d45fd"}, + {file = "annotated_types-0.5.0.tar.gz", hash = "sha256:47cdc3490d9ac1506ce92c7aaa76c579dc3509ff11e098fc867e5130ab7be802"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.9\""} + [[package]] name = "ansicon" version = "1.89.0" @@ -2178,55 +2192,135 @@ files = [ [[package]] name = "pydantic" -version = "1.10.11" -description = "Data validation and settings management using python type hints" -optional = false -python-versions = ">=3.7" -files = [ - {file = "pydantic-1.10.11-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ff44c5e89315b15ff1f7fdaf9853770b810936d6b01a7bcecaa227d2f8fe444f"}, - {file = "pydantic-1.10.11-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a6c098d4ab5e2d5b3984d3cb2527e2d6099d3de85630c8934efcfdc348a9760e"}, - {file = "pydantic-1.10.11-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16928fdc9cb273c6af00d9d5045434c39afba5f42325fb990add2c241402d151"}, - {file = "pydantic-1.10.11-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0588788a9a85f3e5e9ebca14211a496409cb3deca5b6971ff37c556d581854e7"}, - {file = "pydantic-1.10.11-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e9baf78b31da2dc3d3f346ef18e58ec5f12f5aaa17ac517e2ffd026a92a87588"}, - {file = "pydantic-1.10.11-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:373c0840f5c2b5b1ccadd9286782852b901055998136287828731868027a724f"}, - {file = "pydantic-1.10.11-cp310-cp310-win_amd64.whl", hash = "sha256:c3339a46bbe6013ef7bdd2844679bfe500347ac5742cd4019a88312aa58a9847"}, - {file = "pydantic-1.10.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:08a6c32e1c3809fbc49debb96bf833164f3438b3696abf0fbeceb417d123e6eb"}, - {file = "pydantic-1.10.11-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a451ccab49971af043ec4e0d207cbc8cbe53dbf148ef9f19599024076fe9c25b"}, - {file = "pydantic-1.10.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5b02d24f7b2b365fed586ed73582c20f353a4c50e4be9ba2c57ab96f8091ddae"}, - {file = "pydantic-1.10.11-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3f34739a89260dfa420aa3cbd069fbcc794b25bbe5c0a214f8fb29e363484b66"}, - {file = "pydantic-1.10.11-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e297897eb4bebde985f72a46a7552a7556a3dd11e7f76acda0c1093e3dbcf216"}, - {file = "pydantic-1.10.11-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d185819a7a059550ecb85d5134e7d40f2565f3dd94cfd870132c5f91a89cf58c"}, - {file = "pydantic-1.10.11-cp311-cp311-win_amd64.whl", hash = "sha256:4400015f15c9b464c9db2d5d951b6a780102cfa5870f2c036d37c23b56f7fc1b"}, - {file = "pydantic-1.10.11-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2417de68290434461a266271fc57274a138510dca19982336639484c73a07af6"}, - {file = "pydantic-1.10.11-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:331c031ba1554b974c98679bd0780d89670d6fd6f53f5d70b10bdc9addee1713"}, - {file = "pydantic-1.10.11-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8268a735a14c308923e8958363e3a3404f6834bb98c11f5ab43251a4e410170c"}, - {file = "pydantic-1.10.11-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:44e51ba599c3ef227e168424e220cd3e544288c57829520dc90ea9cb190c3248"}, - {file = "pydantic-1.10.11-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d7781f1d13b19700b7949c5a639c764a077cbbdd4322ed505b449d3ca8edcb36"}, - {file = "pydantic-1.10.11-cp37-cp37m-win_amd64.whl", hash = "sha256:7522a7666157aa22b812ce14c827574ddccc94f361237ca6ea8bb0d5c38f1629"}, - {file = "pydantic-1.10.11-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bc64eab9b19cd794a380179ac0e6752335e9555d214cfcb755820333c0784cb3"}, - {file = "pydantic-1.10.11-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8dc77064471780262b6a68fe67e013298d130414d5aaf9b562c33987dbd2cf4f"}, - {file = "pydantic-1.10.11-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe429898f2c9dd209bd0632a606bddc06f8bce081bbd03d1c775a45886e2c1cb"}, - {file = "pydantic-1.10.11-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:192c608ad002a748e4a0bed2ddbcd98f9b56df50a7c24d9a931a8c5dd053bd3d"}, - {file = "pydantic-1.10.11-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ef55392ec4bb5721f4ded1096241e4b7151ba6d50a50a80a2526c854f42e6a2f"}, - {file = "pydantic-1.10.11-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:41e0bb6efe86281623abbeeb0be64eab740c865388ee934cd3e6a358784aca6e"}, - {file = "pydantic-1.10.11-cp38-cp38-win_amd64.whl", hash = "sha256:265a60da42f9f27e0b1014eab8acd3e53bd0bad5c5b4884e98a55f8f596b2c19"}, - {file = "pydantic-1.10.11-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:469adf96c8e2c2bbfa655fc7735a2a82f4c543d9fee97bd113a7fb509bf5e622"}, - {file = "pydantic-1.10.11-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e6cbfbd010b14c8a905a7b10f9fe090068d1744d46f9e0c021db28daeb8b6de1"}, - {file = "pydantic-1.10.11-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abade85268cc92dff86d6effcd917893130f0ff516f3d637f50dadc22ae93999"}, - {file = "pydantic-1.10.11-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e9738b0f2e6c70f44ee0de53f2089d6002b10c33264abee07bdb5c7f03038303"}, - {file = "pydantic-1.10.11-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:787cf23e5a0cde753f2eabac1b2e73ae3844eb873fd1f5bdbff3048d8dbb7604"}, - {file = "pydantic-1.10.11-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:174899023337b9fc685ac8adaa7b047050616136ccd30e9070627c1aaab53a13"}, - {file = "pydantic-1.10.11-cp39-cp39-win_amd64.whl", hash = "sha256:1954f8778489a04b245a1e7b8b22a9d3ea8ef49337285693cf6959e4b757535e"}, - {file = "pydantic-1.10.11-py3-none-any.whl", hash = "sha256:008c5e266c8aada206d0627a011504e14268a62091450210eda7c07fabe6963e"}, - {file = "pydantic-1.10.11.tar.gz", hash = "sha256:f66d479cf7eb331372c470614be6511eae96f1f120344c25f3f9bb59fb1b5528"}, -] - -[package.dependencies] -typing-extensions = ">=4.2.0" - -[package.extras] -dotenv = ["python-dotenv (>=0.10.4)"] -email = ["email-validator (>=1.0.3)"] +version = "2.0.3" +description = "Data validation using Python type hints" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pydantic-2.0.3-py3-none-any.whl", hash = "sha256:614eb3321eb600c81899a88fa9858b008e3c79e0d4f1b49ab1f516b4b0c27cfb"}, + {file = "pydantic-2.0.3.tar.gz", hash = "sha256:94f13e0dcf139a5125e88283fc999788d894e14ed90cf478bcc2ee50bd4fc630"}, +] + +[package.dependencies] +annotated-types = ">=0.4.0" +pydantic-core = "2.3.0" +typing-extensions = ">=4.6.1" + +[package.extras] +email = ["email-validator (>=2.0.0)"] + +[[package]] +name = "pydantic-core" +version = "2.3.0" +description = "" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pydantic_core-2.3.0-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:4542c98b8364b976593703a2dda97377433b102f380b61bc3a2cbc2fbdae1d1f"}, + {file = "pydantic_core-2.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9342de50824b40f55d2600f66c6f9a91a3a24851eca39145a749a3dc804ee599"}, + {file = "pydantic_core-2.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:539432f911686cb80284c30b33eaf9f4fd9a11e1111fe0dc98fdbdce69b49821"}, + {file = "pydantic_core-2.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38a0e7ee65c8999394d92d9c724434cb629279d19844f2b69d9bbc46dc8b8b61"}, + {file = "pydantic_core-2.3.0-cp310-cp310-manylinux_2_24_armv7l.whl", hash = "sha256:e3ed6834cc005798187a56c248a2240207cb8ffdda1c89e9afda4c3d526c2ea0"}, + {file = "pydantic_core-2.3.0-cp310-cp310-manylinux_2_24_ppc64le.whl", hash = "sha256:e72ac299a6bf732a60852d052acf3999d234686755a02ba111e85e7ebf8155b1"}, + {file = "pydantic_core-2.3.0-cp310-cp310-manylinux_2_24_s390x.whl", hash = "sha256:616b3451b05ca63b8f433c627f68046b39543faeaa4e50d8c6699a2a1e4b85a5"}, + {file = "pydantic_core-2.3.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:adcb9c8848e15c613e483e0b99767ae325af27fe0dbd866df01fe5849d06e6e1"}, + {file = "pydantic_core-2.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:464bf799b422be662e5e562e62beeffc9eaa907d381a9d63a2556615bbda286d"}, + {file = "pydantic_core-2.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4638ebc17de08c2f3acba557efeb6f195c88b7299d8c55c0bb4e20638bbd4d03"}, + {file = "pydantic_core-2.3.0-cp310-none-win32.whl", hash = "sha256:9ff322c7e1030543d35d83bb521b69114d3d150750528d7757544f639def9ad6"}, + {file = "pydantic_core-2.3.0-cp310-none-win_amd64.whl", hash = "sha256:4824eb018f0a4680b1e434697a9bf3f41c7799b80076d06530cbbd212e040ccc"}, + {file = "pydantic_core-2.3.0-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:0aa429578e23885b3984c49d687cd05ab06f0b908ea1711a8bf7e503b7f97160"}, + {file = "pydantic_core-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:20d710c1f79af930b8891bcebd84096798e4387ab64023ef41521d58f21277d3"}, + {file = "pydantic_core-2.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:309f45d4d7481d6f09cb9e35c72caa0e50add4a30bb08c04c5fe5956a0158633"}, + {file = "pydantic_core-2.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bcfb7be905aa849bd882262e1df3f75b564e2f708b4b4c7ad2d3deaf5410562"}, + {file = "pydantic_core-2.3.0-cp311-cp311-manylinux_2_24_armv7l.whl", hash = "sha256:85cd9c0af34e371390e3cb2f3a470b0b40cc07568c1e966c638c49062be6352d"}, + {file = "pydantic_core-2.3.0-cp311-cp311-manylinux_2_24_ppc64le.whl", hash = "sha256:37c5028cebdf731298724070838fb3a71ef1fbd201d193d311ac2cbdbca25a23"}, + {file = "pydantic_core-2.3.0-cp311-cp311-manylinux_2_24_s390x.whl", hash = "sha256:e4208f23f12d0ad206a07a489ef4cb15722c10b62774c4460ee4123250be938e"}, + {file = "pydantic_core-2.3.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c24465dd11b65c8510f251b095fc788c7c91481c81840112fe3f76c30793a455"}, + {file = "pydantic_core-2.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3cd7ee8bbfab277ab56e272221886fd33a1b5943fbf45ae9195aa6a48715a8a0"}, + {file = "pydantic_core-2.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0fc7e0b056b66cc536e97ef60f48b3b289f6b3b62ac225afd4b22a42434617bf"}, + {file = "pydantic_core-2.3.0-cp311-none-win32.whl", hash = "sha256:4788135db4bd83a5edc3522b11544b013be7d25b74b155e08dd3b20cd6663bbb"}, + {file = "pydantic_core-2.3.0-cp311-none-win_amd64.whl", hash = "sha256:f93c867e5e85584a28c6a6feb6f2086d717266eb5d1210d096dd717b7f4dec04"}, + {file = "pydantic_core-2.3.0-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:73f62bb7fd862d9bcd886e10612bade6fe042eda8b47e8c129892bcfb7b45e84"}, + {file = "pydantic_core-2.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4d889d498fce64bfcd8adf1a78579a7f626f825cbeb2956a24a29b35f9a1df32"}, + {file = "pydantic_core-2.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7d55e38a89ec2ae17b2fa7ffeda6b70f63afab1888bd0d57aaa7b7879760acb4"}, + {file = "pydantic_core-2.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1aefebb506bc1fe355d91d25f12bcdea7f4d7c2d9f0f6716dd025543777c99a5"}, + {file = "pydantic_core-2.3.0-cp312-cp312-manylinux_2_24_armv7l.whl", hash = "sha256:6441a29f42585f085db0c04cd0557d4cbbb46fa68a0972409b1cfe9f430280c1"}, + {file = "pydantic_core-2.3.0-cp312-cp312-manylinux_2_24_ppc64le.whl", hash = "sha256:47e8f034be31390a8f525431eb5e803a78ce7e2e11b32abf5361a972e14e6b61"}, + {file = "pydantic_core-2.3.0-cp312-cp312-manylinux_2_24_s390x.whl", hash = "sha256:ad814864aba263be9c83ada44a95f72d10caabbf91589321f95c29c902bdcff0"}, + {file = "pydantic_core-2.3.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9eff3837d447fccf2ac38c259b14ab9cbde700df355a45a1f3ff244d5e78f8b6"}, + {file = "pydantic_core-2.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:534f3f63c000f08050c6f7f4378bf2b52d7ba9214e9d35e3f60f7ad24a4d6425"}, + {file = "pydantic_core-2.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ef6a222d54f742c24f6b143aab088702db3a827b224e75b9dd28b38597c595fe"}, + {file = "pydantic_core-2.3.0-cp312-none-win32.whl", hash = "sha256:4e26944e64ecc1d7b19db954c0f7b471f3b141ec8e1a9f57cfe27671525cd248"}, + {file = "pydantic_core-2.3.0-cp312-none-win_amd64.whl", hash = "sha256:019c5c41941438570dfc7d3f0ae389b2425add1775a357ce1e83ed1434f943d6"}, + {file = "pydantic_core-2.3.0-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:27c1bbfb9d84a75cf33b7f19b53c29eb7ead99b235fce52aced5507174ab8f98"}, + {file = "pydantic_core-2.3.0-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:7cb496e934b71f1ade844ab91d6ccac78a3520e5df02fdb2357f85a71e541e69"}, + {file = "pydantic_core-2.3.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5af2d43b1978958d91351afbcc9b4d0cfe144c46c61740e82aaac8bb39ab1a4d"}, + {file = "pydantic_core-2.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d3097c39d7d4e8dba2ef86de171dcccad876c36d8379415ba18a5a4d0533510"}, + {file = "pydantic_core-2.3.0-cp37-cp37m-manylinux_2_24_armv7l.whl", hash = "sha256:dd3b023f3317dbbbc775e43651ce1a31a9cea46216ad0b5be37afc18a2007699"}, + {file = "pydantic_core-2.3.0-cp37-cp37m-manylinux_2_24_ppc64le.whl", hash = "sha256:27babb9879bf2c45ed655d02639f4c30e2b9ef1b71ce59c2305bbf7287910a18"}, + {file = "pydantic_core-2.3.0-cp37-cp37m-manylinux_2_24_s390x.whl", hash = "sha256:2183a9e18cdc0de53bdaa1675f237259162abeb62d6ac9e527c359c1074dc55d"}, + {file = "pydantic_core-2.3.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c089d8e7f1b4db08b2f8e4107304eec338df046275dad432635a9be9531e2fc8"}, + {file = "pydantic_core-2.3.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:2f10aa5452b865818dd0137f568d443f5e93b60a27080a01aa4b7512c7ba13a3"}, + {file = "pydantic_core-2.3.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:f642313d559f9d9a00c4de6820124059cc3342a0d0127b18301de2c680d5ea40"}, + {file = "pydantic_core-2.3.0-cp37-none-win32.whl", hash = "sha256:45327fc57afbe3f2c3d7f54a335d5cecee8a9fdb3906a2fbed8af4092f4926df"}, + {file = "pydantic_core-2.3.0-cp37-none-win_amd64.whl", hash = "sha256:e427b66596a6441a5607dfc0085b47d36073f88da7ac48afd284263b9b99e6ce"}, + {file = "pydantic_core-2.3.0-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:0b3d781c71b8bfb621ef23b9c874933e2cd33237c1a65cc20eeb37437f8e7e18"}, + {file = "pydantic_core-2.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ad46027dbd5c1db87dc0b49becbe23093b143a20302028d387dae37ee5ef95f5"}, + {file = "pydantic_core-2.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39aa09ed7ce2a648c904f79032d16dda29e6913112af8465a7bf710eef23c7ca"}, + {file = "pydantic_core-2.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05b4bf8c58409586a7a04c858a86ab10f28c6c1a7c33da65e0326c59d5b0ab16"}, + {file = "pydantic_core-2.3.0-cp38-cp38-manylinux_2_24_armv7l.whl", hash = "sha256:ba2b807d2b62c446120906b8580cddae1d76d3de4efbb95ccc87f5e35c75b4b2"}, + {file = "pydantic_core-2.3.0-cp38-cp38-manylinux_2_24_ppc64le.whl", hash = "sha256:ea955e4ed21f4bbb9b83fea09fc6af0bed82e69ecf6b35ec89237a0a49633033"}, + {file = "pydantic_core-2.3.0-cp38-cp38-manylinux_2_24_s390x.whl", hash = "sha256:06884c07956526ac9ebfef40fe21a11605569b8fc0e2054a375fb39c978bf48f"}, + {file = "pydantic_core-2.3.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f868e731a18b403b88aa434d960489ceeed0ddeb44ebc02389540731a67705e0"}, + {file = "pydantic_core-2.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cb08fab0fc1db15c277b72e33ac74ad9c0c789413da8984a3eacb22a94b42ef4"}, + {file = "pydantic_core-2.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6ca34c29fbd6592de5fd39e80c1993634d704c4e7e14ba54c87b2c7c53da68fe"}, + {file = "pydantic_core-2.3.0-cp38-none-win32.whl", hash = "sha256:cd782807d35c8a41aaa7d30b5107784420eefd9fdc1c760d86007d43ae00b15d"}, + {file = "pydantic_core-2.3.0-cp38-none-win_amd64.whl", hash = "sha256:01f56d5ee70b1d39c0fd08372cc5142274070ab7181d17c86035f130eebc05b8"}, + {file = "pydantic_core-2.3.0-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:78b1ac0151271ce62bc2b33755f1043eda6a310373143a2f27e2bcd3d5fc8633"}, + {file = "pydantic_core-2.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:64bfd2c35a2c350f73ac52dc134d8775f93359c4c969280a6fe5301b5b6e7431"}, + {file = "pydantic_core-2.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:937c0fe9538f1212b62df6a68f8d78df3572fe3682d9a0dd8851eac8a4e46063"}, + {file = "pydantic_core-2.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d965c7c4b40d1cedec9188782e98bd576f9a04868835604200c3a6e817b824f"}, + {file = "pydantic_core-2.3.0-cp39-cp39-manylinux_2_24_armv7l.whl", hash = "sha256:ad442b8585ed4a3c2d22e4bf7b465d9b7d281e055b09719a8aeb5b576422dc9b"}, + {file = "pydantic_core-2.3.0-cp39-cp39-manylinux_2_24_ppc64le.whl", hash = "sha256:4bf20c9722821fce766e685718e739deeccc60d6bc7be5029281db41f999ee0c"}, + {file = "pydantic_core-2.3.0-cp39-cp39-manylinux_2_24_s390x.whl", hash = "sha256:f3dd5333049b5b3faa739e0f40b77cc8b7a1aded2f2da0e28794c81586d7b08a"}, + {file = "pydantic_core-2.3.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0dc5f516b24d24bc9e8dd9305460899f38302b3c4f9752663b396ef9848557bf"}, + {file = "pydantic_core-2.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:055f7ea6b1fbb37880d66d70eefd22dd319b09c79d2cb99b1dbfeb34b653b0b2"}, + {file = "pydantic_core-2.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:af693a89db6d6ac97dd84dd7769b3f2bd9007b578127d0e7dda03053f4d3b34b"}, + {file = "pydantic_core-2.3.0-cp39-none-win32.whl", hash = "sha256:f60e31e3e15e8c294bf70c60f8ae4d0c3caf3af8f26466e9aa8ea4c01302749b"}, + {file = "pydantic_core-2.3.0-cp39-none-win_amd64.whl", hash = "sha256:2b79f3681481f4424d7845cc7a261d5a4baa810d656b631fa844dc9967b36a7b"}, + {file = "pydantic_core-2.3.0-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:a666134b41712e30a71afaa26deeb4da374179f769fa49784cdf0e7698880fab"}, + {file = "pydantic_core-2.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c119e9227487ad3d7c3c737d896afe548a6be554091f9745da1f4b489c40561"}, + {file = "pydantic_core-2.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73929a2fb600a2333fce2efd92596cff5e6bf8946e20e93c067b220760064862"}, + {file = "pydantic_core-2.3.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:41bbc2678a5b6a19371b2cb51f30ccea71f0c14b26477d2d884fed761cea42c7"}, + {file = "pydantic_core-2.3.0-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:dcbff997f47d45bf028bda4c3036bb3101e89a3df271281d392b6175f71c71d1"}, + {file = "pydantic_core-2.3.0-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:afa8808159169368b66e4fbeafac6c6fd8f26246dc4d0dcc2caf94bd9cf1b828"}, + {file = "pydantic_core-2.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:12be3b5f54f8111ca38e6b7277f26c23ba5cb3344fae06f879a0a93dfc8b479e"}, + {file = "pydantic_core-2.3.0-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:ed5babdcd3d052ba5cf8832561f18df20778c7ccf12587b2d82f7bf3bf259a0e"}, + {file = "pydantic_core-2.3.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d642e5c029e2acfacf6aa0a7a3e822086b3b777c70d364742561f9ca64c1ffc"}, + {file = "pydantic_core-2.3.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ba3073eb38a1294e8c7902989fb80a7a147a69db2396818722bd078476586a0"}, + {file = "pydantic_core-2.3.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d5146a6749b1905e04e62e0ad4622f079e5582f8b3abef5fb64516c623127908"}, + {file = "pydantic_core-2.3.0-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:deeb64335f489c3c11949cbd1d1668b3f1fb2d1c6a5bf40e126ef7bf95f9fa40"}, + {file = "pydantic_core-2.3.0-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:31acc37288b8e69e4849f618c3d5cf13b58077c1a1ff9ade0b3065ba974cd385"}, + {file = "pydantic_core-2.3.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:e09d9f6d722de9d4c1c5f122ea9bc6b25a05f975457805af4dcab7b0128aacbf"}, + {file = "pydantic_core-2.3.0-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:ba6a8cf089222a171b8f84e6ec2d10f7a9d14f26be3a347b14775a8741810676"}, + {file = "pydantic_core-2.3.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef1fd1b24e9bcddcb168437686677104e205c8e25b066e73ffdf331d3bb8792b"}, + {file = "pydantic_core-2.3.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eda1a89c4526826c0a87d33596a4cd15b8f58e9250f503e39af1699ba9c878e8"}, + {file = "pydantic_core-2.3.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a3e9a18401a28db4358da2e191508702dbf065f2664c710708cdf9552b9fa50c"}, + {file = "pydantic_core-2.3.0-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:a439fd0d45d51245bbde799726adda5bd18aed3fa2b01ab2e6a64d6d13776fa3"}, + {file = "pydantic_core-2.3.0-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:bf6a1d2c920cc9528e884850a4b2ee7629e3d362d5c44c66526d4097bbb07a1a"}, + {file = "pydantic_core-2.3.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e33fcbea3b63a339dd94de0fc442fefacfe681cc7027ce63f67af9f7ceec7422"}, + {file = "pydantic_core-2.3.0-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:bf3ed993bdf4754909f175ff348cf8f78d4451215b8aa338633f149ca3b1f37a"}, + {file = "pydantic_core-2.3.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7584171eb3115acd4aba699bc836634783f5bd5aab131e88d8eeb8a3328a4a72"}, + {file = "pydantic_core-2.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1624baa76d1740711b2048f302ae9a6d73d277c55a8c3e88b53b773ebf73a971"}, + {file = "pydantic_core-2.3.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:06f33f695527f5a86e090f208978f9fd252c9cfc7e869d3b679bd71f7cb2c1fa"}, + {file = "pydantic_core-2.3.0-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:7ecf0a67b212900e92f328181fed02840d74ed39553cdb38d27314e2b9c89dfa"}, + {file = "pydantic_core-2.3.0-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:45fa1e8ad6f4367ad73674ca560da8e827cc890eaf371f3ee063d6d7366a207b"}, + {file = "pydantic_core-2.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:8d0dbcc57839831ae79fd24b1b83d42bc9448d79feaf3ed3fb5cbf94ffbf3eb7"}, + {file = "pydantic_core-2.3.0.tar.gz", hash = "sha256:5cfb5ac4e82c47d5dc25b209dd4c3989e284b80109f9e08b33c895080c424b4f"}, +] + +[package.dependencies] +typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pydantic-factories" @@ -3018,13 +3112,13 @@ full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart", "pyyam [[package]] name = "starlite" -version = "1.51.13" +version = "1.51.12" description = "Performant, light and flexible ASGI API Framework" optional = false python-versions = ">=3.8,<4.0" files = [ - {file = "starlite-1.51.13-py3-none-any.whl", hash = "sha256:43544dcddf98883adeb8554eabd06781519448ef68cedf839aff5d94ddbe3b5d"}, - {file = "starlite-1.51.13.tar.gz", hash = "sha256:969f175bd3fed21f41090be8be0577a6f5f709c9432d48f9e2fb8ded68680401"}, + {file = "starlite-1.51.12-py3-none-any.whl", hash = "sha256:efc9d478660c4500fd26f86f853a7f014a4aa510cbb0825669028934f6106c3f"}, + {file = "starlite-1.51.12.tar.gz", hash = "sha256:c785d26291a361dedc52dbf5145be5dfeb41676f0204c49e506fcbafb0a10268"}, ] [package.dependencies] @@ -3035,7 +3129,7 @@ importlib-metadata = {version = "*", markers = "python_version < \"3.10\""} mako = ">=1.2.4" msgspec = ">=0.11.0" multidict = ">=6.0.2" -pydantic = "<2" +pydantic = "*" pydantic-factories = "*" pydantic-openapi-schema = ">=1.5.0" pyyaml = "*" @@ -3928,4 +4022,4 @@ starlite = ["starlite"] [metadata] lock-version = "2.0" python-versions = "^3.7" -content-hash = "7e1c41ece0197cdbb134f5ff1b7539f0d035b7cc636a11eddf061a068010b55c" +content-hash = "e1e0312ba34a8e3ce597c7f41895e381375a875b7612b886f3217f32162f60dc" diff --git a/pyproject.toml b/pyproject.toml index 16888aaf97..5fa701bd6a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,7 +48,7 @@ flask = {version = ">=1.1", optional = true} opentelemetry-api = {version = "<2", optional = true} opentelemetry-sdk = {version = "<2", optional = true} chalice = {version = "^1.22", optional = true} -pydantic = {version = ">2", optional = true} +pydantic = "^2.0" python-multipart = {version = ">=0.0.5,<0.0.7", optional = true} sanic = {version = ">=20.12.2", optional = true} aiohttp = {version = "^3.7.4.post0", optional = true} @@ -112,7 +112,7 @@ channels = "^3.0.5" Django = ">=3.2" fastapi = {version = ">=0.65.0", optional = false} flask = ">=1.1" -pydantic = {version = "<2", optional = false} +pydantic = {version = ">2", optional = false} pytest-aiohttp = "^1.0.3" pytest-django = {version = "^4.5"} pytest-flask = {version = "^1.2.0"} From 79c41d28f0593de2199ed611d1a72314277a9888 Mon Sep 17 00:00:00 2001 From: jameschua Date: Sat, 22 Jul 2023 16:44:22 -0700 Subject: [PATCH 21/32] remove unused --- tests/test_dataloaders.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_dataloaders.py b/tests/test_dataloaders.py index 8b2b0cb570..b639cf029e 100644 --- a/tests/test_dataloaders.py +++ b/tests/test_dataloaders.py @@ -363,7 +363,7 @@ async def idx(keys: List[int]) -> List[int]: async def test_cache_override(): class TestCache(AbstractCache[int, int]): def __init__(self): - self.cache: Dict[int, Future[int]] = {} + self.cache: Dict[int, "Future[int]"] = {} def get(self, key: int) -> Optional["Future[int]"]: return self.cache.get(key) From 3b3a3924a8e1e538c1229851b700552174285ebb Mon Sep 17 00:00:00 2001 From: jameschua Date: Sat, 22 Jul 2023 16:54:38 -0700 Subject: [PATCH 22/32] fix mypy --- strawberry/experimental/pydantic/v2_compat.py | 6 +- strawberry/ext/mypy_plugin.py | 58 ++++++++++++----- .../pydantic/schema/test_defaults.py | 63 +++++++++++++++++++ 3 files changed, 108 insertions(+), 19 deletions(-) diff --git a/strawberry/experimental/pydantic/v2_compat.py b/strawberry/experimental/pydantic/v2_compat.py index eede049931..acc666f620 100644 --- a/strawberry/experimental/pydantic/v2_compat.py +++ b/strawberry/experimental/pydantic/v2_compat.py @@ -66,9 +66,9 @@ def get_model_fields(model: Type[BaseModel]) -> Dict[str, CompatModelField]: is_new_type, new_type_supertype, ) - from pydantic.utils import ( - lenient_issubclass, # type: ignore[no-redef] - smart_deepcopy, # type: ignore[no-redef] + from pydantic.utils import ( # type: ignore[no-redef] + lenient_issubclass, + smart_deepcopy, ) PYDANTIC_MISSING_TYPE = dataclasses.MISSING # type: ignore[assignment] diff --git a/strawberry/ext/mypy_plugin.py b/strawberry/ext/mypy_plugin.py index 1da6f7f44e..2460e12104 100644 --- a/strawberry/ext/mypy_plugin.py +++ b/strawberry/ext/mypy_plugin.py @@ -53,6 +53,8 @@ from mypy.typevars import fill_typevars from mypy.util import get_unique_redefinition_name +from strawberry.experimental.pydantic.v2_compat import IS_PYDANTIC_V1 + # Backwards compatible with the removal of `TypeVarDef` in mypy 0.920. try: from mypy.types import TypeVarDef # type: ignore @@ -412,7 +414,14 @@ def strawberry_pydantic_class_callback(ctx: ClassDefContext) -> None: for _name, data in model_type.type.metadata[PYDANTIC_METADATA_KEY][ "fields" ].items(): - field = PydanticModelField.deserialize(ctx.cls.info, data) + if IS_PYDANTIC_V1: + field = PydanticModelField.deserialize( + ctx.cls.info, data + ) # type:ignore[call-arg] + else: + field = PydanticModelField.deserialize( + info=ctx.cls.info, data=data, api=ctx.api + ) pydantic_fields.add(field) except KeyError: # this will happen if the user didn't add the pydantic plugin @@ -440,21 +449,38 @@ def strawberry_pydantic_class_callback(ctx: ClassDefContext) -> None: # Add the default to_pydantic if undefined by the user if "to_pydantic" not in ctx.cls.info.names: - add_method( - ctx, - "to_pydantic", - args=[ - f.to_argument( - # TODO: use_alias should depend on config? - info=model_type.type, - typed=True, - force_optional=False, - use_alias=True, - ) - for f in missing_pydantic_fields - ], - return_type=model_type, - ) + if IS_PYDANTIC_V1: + add_method( + ctx, + "to_pydantic", + args=[ + f.to_argument( + # TODO: use_alias should depend on config? + info=model_type.type, # type:ignore[call-arg] + typed=True, + force_optional=False, + use_alias=True, + ) + for f in missing_pydantic_fields + ], + return_type=model_type, + ) + else: + add_method( + ctx, + "to_pydantic", + args=[ + f.to_argument( + # TODO: use_alias should depend on config? + current_info=model_type.type, + typed=True, + force_optional=False, + use_alias=True, + ) + for f in missing_pydantic_fields + ], + return_type=model_type, + ) # Add from_pydantic model_argument = Argument( diff --git a/tests/experimental/pydantic/schema/test_defaults.py b/tests/experimental/pydantic/schema/test_defaults.py index 0917e85ec9..9da15048c2 100644 --- a/tests/experimental/pydantic/schema/test_defaults.py +++ b/tests/experimental/pydantic/schema/test_defaults.py @@ -5,6 +5,7 @@ import strawberry from strawberry.printer import print_schema +from tests.experimental.pydantic.utils import needs_pydanticv1, needs_pydanticv2 def test_field_type_default(): @@ -156,3 +157,65 @@ def b(self, user: StrawberryUser) -> str: """ assert print_schema(schema) == textwrap.dedent(expected).strip() + + +@needs_pydanticv1 +def test_v1_implicit_default(): + class User(pydantic.BaseModel): + name: Optional[str] + + @strawberry.experimental.pydantic.type(User, all_fields=True) + class PydanticUser: + ... + + @strawberry.type + class Query: + @strawberry.field + def a(self) -> PydanticUser: + ... + + schema = strawberry.Schema(Query) + + # name should have a default of None + expected = """ + type PydanticUser { + name: String = null + } + + type Query { + a: PydanticUser! + } + """ + + assert print_schema(schema) == textwrap.dedent(expected).strip() + + +@needs_pydanticv2 +def test_v2_explicit_default(): + class User(pydantic.BaseModel): + name: Optional[str] + + @strawberry.experimental.pydantic.type(User, all_fields=True) + class PydanticUser: + ... + + @strawberry.type + class Query: + @strawberry.field + def a(self) -> PydanticUser: + ... + + schema = strawberry.Schema(Query) + + # name should have no default + expected = """ + type PydanticUser { + name: String + } + + type Query { + a: PydanticUser! + } + """ + + assert print_schema(schema) == textwrap.dedent(expected).strip() From 817c32523b3a24e3115f738f527b66828a24189b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 22 Jul 2023 23:57:26 +0000 Subject: [PATCH 23/32] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- strawberry/ext/mypy_plugin.py | 1 - tests/experimental/pydantic/schema/test_defaults.py | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/strawberry/ext/mypy_plugin.py b/strawberry/ext/mypy_plugin.py index 2460e12104..5e798780ab 100644 --- a/strawberry/ext/mypy_plugin.py +++ b/strawberry/ext/mypy_plugin.py @@ -52,7 +52,6 @@ ) from mypy.typevars import fill_typevars from mypy.util import get_unique_redefinition_name - from strawberry.experimental.pydantic.v2_compat import IS_PYDANTIC_V1 # Backwards compatible with the removal of `TypeVarDef` in mypy 0.920. diff --git a/tests/experimental/pydantic/schema/test_defaults.py b/tests/experimental/pydantic/schema/test_defaults.py index 9da15048c2..bffd66f52f 100644 --- a/tests/experimental/pydantic/schema/test_defaults.py +++ b/tests/experimental/pydantic/schema/test_defaults.py @@ -181,7 +181,7 @@ def a(self) -> PydanticUser: type PydanticUser { name: String = null } - + type Query { a: PydanticUser! } @@ -212,7 +212,7 @@ def a(self) -> PydanticUser: type PydanticUser { name: String } - + type Query { a: PydanticUser! } From bfd7ac468d905decc530755b83f6e5814bdaf1fc Mon Sep 17 00:00:00 2001 From: jameschua Date: Sat, 22 Jul 2023 17:03:59 -0700 Subject: [PATCH 24/32] fix poetry --- poetry.lock | 2 +- pyproject.toml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/poetry.lock b/poetry.lock index 85e7fe367c..54b2929b7e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -4022,4 +4022,4 @@ starlite = ["starlite"] [metadata] lock-version = "2.0" python-versions = "^3.7" -content-hash = "e1e0312ba34a8e3ce597c7f41895e381375a875b7612b886f3217f32162f60dc" +content-hash = "a98ba56206d94761064ef8de0b61180ee81a7c0c0999505c725179a2ef269ab6" diff --git a/pyproject.toml b/pyproject.toml index 5fa701bd6a..560152cfe6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,7 +48,7 @@ flask = {version = ">=1.1", optional = true} opentelemetry-api = {version = "<2", optional = true} opentelemetry-sdk = {version = "<2", optional = true} chalice = {version = "^1.22", optional = true} -pydantic = "^2.0" +pydantic = {version = ">1.6.1", optional = true} python-multipart = {version = ">=0.0.5,<0.0.7", optional = true} sanic = {version = ">=20.12.2", optional = true} aiohttp = {version = "^3.7.4.post0", optional = true} @@ -112,7 +112,7 @@ channels = "^3.0.5" Django = ">=3.2" fastapi = {version = ">=0.65.0", optional = false} flask = ">=1.1" -pydantic = {version = ">2", optional = false} +pydantic = {version = ">1.6.1", optional = false} pytest-aiohttp = "^1.0.3" pytest-django = {version = "^4.5"} pytest-flask = {version = "^1.2.0"} From 93146091d2c17e98f5d07a20ec23865dc8be4125 Mon Sep 17 00:00:00 2001 From: jameschua Date: Sat, 22 Jul 2023 17:10:19 -0700 Subject: [PATCH 25/32] remove implicit default test --- .../pydantic/schema/test_defaults.py | 33 ------------------- 1 file changed, 33 deletions(-) diff --git a/tests/experimental/pydantic/schema/test_defaults.py b/tests/experimental/pydantic/schema/test_defaults.py index bffd66f52f..feb060a243 100644 --- a/tests/experimental/pydantic/schema/test_defaults.py +++ b/tests/experimental/pydantic/schema/test_defaults.py @@ -157,39 +157,6 @@ def b(self, user: StrawberryUser) -> str: """ assert print_schema(schema) == textwrap.dedent(expected).strip() - - -@needs_pydanticv1 -def test_v1_implicit_default(): - class User(pydantic.BaseModel): - name: Optional[str] - - @strawberry.experimental.pydantic.type(User, all_fields=True) - class PydanticUser: - ... - - @strawberry.type - class Query: - @strawberry.field - def a(self) -> PydanticUser: - ... - - schema = strawberry.Schema(Query) - - # name should have a default of None - expected = """ - type PydanticUser { - name: String = null - } - - type Query { - a: PydanticUser! - } - """ - - assert print_schema(schema) == textwrap.dedent(expected).strip() - - @needs_pydanticv2 def test_v2_explicit_default(): class User(pydantic.BaseModel): From af3299e6abe0c67f3a8c7a18ac9b764a60676240 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 23 Jul 2023 00:10:43 +0000 Subject: [PATCH 26/32] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/experimental/pydantic/schema/test_defaults.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/experimental/pydantic/schema/test_defaults.py b/tests/experimental/pydantic/schema/test_defaults.py index feb060a243..a64f9574c9 100644 --- a/tests/experimental/pydantic/schema/test_defaults.py +++ b/tests/experimental/pydantic/schema/test_defaults.py @@ -5,7 +5,7 @@ import strawberry from strawberry.printer import print_schema -from tests.experimental.pydantic.utils import needs_pydanticv1, needs_pydanticv2 +from tests.experimental.pydantic.utils import needs_pydanticv2 def test_field_type_default(): @@ -157,6 +157,8 @@ def b(self, user: StrawberryUser) -> str: """ assert print_schema(schema) == textwrap.dedent(expected).strip() + + @needs_pydanticv2 def test_v2_explicit_default(): class User(pydantic.BaseModel): From 8cd57d969824eef4546fb50a2b1e8889e53a7230 Mon Sep 17 00:00:00 2001 From: jameschua Date: Sat, 22 Jul 2023 17:21:36 -0700 Subject: [PATCH 27/32] force pydantic 1.10 --- .github/workflows/test.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b67e45017a..91ba53c55e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -159,6 +159,9 @@ jobs: - run: poetry install --with integrations if: steps.setup-python.outputs.cache-hit != 'true' + # Since we are running all the integrations at once, we can't use + # pydantic v2. It is not compatible with starlette yet + - run: poetry run pip install pydantic==1.10 # we use poetry directly instead of nox since we want to # test all integrations at once on windows From eec5c8e7d32d95c99800b8f7b969597736b24454 Mon Sep 17 00:00:00 2001 From: James Chua <30519287+thejaminator@users.noreply.github.com> Date: Mon, 24 Jul 2023 11:00:21 -0700 Subject: [PATCH 28/32] Update noxfile.py Co-authored-by: Patrick Arminio --- noxfile.py | 1 - 1 file changed, 1 deletion(-) diff --git a/noxfile.py b/noxfile.py index 136f023c7b..6cd738f419 100644 --- a/noxfile.py +++ b/noxfile.py @@ -105,7 +105,6 @@ def tests_integrations(session: Session, integration: str) -> None: @session(python=["3.11"], name="Pydantic tests", tags=["tests"]) -# TODO: add pydantic 2.0 here :) @nox.parametrize("pydantic", ["1.10", "2.0.3"]) def test_pydantic(session: Session, pydantic: str) -> None: session.run_always("poetry", "install", external=True) From f17ee9458824edbc00e0e7bb9b2e2738a473d74e Mon Sep 17 00:00:00 2001 From: James Chua <30519287+thejaminator@users.noreply.github.com> Date: Mon, 24 Jul 2023 11:00:47 -0700 Subject: [PATCH 29/32] Update tests/experimental/pydantic/schema/test_defaults.py Co-authored-by: Patrick Arminio --- tests/experimental/pydantic/schema/test_defaults.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/experimental/pydantic/schema/test_defaults.py b/tests/experimental/pydantic/schema/test_defaults.py index a64f9574c9..60cc7ce266 100644 --- a/tests/experimental/pydantic/schema/test_defaults.py +++ b/tests/experimental/pydantic/schema/test_defaults.py @@ -172,7 +172,7 @@ class PydanticUser: class Query: @strawberry.field def a(self) -> PydanticUser: - ... + raise NotImplementedError schema = strawberry.Schema(Query) From 5afee6b8c21162cbed6ae683ffc245a744438671 Mon Sep 17 00:00:00 2001 From: jameschua Date: Mon, 24 Jul 2023 11:16:52 -0700 Subject: [PATCH 30/32] rename v2_compat -> _compat --- .../pydantic/{v2_compat.py => _compat.py} | 0 .../experimental/pydantic/error_type.py | 2 +- strawberry/experimental/pydantic/fields.py | 17 ++++++++-------- .../experimental/pydantic/object_type.py | 11 +++++----- strawberry/experimental/pydantic/utils.py | 2 +- strawberry/ext/mypy_plugin.py | 2 +- .../pydantic/schema/test_defaults.py | 4 ++-- .../pydantic/schema/test_mutation.py | 2 +- .../experimental/pydantic/test_conversion.py | 2 +- tests/experimental/pydantic/test_fields.py | 20 +++++++++---------- tests/experimental/pydantic/utils.py | 6 +++--- 11 files changed, 33 insertions(+), 35 deletions(-) rename strawberry/experimental/pydantic/{v2_compat.py => _compat.py} (100%) diff --git a/strawberry/experimental/pydantic/v2_compat.py b/strawberry/experimental/pydantic/_compat.py similarity index 100% rename from strawberry/experimental/pydantic/v2_compat.py rename to strawberry/experimental/pydantic/_compat.py diff --git a/strawberry/experimental/pydantic/error_type.py b/strawberry/experimental/pydantic/error_type.py index 6c46d4e588..8f868b0b10 100644 --- a/strawberry/experimental/pydantic/error_type.py +++ b/strawberry/experimental/pydantic/error_type.py @@ -22,7 +22,7 @@ get_strawberry_type_from_model, normalize_type, ) -from strawberry.experimental.pydantic.v2_compat import ( +from strawberry.experimental.pydantic._compat import ( CompatModelField, get_model_fields, lenient_issubclass, diff --git a/strawberry/experimental/pydantic/fields.py b/strawberry/experimental/pydantic/fields.py index dc54bdf8a6..a0a4f9e958 100644 --- a/strawberry/experimental/pydantic/fields.py +++ b/strawberry/experimental/pydantic/fields.py @@ -6,17 +6,16 @@ import pydantic from pydantic import BaseModel -from strawberry.experimental.pydantic.exceptions import ( - UnregisteredTypeException, - UnsupportedTypeError, -) -from strawberry.experimental.pydantic.v2_compat import ( - IS_PYDANTIC_V2, +from strawberry.experimental.pydantic._compat import ( get_args, get_origin, is_new_type, lenient_issubclass, - new_type_supertype, + new_type_supertype, IS_PYDANTIC_V1, +) +from strawberry.experimental.pydantic.exceptions import ( + UnregisteredTypeException, + UnsupportedTypeError, ) from strawberry.types.types import StrawberryObjectDefinition @@ -90,13 +89,13 @@ for field_name, type in ATTR_TO_TYPE_MAP.items() if hasattr(pydantic, field_name) } - if not IS_PYDANTIC_V2 + if IS_PYDANTIC_V1 else {} ) def get_basic_type(type_: Any) -> Type[Any]: - if not IS_PYDANTIC_V2: + if IS_PYDANTIC_V1: # only pydantic v1 has these if lenient_issubclass(type_, pydantic.ConstrainedInt): return int diff --git a/strawberry/experimental/pydantic/object_type.py b/strawberry/experimental/pydantic/object_type.py index b3da183c69..a5a443caed 100644 --- a/strawberry/experimental/pydantic/object_type.py +++ b/strawberry/experimental/pydantic/object_type.py @@ -18,6 +18,10 @@ from strawberry.annotation import StrawberryAnnotation from strawberry.auto import StrawberryAuto +from strawberry.experimental.pydantic._compat import ( + CompatModelField, + get_model_fields, IS_PYDANTIC_V1, +) from strawberry.experimental.pydantic.conversion import ( convert_pydantic_model_to_strawberry_class, convert_strawberry_class_to_pydantic_model, @@ -30,11 +34,6 @@ get_default_factory_for_field, get_private_fields, ) -from strawberry.experimental.pydantic.v2_compat import ( - IS_PYDANTIC_V2, - CompatModelField, - get_model_fields, -) from strawberry.field import StrawberryField from strawberry.object_type import _process_type, _wrap_dataclass from strawberry.types.type_resolver import _get_fields @@ -47,7 +46,7 @@ def get_type_for_field(field: CompatModelField, is_input: bool): # noqa: ANN201 outer_type = field.outer_type_ replaced_type = replace_types_recursively(outer_type, is_input) - if not IS_PYDANTIC_V2: + if IS_PYDANTIC_V1: # only pydantic v1 has this Optional logic should_add_optional: bool = field.allow_none if should_add_optional: diff --git a/strawberry/experimental/pydantic/utils.py b/strawberry/experimental/pydantic/utils.py index 1ae59e9965..c6b89548bc 100644 --- a/strawberry/experimental/pydantic/utils.py +++ b/strawberry/experimental/pydantic/utils.py @@ -19,7 +19,7 @@ BothDefaultAndDefaultFactoryDefinedError, UnregisteredTypeException, ) -from strawberry.experimental.pydantic.v2_compat import ( +from strawberry.experimental.pydantic._compat import ( PYDANTIC_MISSING_TYPE, CompatModelField, get_model_fields, diff --git a/strawberry/ext/mypy_plugin.py b/strawberry/ext/mypy_plugin.py index 5e798780ab..09a7c9a858 100644 --- a/strawberry/ext/mypy_plugin.py +++ b/strawberry/ext/mypy_plugin.py @@ -52,7 +52,7 @@ ) from mypy.typevars import fill_typevars from mypy.util import get_unique_redefinition_name -from strawberry.experimental.pydantic.v2_compat import IS_PYDANTIC_V1 +from strawberry.experimental.pydantic._compat import IS_PYDANTIC_V1 # Backwards compatible with the removal of `TypeVarDef` in mypy 0.920. try: diff --git a/tests/experimental/pydantic/schema/test_defaults.py b/tests/experimental/pydantic/schema/test_defaults.py index 60cc7ce266..c798c89b15 100644 --- a/tests/experimental/pydantic/schema/test_defaults.py +++ b/tests/experimental/pydantic/schema/test_defaults.py @@ -5,7 +5,7 @@ import strawberry from strawberry.printer import print_schema -from tests.experimental.pydantic.utils import needs_pydanticv2 +from tests.experimental.pydantic.utils import needs_pydantic_v2 def test_field_type_default(): @@ -159,7 +159,7 @@ def b(self, user: StrawberryUser) -> str: assert print_schema(schema) == textwrap.dedent(expected).strip() -@needs_pydanticv2 +@needs_pydantic_v2 def test_v2_explicit_default(): class User(pydantic.BaseModel): name: Optional[str] diff --git a/tests/experimental/pydantic/schema/test_mutation.py b/tests/experimental/pydantic/schema/test_mutation.py index 06bb00cba6..4baa4f35c0 100644 --- a/tests/experimental/pydantic/schema/test_mutation.py +++ b/tests/experimental/pydantic/schema/test_mutation.py @@ -3,7 +3,7 @@ import pydantic import strawberry -from strawberry.experimental.pydantic.v2_compat import IS_PYDANTIC_V2 +from strawberry.experimental.pydantic._compat import IS_PYDANTIC_V2 def test_mutation(): diff --git a/tests/experimental/pydantic/test_conversion.py b/tests/experimental/pydantic/test_conversion.py index 1269782626..1a3ca81b3f 100644 --- a/tests/experimental/pydantic/test_conversion.py +++ b/tests/experimental/pydantic/test_conversion.py @@ -14,7 +14,7 @@ BothDefaultAndDefaultFactoryDefinedError, ) from strawberry.experimental.pydantic.utils import get_default_factory_for_field -from strawberry.experimental.pydantic.v2_compat import ( +from strawberry.experimental.pydantic._compat import ( IS_PYDANTIC_V2, PYDANTIC_MISSING_TYPE, CompatModelField, diff --git a/tests/experimental/pydantic/test_fields.py b/tests/experimental/pydantic/test_fields.py index 33f386f8d9..02cdefcf44 100644 --- a/tests/experimental/pydantic/test_fields.py +++ b/tests/experimental/pydantic/test_fields.py @@ -7,13 +7,13 @@ from pydantic import BaseModel, ValidationError, conlist import strawberry -from strawberry.experimental.pydantic.v2_compat import IS_PYDANTIC_V1 +from strawberry.experimental.pydantic._compat import IS_PYDANTIC_V1 from strawberry.type import StrawberryOptional from strawberry.types.types import StrawberryObjectDefinition -from tests.experimental.pydantic.utils import needs_pydanticv1, needs_pydanticv2 +from tests.experimental.pydantic.utils import needs_pydantic_v1, needs_pydantic_v2 -@needs_pydanticv1 +@needs_pydantic_v1 @pytest.mark.parametrize( ("pydantic_type", "field_type"), [ @@ -54,7 +54,7 @@ class Type: assert field.type is field_type -@needs_pydanticv1 +@needs_pydantic_v1 @pytest.mark.parametrize( ("pydantic_type", "field_type"), [(pydantic.NoneStr, str)] if IS_PYDANTIC_V1 else [], @@ -77,7 +77,7 @@ class Type: assert field.type.of_type is field_type -@needs_pydanticv2 +@needs_pydantic_v2 def test_conint(): class Model(pydantic.BaseModel): field: pydantic.conint(lt=100) @@ -95,7 +95,7 @@ class Type: assert field.type is int -@needs_pydanticv1 +@needs_pydantic_v1 def test_confloat(): class Model(pydantic.BaseModel): field: pydantic.confloat(lt=100.5) @@ -113,7 +113,7 @@ class Type: assert field.type is float -@needs_pydanticv1 +@needs_pydantic_v1 def test_constr(): class Model(pydantic.BaseModel): field: pydantic.constr(max_length=100) @@ -131,7 +131,7 @@ class Type: assert field.type is str -@needs_pydanticv1 +@needs_pydantic_v1 def test_constrained_list(): class User(BaseModel): friends: conlist(str, min_items=1) @@ -159,7 +159,7 @@ class UserType: data.to_pydantic() -@needs_pydanticv1 +@needs_pydantic_v1 def test_constrained_list_nested(): class User(BaseModel): friends: conlist(conlist(int, min_items=1), min_items=1) @@ -175,7 +175,7 @@ class UserType: ) -@needs_pydanticv1 +@needs_pydantic_v1 @pytest.mark.parametrize( "pydantic_type", [ diff --git a/tests/experimental/pydantic/utils.py b/tests/experimental/pydantic/utils.py index e53458225c..c17cf2ba11 100644 --- a/tests/experimental/pydantic/utils.py +++ b/tests/experimental/pydantic/utils.py @@ -1,6 +1,6 @@ import pytest -from strawberry.experimental.pydantic.v2_compat import IS_PYDANTIC_V2 +from strawberry.experimental.pydantic._compat import IS_PYDANTIC_V2 -needs_pydanticv2 = pytest.mark.skipif(not IS_PYDANTIC_V2, reason="requires Pydantic v2") -needs_pydanticv1 = pytest.mark.skipif(IS_PYDANTIC_V2, reason="requires Pydantic v1") +needs_pydantic_v2 = pytest.mark.skipif(not IS_PYDANTIC_V2, reason="requires Pydantic v2") +needs_pydantic_v1 = pytest.mark.skipif(IS_PYDANTIC_V2, reason="requires Pydantic v1") From db26d26f3dbd2e9fd30643209ce8799dc40b5a56 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 24 Jul 2023 18:17:17 +0000 Subject: [PATCH 31/32] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- strawberry/experimental/pydantic/error_type.py | 10 +++++----- strawberry/experimental/pydantic/fields.py | 3 ++- strawberry/experimental/pydantic/object_type.py | 3 ++- strawberry/experimental/pydantic/utils.py | 10 +++++----- tests/experimental/pydantic/test_conversion.py | 10 +++++----- tests/experimental/pydantic/utils.py | 4 +++- 6 files changed, 22 insertions(+), 18 deletions(-) diff --git a/strawberry/experimental/pydantic/error_type.py b/strawberry/experimental/pydantic/error_type.py index 8f868b0b10..ec7d827cc0 100644 --- a/strawberry/experimental/pydantic/error_type.py +++ b/strawberry/experimental/pydantic/error_type.py @@ -17,16 +17,16 @@ from pydantic import BaseModel from strawberry.auto import StrawberryAuto -from strawberry.experimental.pydantic.utils import ( - get_private_fields, - get_strawberry_type_from_model, - normalize_type, -) from strawberry.experimental.pydantic._compat import ( CompatModelField, get_model_fields, lenient_issubclass, ) +from strawberry.experimental.pydantic.utils import ( + get_private_fields, + get_strawberry_type_from_model, + normalize_type, +) from strawberry.object_type import _process_type, _wrap_dataclass from strawberry.types.type_resolver import _get_fields from strawberry.utils.typing import get_list_annotation, is_list diff --git a/strawberry/experimental/pydantic/fields.py b/strawberry/experimental/pydantic/fields.py index a0a4f9e958..8ef4417c0e 100644 --- a/strawberry/experimental/pydantic/fields.py +++ b/strawberry/experimental/pydantic/fields.py @@ -7,11 +7,12 @@ from pydantic import BaseModel from strawberry.experimental.pydantic._compat import ( + IS_PYDANTIC_V1, get_args, get_origin, is_new_type, lenient_issubclass, - new_type_supertype, IS_PYDANTIC_V1, + new_type_supertype, ) from strawberry.experimental.pydantic.exceptions import ( UnregisteredTypeException, diff --git a/strawberry/experimental/pydantic/object_type.py b/strawberry/experimental/pydantic/object_type.py index a5a443caed..f7e87ed6ef 100644 --- a/strawberry/experimental/pydantic/object_type.py +++ b/strawberry/experimental/pydantic/object_type.py @@ -19,8 +19,9 @@ from strawberry.annotation import StrawberryAnnotation from strawberry.auto import StrawberryAuto from strawberry.experimental.pydantic._compat import ( + IS_PYDANTIC_V1, CompatModelField, - get_model_fields, IS_PYDANTIC_V1, + get_model_fields, ) from strawberry.experimental.pydantic.conversion import ( convert_pydantic_model_to_strawberry_class, diff --git a/strawberry/experimental/pydantic/utils.py b/strawberry/experimental/pydantic/utils.py index c6b89548bc..02b2740b71 100644 --- a/strawberry/experimental/pydantic/utils.py +++ b/strawberry/experimental/pydantic/utils.py @@ -14,17 +14,17 @@ cast, ) -from strawberry.experimental.pydantic.exceptions import ( - AutoFieldsNotInBaseModelError, - BothDefaultAndDefaultFactoryDefinedError, - UnregisteredTypeException, -) from strawberry.experimental.pydantic._compat import ( PYDANTIC_MISSING_TYPE, CompatModelField, get_model_fields, smart_deepcopy, ) +from strawberry.experimental.pydantic.exceptions import ( + AutoFieldsNotInBaseModelError, + BothDefaultAndDefaultFactoryDefinedError, + UnregisteredTypeException, +) from strawberry.private import is_private from strawberry.unset import UNSET from strawberry.utils.typing import ( diff --git a/tests/experimental/pydantic/test_conversion.py b/tests/experimental/pydantic/test_conversion.py index 1a3ca81b3f..78aa1d778a 100644 --- a/tests/experimental/pydantic/test_conversion.py +++ b/tests/experimental/pydantic/test_conversion.py @@ -9,16 +9,16 @@ from pydantic import BaseModel, Field, ValidationError import strawberry -from strawberry.experimental.pydantic.exceptions import ( - AutoFieldsNotInBaseModelError, - BothDefaultAndDefaultFactoryDefinedError, -) -from strawberry.experimental.pydantic.utils import get_default_factory_for_field from strawberry.experimental.pydantic._compat import ( IS_PYDANTIC_V2, PYDANTIC_MISSING_TYPE, CompatModelField, ) +from strawberry.experimental.pydantic.exceptions import ( + AutoFieldsNotInBaseModelError, + BothDefaultAndDefaultFactoryDefinedError, +) +from strawberry.experimental.pydantic.utils import get_default_factory_for_field from strawberry.type import StrawberryList, StrawberryOptional from strawberry.types.types import StrawberryObjectDefinition diff --git a/tests/experimental/pydantic/utils.py b/tests/experimental/pydantic/utils.py index c17cf2ba11..229d1c1a93 100644 --- a/tests/experimental/pydantic/utils.py +++ b/tests/experimental/pydantic/utils.py @@ -2,5 +2,7 @@ from strawberry.experimental.pydantic._compat import IS_PYDANTIC_V2 -needs_pydantic_v2 = pytest.mark.skipif(not IS_PYDANTIC_V2, reason="requires Pydantic v2") +needs_pydantic_v2 = pytest.mark.skipif( + not IS_PYDANTIC_V2, reason="requires Pydantic v2" +) needs_pydantic_v1 = pytest.mark.skipif(IS_PYDANTIC_V2, reason="requires Pydantic v1") From 01182e217e608964debadf0acadf4cf75fa8e9a3 Mon Sep 17 00:00:00 2001 From: jameschua Date: Mon, 24 Jul 2023 21:45:05 -0700 Subject: [PATCH 32/32] ignore mypy windows tests --- .github/workflows/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 91ba53c55e..7682efeae3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -165,9 +165,9 @@ jobs: # we use poetry directly instead of nox since we want to # test all integrations at once on windows + # but we want to exclude tests/mypy since we are using an old version of pydantic - run: | - poetry run pytest --cov=. --cov-append --cov-report=xml -n auto --showlocals -vv - + poetry run pytest --cov=. --cov-append --cov-report=xml -n auto --showlocals --ignore tests/mypy -vv - name: coverage xml run: coverage xml -i if: ${{ always() }}