Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

wip: Initial work for first class pydantic usage #3268

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
181 changes: 181 additions & 0 deletions strawberry/experimental/pydantic/pydantic_first_class.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
import dataclasses
from typing import Callable, Dict, List, Optional, Sequence, Type

from pydantic import BaseModel

from strawberry.annotation import StrawberryAnnotation
from strawberry.experimental.pydantic._compat import CompatModelField, get_model_fields
from strawberry.experimental.pydantic.conversion_types import PydanticModel
from strawberry.experimental.pydantic.fields import replace_types_recursively
from strawberry.experimental.pydantic.utils import get_default_factory_for_field
from strawberry.field import StrawberryField
from strawberry.object_type import _get_interfaces
from strawberry.types.types import StrawberryObjectDefinition
from strawberry.utils.deprecations import DEPRECATION_MESSAGES, DeprecatedDescriptor
from strawberry.utils.str_converters import to_camel_case


def _get_strawberry_fields_from_basemodel(
model: Type[BaseModel], is_input: bool, use_pydantic_alias: bool
) -> List[StrawberryField]:
"""Get all the strawberry fields off a pydantic BaseModel cls
This function returns a list of StrawberryFields (one for each field item), while
also paying attention the name and typing of the field.
model:
A pure pydantic field. Will not have a StrawberryField; one will need to
be created in this function. Type annotation is required.
"""
fields: list[StrawberryField] = []

Check warning on line 28 in strawberry/experimental/pydantic/pydantic_first_class.py

View check run for this annotation

Codecov / codecov/patch

strawberry/experimental/pydantic/pydantic_first_class.py#L28

Added line #L28 was not covered by tests

# BaseModel already has fields, so we need to get them from there
model_fields: Dict[str, CompatModelField] = get_model_fields(model)

Check warning on line 31 in strawberry/experimental/pydantic/pydantic_first_class.py

View check run for this annotation

Codecov / codecov/patch

strawberry/experimental/pydantic/pydantic_first_class.py#L31

Added line #L31 was not covered by tests
for name, field in model_fields.items():
converted_type = replace_types_recursively(field.outer_type_, is_input=is_input)

Check warning on line 33 in strawberry/experimental/pydantic/pydantic_first_class.py

View check run for this annotation

Codecov / codecov/patch

strawberry/experimental/pydantic/pydantic_first_class.py#L33

Added line #L33 was not covered by tests
if field.allow_none:
converted_type = Optional[converted_type]
graphql_before_case = (

Check warning on line 36 in strawberry/experimental/pydantic/pydantic_first_class.py

View check run for this annotation

Codecov / codecov/patch

strawberry/experimental/pydantic/pydantic_first_class.py#L35-L36

Added lines #L35 - L36 were not covered by tests
field.alias or field.name if use_pydantic_alias else field.name
)
camel_case_name = to_camel_case(graphql_before_case)
fields.append(

Check warning on line 40 in strawberry/experimental/pydantic/pydantic_first_class.py

View check run for this annotation

Codecov / codecov/patch

strawberry/experimental/pydantic/pydantic_first_class.py#L39-L40

Added lines #L39 - L40 were not covered by tests
StrawberryField(
python_name=name,
graphql_name=camel_case_name,
# always unset because we use default_factory instead
default=dataclasses.MISSING,
default_factory=get_default_factory_for_field(field),
type_annotation=StrawberryAnnotation.from_annotation(converted_type),
description=field.description,
deprecation_reason=None,
permission_classes=[],
directives=[],
metadata={},
)
)

return fields

Check warning on line 56 in strawberry/experimental/pydantic/pydantic_first_class.py

View check run for this annotation

Codecov / codecov/patch

strawberry/experimental/pydantic/pydantic_first_class.py#L56

Added line #L56 was not covered by tests


def first_class_process_basemodel(
model: Type[BaseModel],
*,
name: Optional[str] = None,
is_input: bool = False,
is_interface: bool = False,
description: Optional[str] = None,
directives: Optional[Sequence[object]] = (),
extend: bool = False,
use_pydantic_alias: bool = True,
):
name = name or to_camel_case(model.__name__)

Check warning on line 70 in strawberry/experimental/pydantic/pydantic_first_class.py

View check run for this annotation

Codecov / codecov/patch

strawberry/experimental/pydantic/pydantic_first_class.py#L70

Added line #L70 was not covered by tests

