Skip to content

Commit ae45f07

Browse files
committed
feat: Use mongengine field metadata and class docstrings for default field descriptions.
1 parent a1de06c commit ae45f07

File tree

4 files changed

+94
-18
lines changed

4 files changed

+94
-18
lines changed

graphene_mongo/converter.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
from .advanced_types import PointFieldType, MultiPolygonFieldType
1919
from .fields import MongoengineConnectionField
20-
from .utils import import_single_dispatch
20+
from .utils import import_single_dispatch, get_field_description
2121

2222
singledispatch = import_single_dispatch()
2323

@@ -33,36 +33,36 @@ def convert_mongoengine_field(field, registry=None):
3333
@convert_mongoengine_field.register(mongoengine.StringField)
3434
@convert_mongoengine_field.register(mongoengine.URLField)
3535
def convert_field_to_string(field, registry=None):
36-
return String(description=field.db_field, required=field.required)
36+
return String(description=get_field_description(field, registry), required=field.required)
3737

3838

3939
@convert_mongoengine_field.register(mongoengine.UUIDField)
4040
@convert_mongoengine_field.register(mongoengine.ObjectIdField)
4141
def convert_field_to_id(field, registry=None):
42-
return ID(description=field.db_field, required=field.required)
42+
return ID(description=get_field_description(field, registry), required=field.required)
4343

4444

4545
@convert_mongoengine_field.register(mongoengine.IntField)
4646
@convert_mongoengine_field.register(mongoengine.LongField)
4747
def convert_field_to_int(field, registry=None):
48-
return Int(description=field.db_field, required=field.required)
48+
return Int(description=get_field_description(field, registry), required=field.required)
4949

5050

5151
@convert_mongoengine_field.register(mongoengine.BooleanField)
5252
def convert_field_to_boolean(field, registry=None):
53-
return Boolean(description=field.db_field, required=field.required)
53+
return Boolean(description=get_field_description(field, registry), required=field.required)
5454

5555

5656
@convert_mongoengine_field.register(mongoengine.DecimalField)
5757
@convert_mongoengine_field.register(mongoengine.FloatField)
5858
def convert_field_to_float(field, registry=None):
59-
return Float(description=field.db_field, required=field.required)
59+
return Float(description=get_field_description(field, registry), required=field.required)
6060

6161

6262
@convert_mongoengine_field.register(mongoengine.DictField)
6363
@convert_mongoengine_field.register(mongoengine.MapField)
6464
def convert_dict_to_jsonstring(field, registry=None):
65-
return JSONString(description=field.db_field, required=field.required)
65+
return JSONString(description=get_field_description(field, registry), required=field.required)
6666

6767

6868
@convert_mongoengine_field.register(mongoengine.PointField)
@@ -77,7 +77,7 @@ def convert_multipolygon_to_field(field, register=None):
7777

7878
@convert_mongoengine_field.register(mongoengine.DateTimeField)
7979
def convert_field_to_datetime(field, registry=None):
80-
return DateTime(description=field.db_field, required=field.required)
80+
return DateTime(description=get_field_description(field, registry), required=field.required)
8181

8282

8383
@convert_mongoengine_field.register(mongoengine.ListField)
@@ -99,7 +99,7 @@ def convert_field_to_list(field, registry=None):
9999
and not isinstance(field.field, relations):
100100
base_type = type(base_type)
101101

102-
return List(base_type, description=field.db_field, required=field.required)
102+
return List(base_type, description=get_field_description(field, registry), required=field.required)
103103

104104

105105
@convert_mongoengine_field.register(mongoengine.EmbeddedDocumentField)
@@ -111,6 +111,6 @@ def dynamic_type():
111111
_type = registry.get_type_for_model(model)
112112
if not _type:
113113
return None
114-
return Field(_type)
114+
return Field(_type, description=get_field_description(field, registry))
115115

116116
return Dynamic(dynamic_type)

graphene_mongo/tests/models.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,24 @@
1313

1414

1515
class Editor(Document):
16+
"""
17+
An Editor of a publication.
18+
"""
1619

