Skip to content

Commit 361b44c

Browse files
committed
Merge master into convert_enums
2 parents 67d789d + 082169e commit 361b44c

File tree

7 files changed

+145
-59
lines changed

7 files changed

+145
-59
lines changed

Diff for: .gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ htmlcov/
4646
nosetests.xml
4747
coverage.xml
4848
*,cover
49+
.pytest_cache/
4950

5051
# Translations
5152
*.mo

Diff for: graphene_sqlalchemy/converter.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
String)
88
from graphene.types.json import JSONString
99

10-
from .fields import createConnectionField
1110
from .registry import get_global_registry
1211

1312
try:
@@ -24,7 +23,7 @@ def is_column_nullable(column):
2423
return bool(getattr(column, "nullable", True))
2524

2625

27-
def convert_sqlalchemy_relationship(relationship, registry):
26+
def convert_sqlalchemy_relationship(relationship, registry, connection_field_factory):
2827
direction = relationship.direction
2928
model = relationship.mapper.entity
3029

@@ -36,7 +35,7 @@ def dynamic_type():
3635
return Field(_type)
3736
elif direction in (interfaces.ONETOMANY, interfaces.MANYTOMANY):
3837
if _type._meta.connection:
39-
return createConnectionField(_type._meta.connection)
38+
return connection_field_factory(relationship, registry)
4039
return Field(List(_type))
4140

4241
return Dynamic(dynamic_type)

Diff for: graphene_sqlalchemy/fields.py

+22
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import logging
12
from functools import partial
23

34
from promise import Promise, is_thenable
@@ -9,6 +10,8 @@
910

1011
from .utils import get_query, get_sort_argument_for_model
1112

13+
log = logging.getLogger()
14+
1215

1316
class UnsortedSQLAlchemyConnectionField(ConnectionField):
1417
@property
@@ -95,18 +98,37 @@ def __init__(self, type, *args, **kwargs):
9598
super(SQLAlchemyConnectionField, self).__init__(type, *args, **kwargs)
9699

97100

101+
def default_connection_field_factory(relationship, registry):
102+
model = relationship.mapper.entity
103+
model_type = registry.get_type_for_model(model)
104+
return createConnectionField(model_type)
105+
106+
107+
# TODO Remove in next major version
98108
__connectionFactory = UnsortedSQLAlchemyConnectionField
99109

100110

101111
def createConnectionField(_type):
112+
log.warn(
113+
'createConnectionField is deprecated and will be removed in the next '
114+
'major version. Use SQLAlchemyObjectType.Meta.connection_field_factory instead.'
115+
)
102116
return __connectionFactory(_type)
103117

104118

105119
def registerConnectionFieldFactory(factoryMethod):
120+
log.warn(
121+
'registerConnectionFieldFactory is deprecated and will be removed in the next '
122+
'major version. Use SQLAlchemyObjectType.Meta.connection_field_factory instead.'
123+
)
106124
global __connectionFactory
107125
__connectionFactory = factoryMethod
108126

109127

110128
def unregisterConnectionFieldFactory():
129+
log.warn(
130+
'registerConnectionFieldFactory is deprecated and will be removed in the next '
131+
'major version. Use SQLAlchemyObjectType.Meta.connection_field_factory instead.'
132+
)
111133
global __connectionFactory
112134
__connectionFactory = UnsortedSQLAlchemyConnectionField

Diff for: graphene_sqlalchemy/tests/test_connectionfactory.py

-42
This file was deleted.

Diff for: graphene_sqlalchemy/tests/test_converter.py

+13-8
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
from ..converter import (convert_sqlalchemy_column,
1717
convert_sqlalchemy_composite,
1818
convert_sqlalchemy_relationship)
19-
from ..fields import UnsortedSQLAlchemyConnectionField
19+
from ..fields import (UnsortedSQLAlchemyConnectionField,
20+
default_connection_field_factory)
2021
from ..registry import Registry
2122
from ..types import SQLAlchemyObjectType
2223
from .models import Article, Pet, Reporter
@@ -197,7 +198,9 @@ def test_should_jsontype_convert_jsonstring():
197198

198199
def test_should_manytomany_convert_connectionorlist():
199200
registry = Registry()
200-
dynamic_field = convert_sqlalchemy_relationship(Reporter.pets.property, registry)
201+
dynamic_field = convert_sqlalchemy_relationship(
202+
Reporter.pets.property, registry, default_connection_field_factory
203+
)
201204
assert isinstance(dynamic_field, graphene.Dynamic)
202205
assert not dynamic_field.get_type()
203206