interfaces = _get_interfaces(model)
fields: List[StrawberryField] = _get_strawberry_fields_from_basemodel(

Check warning on line 73 in strawberry/experimental/pydantic/pydantic_first_class.py

View check run for this annotation

Codecov / codecov/patch

strawberry/experimental/pydantic/pydantic_first_class.py#L72-L73

Added lines #L72 - L73 were not covered by tests
model, is_input=is_input, use_pydantic_alias=use_pydantic_alias
)
is_type_of = getattr(model, "is_type_of", None)
resolve_type = getattr(model, "resolve_type", None)

Check warning on line 77 in strawberry/experimental/pydantic/pydantic_first_class.py

View check run for this annotation

Codecov / codecov/patch

strawberry/experimental/pydantic/pydantic_first_class.py#L76-L77

Added lines #L76 - L77 were not covered by tests

model.__strawberry_definition__ = StrawberryObjectDefinition(

Check warning on line 79 in strawberry/experimental/pydantic/pydantic_first_class.py

View check run for this annotation

Codecov / codecov/patch

strawberry/experimental/pydantic/pydantic_first_class.py#L79

Added line #L79 was not covered by tests
name=name,
is_input=is_input,
is_interface=is_interface,
interfaces=interfaces,
description=description,
directives=directives,
origin=model,
extend=extend,
fields=fields,
is_type_of=is_type_of,
resolve_type=resolve_type,
)
# TODO: remove when deprecating _type_definition
DeprecatedDescriptor(

Check warning on line 93 in strawberry/experimental/pydantic/pydantic_first_class.py

View check run for this annotation

Codecov / codecov/patch

strawberry/experimental/pydantic/pydantic_first_class.py#L93

Added line #L93 was not covered by tests
DEPRECATION_MESSAGES._TYPE_DEFINITION,
model.__strawberry_definition__,
"_type_definition",
).inject(model)

return model

Check warning on line 99 in strawberry/experimental/pydantic/pydantic_first_class.py

View check run for this annotation

Codecov / codecov/patch

strawberry/experimental/pydantic/pydantic_first_class.py#L99

Added line #L99 was not covered by tests


def register_first_class(
model: Type[PydanticModel],
*,
name: Optional[str] = None,
is_input: bool = False,
is_interface: bool = False,
description: Optional[str] = None,
use_pydantic_alias: bool = True,
) -> Type[PydanticModel]:
"""A function for registering a pydantic model as a first class strawberry type.
This is useful when your pydantic model is some code that you can't edit
(e.g. from a third party library).

Example:
class User(BaseModel):
id: int
name: str

register_first_class(User)

@strawberry.type
class Query:
@strawberry.field
def user(self) -> User:
return User(id=1, name="Patrick")
"""

first_class_process_basemodel(

Check warning on line 129 in strawberry/experimental/pydantic/pydantic_first_class.py

View check run for this annotation

Codecov / codecov/patch

strawberry/experimental/pydantic/pydantic_first_class.py#L129

Added line #L129 was not covered by tests
model,
name=name or to_camel_case(model.__name__),
is_input=is_input,
is_interface=is_interface,
description=description,
use_pydantic_alias=use_pydantic_alias,
)

if is_input:
# TODO: Probably should check if the name clashes with an existing type?
model._strawberry_input_type = model # type: ignore

Check warning on line 140 in strawberry/experimental/pydantic/pydantic_first_class.py

View check run for this annotation

Codecov / codecov/patch

strawberry/experimental/pydantic/pydantic_first_class.py#L140

Added line #L140 was not covered by tests
else:
model._strawberry_type = model # type: ignore

Check warning on line 142 in strawberry/experimental/pydantic/pydantic_first_class.py

View check run for this annotation

Codecov / codecov/patch

strawberry/experimental/pydantic/pydantic_first_class.py#L142

Added line #L142 was not covered by tests

return model

Check warning on line 144 in strawberry/experimental/pydantic/pydantic_first_class.py

View check run for this annotation

Codecov / codecov/patch

strawberry/experimental/pydantic/pydantic_first_class.py#L144

Added line #L144 was not covered by tests


def first_class(
name: Optional[str] = None,
is_input: bool = False,
is_interface: bool = False,
description: Optional[str] = None,
use_pydantic_alias: bool = True,
) -> Callable[[Type[PydanticModel]], Type[PydanticModel]]:
"""A decorator to make a pydantic class work on strawberry without creating
a separate strawberry type.

Example:
@strawberry.experimental.pydantic.first_class()
class User(BaseModel):
id: int
name: str

@strawberry.type
class Query:
@strawberry.field
def user(self) -> User:
return User(id=1, name="Patrick")

"""

