Skip to content

Commit 91762db

Browse files
committed
Improve test coverage
Signed-off-by: Erik Wrede <[email protected]>
1 parent bc90e57 commit 91762db

File tree

4 files changed

+149
-14
lines changed

4 files changed

+149
-14
lines changed

graphene_sqlalchemy/converter.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,12 @@ def convert_sqlalchemy_hybrid_property_type(arg: Any):
307307
if existing_graphql_type:
308308
return existing_graphql_type
309309

310+
if isinstance(arg, type(graphene.ObjectType)):
311+
return arg
312+
313+
if isinstance(arg, type(graphene.Scalar)):
314+
return arg
315+
310316
# No valid type found, warn and fall back to graphene.String
311317
warnings.warn(
312318
(f"I don't know how to generate a GraphQL type out of a \"{arg}\" type."
@@ -407,7 +413,7 @@ def convert_sqlalchemy_hybrid_property_union(arg):
407413
return graphene_types[0]
408414

409415
# Now check if every type is instance of an ObjectType
410-
if not all(isinstance(graphene_type, graphene.ObjectType) for graphene_type in graphene_types):
416+
if not all(isinstance(graphene_type, type(graphene.ObjectType)) for graphene_type in graphene_types):
411417
raise ValueError("Cannot convert hybrid_property Union to graphene.Union: the Union contains scalars. "
412418
"Please add the corresponding hybrid_property to the excluded fields in the ObjectType, "
413419
"or use an ORMField to override this behaviour.")

graphene_sqlalchemy/registry.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from collections import defaultdict
2-
from typing import List
2+
from typing import List, Type
33

44
from sqlalchemy.types import Enum as SQLAlchemyEnumType
55

@@ -89,22 +89,22 @@ def register_sort_enum(self, obj_type, sort_enum: Enum):
8989
def get_sort_enum_for_object_type(self, obj_type: graphene.ObjectType):
9090
return self._registry_sort_enums.get(obj_type)
9191

92-
def register_union_type(self, union: graphene.Union, obj_types: List[graphene.ObjectType]):
92+
def register_union_type(self, union: graphene.Union, obj_types: List[Type[graphene.ObjectType]]):
9393
if not isinstance(union, graphene.Union):
9494
raise TypeError(
9595
"Expected graphene.Union, but got: {!r}".format(union)
9696
)
9797

9898
for obj_type in obj_types:
99-
if not isinstance(obj_type, graphene.ObjectType):
99+
if not isinstance(obj_type, type(graphene.ObjectType)):
100100
raise TypeError(
101101
"Expected Graphene ObjectType, but got: {!r}".format(obj_type)
102102
)
103103

104-
self._registry_enums[tuple(sorted(obj_types))] = union
104+
self._registry_unions[frozenset(obj_types)] = union
105105

106-
def get_union_for_object_types(self, obj_types: List[graphene.ObjectType]):
107-
self._registry_unions.get(tuple(sorted(obj_types)))
106+
def get_union_for_object_types(self, obj_types : List[Type[graphene.ObjectType]]):
107+
return self._registry_unions.get(frozenset(obj_types))
108108

109109

110110
registry = None

graphene_sqlalchemy/tests/test_converter.py

+81-6
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import graphene
1616
from graphene.types.structures import Structure
1717

18-
1918
from ..converter import (convert_sqlalchemy_column,
2019
convert_sqlalchemy_composite,
2120
convert_sqlalchemy_hybrid_method,
@@ -94,11 +93,63 @@ def prop_method() -> int | None:
9493

9594

9695
@pytest.mark.skipif(sys.version_info < (3, 10), reason="|-Style Unions are unsupported in python < 3.10")
97-
def test_should_unknown_sqlalchemy_field_raise_exception_310():
98-
re_err = "Don't know how to convert the SQLAlchemy field"
99-
with pytest.raises(Exception, match=re_err):
100-
# support legacy Binary type and subsequent LargeBinary
101-
get_field(getattr(types, 'LargeBinary', types.BINARY)())
96+
def test_should_union_work_310():
97+
reg = Registry()
98+
99+
class PetType(SQLAlchemyObjectType):
100+
class Meta:
101+
model = Pet
102+
registry = reg
103+
104+
class ShoppingCartType(SQLAlchemyObjectType):
105+
class Meta:
106+
model = ShoppingCartItem
107+
registry = reg
108+
109+
@hybrid_property
110+
def prop_method() -> Union[PetType, ShoppingCartType]:
111+
return None
112+
113+
@hybrid_property
114+
def prop_method_2() -> Union[ShoppingCartType, PetType]:
115+
return None
116+
117+
field_type_1 = get_hybrid_property_type(prop_method).type
118+
field_type_2 = get_hybrid_property_type(prop_method_2).type
119+
120+
assert isinstance(field_type_1, graphene.Union)
121+
assert field_type_1 is field_type_2
122+
123+
# TODO verify types of the union
124+
125+
126+
@pytest.mark.skipif(sys.version_info < (3, 10), reason="|-Style Unions are unsupported in python < 3.10")
127+
def test_should_union_work_310():
128+
reg = Registry()
129+
130+
class PetType(SQLAlchemyObjectType):
131+
class Meta:
132+
model = Pet
133+
registry = reg
134+
135+
class ShoppingCartType(SQLAlchemyObjectType):
136+
class Meta:
137+
model = ShoppingCartItem
138+
registry = reg
139+
140+
@hybrid_property
141+
def prop_method() -> PetType | ShoppingCartType:
142+
return None
143+
144+
@hybrid_property
145+
def prop_method_2() -> ShoppingCartType | PetType:
146+
return None
147+
148+
field_type_1 = get_hybrid_property_type(prop_method).type
149+
field_type_2 = get_hybrid_property_type(prop_method_2).type
150+
151+
assert isinstance(field_type_1, graphene.Union)
152+
assert field_type_1 is field_type_2
102153

103154

104155
def test_should_datetime_convert_datetime():
@@ -129,6 +180,30 @@ def test_should_unicodetext_convert_string():
129180
assert get_field(types.UnicodeText()).type == graphene.String
130181

131182

183+
def test_should_tsvector_convert_string():
184+
assert get_field(sqa_utils.TSVectorType()).type == graphene.String
185+
186+
187+
def test_should_email_convert_string():
188+
assert get_field(sqa_utils.EmailType()).type == graphene.String
189+
190+
191+
def test_should_URL_convert_string():
192+
assert get_field(sqa_utils.URLType()).type == graphene.String
193+
194+
195+
def test_should_IPaddress_convert_string():
196+
assert get_field(sqa_utils.IPAddressType()).type == graphene.String
197+
198+
199+
def test_should_inet_convert_string():
200+
assert get_field(postgresql.INET()).type == graphene.String
201+
202+
203+
def test_should_cidr_convert_string():
204+
assert get_field(postgresql.CIDR()).type == graphene.String
205+
206+
132207
def test_should_enum_convert_enum():
133208
field = get_field(types.Enum(enum.Enum("TwoNumbers", ("one", "two"))))
134209
field_type = field.type()

graphene_sqlalchemy/tests/test_registry.py

+55-1
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22
from sqlalchemy.types import Enum as SQLAlchemyEnum
33

44
from graphene import Enum as GrapheneEnum
5+
import graphene
56

67
from ..registry import Registry
78
from ..types import SQLAlchemyObjectType
89
from ..utils import EnumValue
9-
from .models import Pet
10+
from .models import Pet, Reporter
1011

1112

1213
def test_register_object_type():
@@ -126,3 +127,56 @@ class Meta:
126127
re_err = r"Expected Graphene Enum, but got: .*PetType.*"
127128
with pytest.raises(TypeError, match=re_err):
128129
reg.register_sort_enum(PetType, PetType)
130+
131+
132+
def test_register_union():
133+
reg = Registry()
134+
135+
class PetType(SQLAlchemyObjectType):
136+
class Meta:
137+
model = Pet
138+
registry = reg
139+
140+
class ReporterType(SQLAlchemyObjectType):
141+
class Meta:
142+
model = Reporter
143+
144+
union_types = [PetType, ReporterType]
145+
union = graphene.Union('ReporterPet', tuple(union_types))
146+
147+
reg.register_union_type(union, union_types)
148+
149+
assert reg.get_union_for_object_types(union_types) == union
150+
# Order should no matter
151+
assert reg.get_union_for_object_types([ReporterType, PetType]) == union
152+
153+
154+
def test_register_union_scalar():
155+
reg = Registry()
156+
157+
union_types = [graphene.String, graphene.Int]
158+
union = graphene.Union('StringInt', tuple(union_types))
159+
160+
re_err = r"Expected Graphene ObjectType, but got: .*String.*"
161+
with pytest.raises(TypeError, match=re_err):
162+
reg.register_union_type(union, union_types)
163+
164+
165+
def test_register_union_incorrect_types():
166+
reg = Registry()
167+
168+
class PetType(SQLAlchemyObjectType):
169+
class Meta:
170+
model = Pet
171+
registry = reg
172+
173+
class ReporterType(SQLAlchemyObjectType):
174+
class Meta:
175+
model = Reporter
176+
177+
union_types = [PetType, ReporterType]
178+
union = PetType
179+
180+
re_err = r"Expected graphene.Union, but got: .*PetType.*"
181+
with pytest.raises(TypeError, match=re_err):
182+
reg.register_union_type(union, union_types)

0 commit comments

Comments
 (0)