Skip to content

Commit

Permalink
Merge pull request #42 from necaris/fix-self-referencing
Browse files Browse the repository at this point in the history
Fix self-referencing case
  • Loading branch information
necaris authored Sep 20, 2020
2 parents a59aa31 + abe3741 commit f7686b2
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 23 deletions.
28 changes: 18 additions & 10 deletions graphene_pydantic/converters.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import collections.abc
import datetime
import decimal
import inspect
import enum
import sys
import typing as T
Expand Down Expand Up @@ -199,7 +200,10 @@ def find_graphene_type(
return List
elif registry and registry.get_type_for_model(type_):
return registry.get_type_for_model(type_)
elif registry and isinstance(type_, BaseModel):
elif registry and (
isinstance(type_, BaseModel)
or (inspect.isclass(type_) and issubclass(type_, BaseModel))
):
# If it's a Pydantic model that hasn't yet been wrapped with a ObjectType,
# we can put a placeholder in and request that `resolve_placeholders()`
# be called to update it.
Expand Down Expand Up @@ -262,15 +266,19 @@ def convert_generic_python_type(
return convert_union_type(
type_, field, registry, parent_type=parent_type, model=model
)
elif origin in (
T.Tuple,
T.List,
T.Set,
T.Collection,
T.Iterable,
list,
set,
) or issubclass(origin, collections.abc.Sequence):
elif (
origin
in (
T.Tuple,
T.List,
T.Set,
T.Collection,
T.Iterable,
list,
set,
)
or issubclass(origin, collections.abc.Sequence)
):
# TODO: find a better way of divining that the origin is sequence-like
inner_types = getattr(type_, "__args__", [])
if not inner_types: # pragma: no cover # this really should be impossible
Expand Down
45 changes: 32 additions & 13 deletions tests/test_converters.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import graphene_pydantic.converters as converters
from graphene_pydantic.converters import ConversionError, convert_pydantic_field
from graphene_pydantic.objecttype import PydanticObjectType
from graphene_pydantic.registry import get_global_registry
from graphene_pydantic.registry import get_global_registry, Placeholder


def _get_field_from_spec(name, type_spec_or_default):
Expand Down Expand Up @@ -141,15 +141,34 @@ class Meta:
assert field.type == GraphFoo


def test_unknown():
with pytest.raises(ConversionError) as exc:
_convert_field_from_spec("attr", (create_model("Model", size=int), None))
assert "Don't know how to convert" in exc.value.args[0]
if pydantic.version.VERSION < "1.0":
assert "Field(attr type=Model default=None)" in exc.value.args[0]
else:
# this worked at least as of 1.1
assert (
"ModelField(name='attr', type=Optional[Model], required=False, default=None)"
in exc.value.args[0]
)
def test_unresolved_placeholders():
# no errors should be raised here -- instead a placeholder is created
field = _convert_field_from_spec("attr", (create_model("Model", size=int), None))
assert any(
isinstance(x, Placeholder)
for x in get_global_registry(PydanticObjectType)._registry.values()
)
# this is a runtime error waiting to happen, but what can we do about it?
assert field.type is None


def test_self_referencing():
class NodeModel(BaseModel):
id: int
name: str
# nodes: Union['NodeModel', None]
nodes: T.Optional["NodeModel"]

NodeModel.update_forward_refs()

class NodeModelSchema(PydanticObjectType):
class Meta: # noqa: too-few-public-methods
model = NodeModel

@classmethod
def is_type_of(cls, root, info):
return isinstance(root, (cls, NodeModel))

NodeModelSchema.resolve_placeholders()

assert NodeModelSchema._meta.model is NodeModel

0 comments on commit f7686b2

Please sign in to comment.