@@ -208,7 +211,7 @@ class Meta:
208211
model = Pet
209212

210213
dynamic_field = convert_sqlalchemy_relationship(
211-
Reporter.pets.property, A._meta.registry
214+
Reporter.pets.property, A._meta.registry, default_connection_field_factory
212215
)
213216
assert isinstance(dynamic_field, graphene.Dynamic)
214217
graphene_type = dynamic_field.get_type()
@@ -224,15 +227,17 @@ class Meta:
224227
interfaces = (Node,)
225228

226229
dynamic_field = convert_sqlalchemy_relationship(
227-
Reporter.pets.property, A._meta.registry
230+
Reporter.pets.property, A._meta.registry, default_connection_field_factory
228231
)
229232
assert isinstance(dynamic_field, graphene.Dynamic)
230233
assert isinstance(dynamic_field.get_type(), UnsortedSQLAlchemyConnectionField)
231234

232235

233236
def test_should_manytoone_convert_connectionorlist():
234237
registry = Registry()
235-
dynamic_field = convert_sqlalchemy_relationship(Article.reporter.property, registry)
238+
dynamic_field = convert_sqlalchemy_relationship(
239+
Article.reporter.property, registry, default_connection_field_factory
240+
)
236241
assert isinstance(dynamic_field, graphene.Dynamic)
237242
assert not dynamic_field.get_type()
238243

@@ -243,7 +248,7 @@ class Meta:
243248
model = Reporter
244249

245250
dynamic_field = convert_sqlalchemy_relationship(
246-
Article.reporter.property, A._meta.registry
251+
Article.reporter.property, A._meta.registry, default_connection_field_factory
247252
)
248253
assert isinstance(dynamic_field, graphene.Dynamic)
249254
graphene_type = dynamic_field.get_type()
@@ -258,7 +263,7 @@ class Meta:
258263
interfaces = (Node,)
259264

260265
dynamic_field = convert_sqlalchemy_relationship(
261-
Article.reporter.property, A._meta.registry
266+
Article.reporter.property, A._meta.registry, default_connection_field_factory
262267
)
263268
assert isinstance(dynamic_field, graphene.Dynamic)
264269
graphene_type = dynamic_field.get_type()
@@ -273,7 +278,7 @@ class Meta:
273278
interfaces = (Node,)
274279

275280
dynamic_field = convert_sqlalchemy_relationship(
276-
Reporter.favorite_article.property, A._meta.registry
281+
Reporter.favorite_article.property, A._meta.registry, default_connection_field_factory
277282
)
278283
assert isinstance(dynamic_field, graphene.Dynamic)
279284
graphene_type = dynamic_field.get_type()

Diff for: graphene_sqlalchemy/tests/test_types.py

+95-3
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@
33
import six # noqa F401
44
from promise import Promise
55

6-
from graphene import Field, Int, Interface, ObjectType
7-
from graphene.relay import Connection, Node, is_node
6+
from graphene import (Connection, Field, Int, Interface, Node, ObjectType,
7+
is_node)
88