1720
meta = {'collection': 'test_editor'}
1821
id = StringField(primary_key=True)
19-
first_name = StringField(required=True)
20-
last_name = StringField(required=True)
21-
metadata = MapField(field=StringField())
22+
first_name = StringField(required=True, help_text="Editor's first name.", db_field='fname')
23+
last_name = StringField(required=True, help_text="Editor's last name.")
24+
metadata = MapField(field=StringField(), help_text="Arbitrary metadata.")
2225

2326

2427
class Article(Document):
2528

2629
meta = {'collection': 'test_article'}
27-
headline = StringField(required=True)
28-
pub_date = DateTimeField(default=datetime.now)
30+
headline = StringField(required=True, help_text="The article headline.")
31+
pub_date = DateTimeField(default=datetime.now,
32+
verbose_name="publication date",
33+
help_text="The date of first press.")
2934
editor = ReferenceField(Editor)
3035
reporter = ReferenceField('Reporter')
3136

@@ -41,7 +46,7 @@ class EmbeddedArticle(EmbeddedDocument):
4146

4247
class Reporter(Document):
4348

44-
meta = {'collection': 'test_repoter'}
49+
meta = {'collection': 'test_reporter'}
4550
id = StringField(primary_key=True)
4651
first_name = StringField(required=True)
4752
last_name = StringField(required=True)

graphene_mongo/tests/test_converter.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,3 +221,49 @@ class Meta:
221221
assert isinstance(graphene_field, graphene.List)
222222
dynamic_field = graphene_field.get_type()
223223
assert dynamic_field._of_type == P
224+
225+
226+
def test_should_description_convert_common_metadata():
227+
228+
class A(MongoengineObjectType):
229+
230+
class Meta:
231+
model = Article
232+
233+
headline_field = convert_mongoengine_field(
234+
Article._fields['headline'], A._meta.registry
235+
)
236+
assert headline_field.kwargs['description'] == "The article headline."
237+
238+
pubDate_field = convert_mongoengine_field(
239+
Article._fields['pub_date'], A._meta.registry
240+
)
241+
assert pubDate_field.kwargs['description'] == "Publication Date\nThe date of first press."
242+
243+
firstName_field = convert_mongoengine_field(
244+
Editor._fields['first_name'], A._meta.registry
245+
)
246+
assert firstName_field.kwargs['description'] == "Editor's first name.\n(fname)"
247+
248+
metadata_field = convert_mongoengine_field(
249+
Editor._fields['metadata'], A._meta.registry
250+
)
251+
assert metadata_field.kwargs['description'] == "Arbitrary metadata."
252+
253+
254+
def test_should_description_convert_reference_metadata():
255+
256+
class A(MongoengineObjectType):
257+
258+
class Meta:
259+
model = Article
260+
261+
class E(MongoengineObjectType):
262+
263+
class Meta:
264+
model = Editor
265+
266+
editor_field = convert_mongoengine_field(
267+
Article._fields['editor'], A._meta.registry
268+
).get_type()
269+
assert editor_field.description == "An Editor of a publication."

graphene_mongo/utils.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
import inspect
2-
import mongoengine
1+
from __future__ import unicode_literals
32

3+
import inspect
44
from collections import OrderedDict
55

6+
import mongoengine
7+
from graphene.utils.trim_docstring import trim_docstring
8+
69

710
def get_model_fields(model, excluding=None):
811
excluding = excluding or []
@@ -62,3 +65,25 @@ def get_type_for_document(schema, document):
6265
_type._meta, 'document', None)
6366
if document == type_document:
6467
return _type
68+
69+
70+
def get_field_description(field, registry=None):
71+
"""
72+
Common metadata includes verbose_name and help_text.
73+
74+
http://docs.mongoengine.org/apireference.html#fields
75+
"""
76+
parts = []
77+
if hasattr(field, 'document_type'):
78+
doc = trim_docstring(field.document_type.__doc__)
79+
if doc:
80+
parts.append(doc)
81+
if hasattr(field, 'verbose_name'):
82+
parts.append(field.verbose_name.title())
83+
if hasattr(field, 'help_text'):
84+
parts.append(field.help_text)
85+
if field.db_field != field.name:
86+
name_format = "(%s)" if parts else "%s"
87+
parts.append(name_format % field.db_field)
88+
89+
return "\n".join(parts)

0 commit comments

Comments
 (0)