Skip to content

Commit 087f1c5

Browse files
committed
Improve lazy_import() to accept dotted_attributes
1 parent d4d8a76 commit 087f1c5

File tree

2 files changed

+47
-4
lines changed

2 files changed

+47
-4
lines changed

graphene/utils/module_loading.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from importlib import import_module
33

44

5-
def import_string(dotted_path):
5+
def import_string(dotted_path, dotted_attributes=None):
66
"""
77
Import a dotted module path and return the attribute/class designated by the
88
last name in the path. Raise ImportError if the import failed.
@@ -15,12 +15,27 @@ def import_string(dotted_path):
1515
module = import_module(module_path)
1616

1717
try:
18-
return getattr(module, class_name)
18+
result = getattr(module, class_name)
1919
except AttributeError:
2020
raise ImportError('Module "%s" does not define a "%s" attribute/class' % (
2121
module_path, class_name)
2222
)
2323

24+
if not dotted_attributes:
25+
return result
26+
else:
27+
attributes = dotted_attributes.split('.')
28+
traveled_attributes = []
29+
try:
30+
for attribute in attributes:
31+
traveled_attributes.append(attribute)
32+
result = getattr(result, attribute)
33+
return result
34+
except AttributeError:
35+
raise ImportError('Module "%s" does not define a "%s" attribute inside attribute/class "%s"' % (
36+
module_path, '.'.join(traveled_attributes), class_name
37+
))
2438

25-
def lazy_import(dotted_path):
26-
return partial(import_string, dotted_path)
39+
40+
def lazy_import(dotted_path, dotted_attributes=None):
41+
return partial(import_string, dotted_path, dotted_attributes)

graphene/utils/tests/test_module_loading.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
from pytest import raises
22

33
from graphene import String
4+
from graphene.types.objecttype import ObjectTypeMeta
45
from ..module_loading import lazy_import, import_string
56

67

78
def test_import_string():
89
MyString = import_string('graphene.String')
910
assert MyString == String
1011

12+
MyObjectTypeMeta = import_string('graphene.ObjectType', '__class__')
13+
assert MyObjectTypeMeta == ObjectTypeMeta
14+
1115

1216
def test_import_string_module():
1317
with raises(Exception) as exc_info:
@@ -23,7 +27,31 @@ def test_import_string_class():
2327
assert str(exc_info.value) == 'Module "graphene" does not define a "Stringa" attribute/class'
2428

2529

30+
def test_import_string_attributes():
31+
with raises(Exception) as exc_info:
32+
import_string('graphene.String', 'length')
33+
34+
assert str(exc_info.value) == 'Module "graphene" does not define a "length" attribute inside attribute/class ' \
35+
'"String"'
36+
37+
with raises(Exception) as exc_info:
38+
import_string('graphene.ObjectType', '__class__.length')
39+
40+
assert str(exc_info.value) == 'Module "graphene" does not define a "__class__.length" attribute inside ' \
41+
'attribute/class "ObjectType"'
42+
43+
with raises(Exception) as exc_info:
44+
import_string('graphene.ObjectType', '__classa__.__base__')
45+
46+
assert str(exc_info.value) == 'Module "graphene" does not define a "__classa__" attribute inside attribute/class ' \
47+
'"ObjectType"'
48+
49+
2650
def test_lazy_import():
2751
f = lazy_import('graphene.String')
2852
MyString = f()
2953
assert MyString == String
54+
55+
f = lazy_import('graphene.ObjectType', '__class__')
56+
MyObjectTypeMeta = f()
57+
assert MyObjectTypeMeta == ObjectTypeMeta

0 commit comments

Comments
 (0)