9-
from ..fields import SQLAlchemyConnectionField
9+
from ..fields import (SQLAlchemyConnectionField,
10+
UnsortedSQLAlchemyConnectionField,
11+
registerConnectionFieldFactory,
12+
unregisterConnectionFieldFactory)
1013
from ..registry import Registry
1114
from ..types import SQLAlchemyObjectType, SQLAlchemyObjectTypeOptions
1215
from .models import Article, Reporter
@@ -188,3 +191,92 @@ def resolver(_obj, _info):
188191
resolver, TestConnection, ReporterWithCustomOptions, None, None
189192
)
190193
assert result is not None
194+
195+
196+
# Tests for connection_field_factory
197+
198+
class _TestSQLAlchemyConnectionField(SQLAlchemyConnectionField):
199+
pass
200+
201+
202+
def test_default_connection_field_factory():
203+
_registry = Registry()
204+
205+
class ReporterType(SQLAlchemyObjectType):
206+
class Meta:
207+
model = Reporter
208+
registry = _registry
209+
interfaces = (Node,)
210+
211+
class ArticleType(SQLAlchemyObjectType):
212+
class Meta:
213+
model = Article
214+
registry = _registry
215+
interfaces = (Node,)
216+
217+
assert isinstance(ReporterType._meta.fields['articles'].type(), UnsortedSQLAlchemyConnectionField)
218+
219+
220+
def test_register_connection_field_factory():
221+
def test_connection_field_factory(relationship, registry):
222+
model = relationship.mapper.entity
223+
_type = registry.get_type_for_model(model)
224+
return _TestSQLAlchemyConnectionField(_type._meta.connection)
225+
226+
_registry = Registry()
227+
228+
class ReporterType(SQLAlchemyObjectType):
229+
class Meta:
230+
model = Reporter
231+
registry = _registry
232+
interfaces = (Node,)
233+
connection_field_factory = test_connection_field_factory
234+
235+
class ArticleType(SQLAlchemyObjectType):
236+
class Meta:
237+
model = Article
238+
registry = _registry
239+
interfaces = (Node,)
240+
241+
assert isinstance(ReporterType._meta.fields['articles'].type(), _TestSQLAlchemyConnectionField)
242+
243+
244+
def test_deprecated_registerConnectionFieldFactory():
245+
registerConnectionFieldFactory(_TestSQLAlchemyConnectionField)
246+
247+
_registry = Registry()
248+
249+
class ReporterType(SQLAlchemyObjectType):
250+
class Meta:
251+
model = Reporter
252+
registry = _registry
253+
interfaces = (Node,)
254+
255+
class ArticleType(SQLAlchemyObjectType):
256+
class Meta:
257+
model = Article
258+
registry = _registry
259+
interfaces = (Node,)
260+
261+
assert isinstance(ReporterType._meta.fields['articles'].type(), _TestSQLAlchemyConnectionField)
262+
263+
264+
def test_deprecated_unregisterConnectionFieldFactory():
265+
registerConnectionFieldFactory(_TestSQLAlchemyConnectionField)
266+
unregisterConnectionFieldFactory()
267+
268+
_registry = Registry()
269+
270+
class ReporterType(SQLAlchemyObjectType):
271+
class Meta:
272+
model = Reporter
273+
registry = _registry
274+
interfaces = (Node,)
275+
276+
class ArticleType(SQLAlchemyObjectType):
277+
class Meta:
278+
model = Article
279+
registry = _registry
280+
interfaces = (Node,)
281+
282+
assert not isinstance(ReporterType._meta.fields['articles'].type(), _TestSQLAlchemyConnectionField)

Diff for: graphene_sqlalchemy/types.py

+12-3
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@
1414
convert_sqlalchemy_composite,
1515
convert_sqlalchemy_hybrid_method,
1616
convert_sqlalchemy_relationship)
17+
from .fields import default_connection_field_factory
1718
from .registry import Registry, get_global_registry
1819
from .utils import get_query, is_mapped_class, is_mapped_instance
1920

2021

21-
def construct_fields(model, registry, only_fields, exclude_fields):
22+
def construct_fields(model, registry, only_fields, exclude_fields, connection_field_factory):
2223
inspected_model = sqlalchemyinspect(model)
2324

2425
fields = OrderedDict()
@@ -71,7 +72,7 @@ def construct_fields(model, registry, only_fields, exclude_fields):
7172
# We skip this field if we specify only_fields and is not
7273
# in there. Or when we exclude this field in exclude_fields
7374
continue
74-
converted_relationship = convert_sqlalchemy_relationship(relationship, registry)
75+
converted_relationship = convert_sqlalchemy_relationship(relationship, registry, connection_field_factory)
7576
name = relationship.key
7677
fields[name] = converted_relationship
7778

@@ -99,6 +100,7 @@ def __init_subclass_with_meta__(
99100
use_connection=None,
100101
interfaces=(),
101102
id=None,
103+
connection_field_factory=default_connection_field_factory,
102104
_meta=None,
103105
**options
104106
):
@@ -115,7 +117,14 @@ def __init_subclass_with_meta__(
115117
).format(cls.__name__, registry)
116118

117119
sqla_fields = yank_fields_from_attrs(
118-
construct_fields(model, registry, only_fields, exclude_fields), _as=Field
120+
construct_fields(
121+
model=model,
122+
registry=registry,
123+
only_fields=only_fields,
124+
exclude_fields=exclude_fields,
125+
connection_field_factory=connection_field_factory
126+
),
127+
_as=Field
119128
)
120129

121130
if use_connection is None and interfaces:

0 commit comments

Comments
 (0)