def wrap(model: Type[PydanticModel]) -> Type[PydanticModel]:
return register_first_class(

Check warning on line 172 in strawberry/experimental/pydantic/pydantic_first_class.py

View check run for this annotation

Codecov / codecov/patch

strawberry/experimental/pydantic/pydantic_first_class.py#L171-L172

Added lines #L171 - L172 were not covered by tests
model,
name=name,
is_input=is_input,
is_interface=is_interface,
description=description,
use_pydantic_alias=use_pydantic_alias,
)

return wrap

Check warning on line 181 in strawberry/experimental/pydantic/pydantic_first_class.py

View check run for this annotation

Codecov / codecov/patch

strawberry/experimental/pydantic/pydantic_first_class.py#L181

Added line #L181 was not covered by tests
214 changes: 214 additions & 0 deletions tests/experimental/pydantic_first_class/schema/test_mutation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
from typing import Dict, List, Union

import pydantic
import pytest

import strawberry
from strawberry.experimental.pydantic._compat import IS_PYDANTIC_V2
from strawberry.experimental.pydantic.pydantic_first_class import first_class


def test_mutation():
@first_class(is_input=True)
class CreateUserInput(pydantic.BaseModel):
name: pydantic.constr(min_length=2)

Check warning on line 14 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L13-L14

Added lines #L13 - L14 were not covered by tests

@first_class()
class UserType(pydantic.BaseModel):
name: str

Check warning on line 18 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L17-L18

Added lines #L17 - L18 were not covered by tests

@strawberry.type
class Query:
h: str

Check warning on line 22 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L21-L22

Added lines #L21 - L22 were not covered by tests

@strawberry.type
class Mutation:
@strawberry.mutation
def create_user(self, input: CreateUserInput) -> UserType:
return UserType(name=input.name)

Check warning on line 28 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L25-L28

Added lines #L25 - L28 were not covered by tests

schema = strawberry.Schema(query=Query, mutation=Mutation)

Check warning on line 30 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L30

Added line #L30 was not covered by tests

query = """

Check warning on line 32 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L32

Added line #L32 was not covered by tests
mutation {
createUser(input: { name: "Patrick" }) {
name
}
}
"""

result = schema.execute_sync(query)

Check warning on line 40 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L40

Added line #L40 was not covered by tests

assert not result.errors
assert result.data["createUser"]["name"] == "Patrick"

Check warning on line 43 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L42-L43

Added lines #L42 - L43 were not covered by tests


def test_mutation_with_validation():
@first_class(is_input=True)
class CreateUserInput(pydantic.BaseModel):
name: pydantic.constr(min_length=2)

Check warning on line 49 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L48-L49

Added lines #L48 - L49 were not covered by tests

@first_class()
class UserType(pydantic.BaseModel):
name: str

Check warning on line 53 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L52-L53

Added lines #L52 - L53 were not covered by tests

@strawberry.type
class Query:
h: str

Check warning on line 57 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L56-L57

Added lines #L56 - L57 were not covered by tests

@strawberry.type
class Mutation:
@strawberry.mutation
def create_user(self, input: CreateUserInput) -> UserType:
return UserType(name=input.name)

Check warning on line 63 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L60-L63

Added lines #L60 - L63 were not covered by tests

schema = strawberry.Schema(query=Query, mutation=Mutation)

Check warning on line 65 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L65

Added line #L65 was not covered by tests

query = """

Check warning on line 67 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L67

Added line #L67 was not covered by tests
mutation {
createUser(input: { name: "P" }) {
name
}
}
"""

result = schema.execute_sync(query)

Check warning on line 75 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L75

Added line #L75 was not covered by tests

if IS_PYDANTIC_V2:
assert result.errors[0].message == (

Check warning on line 78 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L78

Added line #L78 was not covered by tests
"1 validation error for CreateUserInput\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 == (

Check warning on line 87 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L87

Added line #L87 was not covered by tests
"1 validation error for CreateUserInput\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():
@first_class(is_input=True)
class HobbyInput(pydantic.BaseModel):
name: pydantic.constr(min_length=2)

Check warning on line 96 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L95-L96

Added lines #L95 - L96 were not covered by tests

@first_class(is_input=True)
class CreateUserInput(pydantic.BaseModel):
hobby: HobbyInput

Check warning on line 100 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L99-L100

Added lines #L99 - L100 were not covered by tests

class UserModel(pydantic.BaseModel):
name: str

Check warning on line 103 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L102-L103

Added lines #L102 - L103 were not covered by tests

@strawberry.experimental.pydantic.type(UserModel)
class UserType:
name: strawberry.auto

Check warning on line 107 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L106-L107

Added lines #L106 - L107 were not covered by tests

@strawberry.type
class Query:
h: str

Check warning on line 111 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L110-L111

Added lines #L110 - L111 were not covered by tests

@strawberry.type
class Mutation:
@strawberry.mutation
def create_user(self, input: CreateUserInput) -> UserType:
return UserType(name=input.hobby.name)

Check warning on line 117 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L114-L117

Added lines #L114 - L117 were not covered by tests

schema = strawberry.Schema(query=Query, mutation=Mutation)

Check warning on line 119 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L119

Added line #L119 was not covered by tests

query = """

Check warning on line 121 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L121

Added line #L121 was not covered by tests
mutation {
createUser(input: { hobby: { name: "P" } }) {
name
}
}
"""

result = schema.execute_sync(query)

Check warning on line 129 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L129

Added line #L129 was not covered by tests

if IS_PYDANTIC_V2:
assert result.errors[0].message == (

Check warning on line 132 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L132

Added line #L132 was not covered by tests
"1 validation error for HobbyInput\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 == (

Check warning on line 142 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L142

Added line #L142 was not covered by tests
"1 validation error for HobbyInput\nname\n"
" ensure this value has at least 2 characters "
"(type=value_error.any_str.min_length; limit_value=2)"
)


@pytest.mark.xfail(
reason="""No way to manually handle errors
the validation goes boom in convert_argument, not in the create_user resolver"""
)
def test_mutation_with_validation_and_error_type():
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue 2: no way to manually handle validation errors for now

@first_class(is_input=True)
class CreateUserInput(pydantic.BaseModel):
name: pydantic.constr(min_length=2)

Check warning on line 156 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L155-L156

Added lines #L155 - L156 were not covered by tests

@first_class()
class UserType(pydantic.BaseModel):
name: str

Check warning on line 160 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L159-L160

Added lines #L159 - L160 were not covered by tests

@first_class()
class UserError(pydantic.BaseModel):
name: str

Check warning on line 164 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L163-L164

Added lines #L163 - L164 were not covered by tests

@strawberry.type
class Query:
h: str

Check warning on line 168 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L167-L168

Added lines #L167 - L168 were not covered by tests

@strawberry.type
class Mutation:
@strawberry.mutation
def create_user(self, input: CreateUserInput) -> Union[UserType, UserError]:
try:
data = input
except pydantic.ValidationError as e:
args: Dict[str, List[str]] = {}

Check warning on line 177 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L171-L177

Added lines #L171 - L177 were not covered by tests
for error in e.errors():
field = error["loc"][0] # currently doesn't support nested errors
field_errors = args.get(field, [])
field_errors.append(error["msg"])
args[field] = field_errors
return UserError(**args)

Check warning on line 183 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L179-L183

Added lines #L179 - L183 were not covered by tests
else:
return UserType(name=data.name)

Check warning on line 185 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L185

Added line #L185 was not covered by tests

schema = strawberry.Schema(query=Query, mutation=Mutation)

Check warning on line 187 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L187

Added line #L187 was not covered by tests

query = """

Check warning on line 189 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L189

Added line #L189 was not covered by tests
mutation {
createUser(input: { name: "P" }) {
... on UserType {
name
}
... on UserError {
nameErrors: name
}
}
}
"""

result = schema.execute_sync(query)

Check warning on line 202 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L202

Added line #L202 was not covered by tests

assert result.errors is None
assert result.data["createUser"].get("name") is None

Check warning on line 205 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L204-L205

Added lines #L204 - L205 were not covered by tests

if IS_PYDANTIC_V2:
assert result.data["createUser"]["nameErrors"] == [

Check warning on line 208 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L208

Added line #L208 was not covered by tests
("String should have at least 2 characters")
]
else:
assert result.data["createUser"]["nameErrors"] == [

Check warning on line 212 in tests/experimental/pydantic_first_class/schema/test_mutation.py

View check run for this annotation

Codecov / codecov/patch

tests/experimental/pydantic_first_class/schema/test_mutation.py#L212

Added line #L212 was not covered by tests
("ensure this value has at least 2 characters")
]
Loading
Loading