8
8
9
9
import importlib
10
10
from types import ModuleType
11
- from typing import Callable , Optional , Union
11
+ from typing import Callable , Optional , TypeVar , Union
12
12
13
13
14
14
def load_module (path : str ) -> Union [ModuleType , Optional [Callable [..., object ]]]:
15
15
"""
16
16
Loads and returns the module/module attr represented by the ``path``: ``full.module.path:optional_attr``
17
17
18
- ::
19
-
20
-
21
18
1. ``load_module("this.is.a_module:fn")`` -> equivalent to ``this.is.a_module.fn``
22
19
1. ``load_module("this.is.a_module")`` -> equivalent to ``this.is.a_module``
23
20
"""
@@ -33,3 +30,36 @@ def load_module(path: str) -> Union[ModuleType, Optional[Callable[..., object]]]
33
30
return getattr (module , method ) if method else module
34
31
except Exception :
35
32
return None
33
+
34
+
35
+ T = TypeVar ("T" )
36
+
37
+
38
+ def import_attr (name : str , attr : str , default : T ) -> T :
39
+ """
40
+ Imports ``name.attr`` and returns it if the module is found.
41
+ Otherwise, returns the specified ``default``.
42
+ Useful when getting an attribute from an optional dependency.
43
+
44
+ Note that the ``default`` parameter is intentionally not an optional
45
+ since this function is intended to be used with modules that may not be
46
+ installed as a dependency. Therefore the caller must ALWAYS provide a
47
+ sensible default.
48
+
49
+ Usage:
50
+
51
+ .. code-block:: python
52
+
53
+ aws_resources = import_attr("torchx.specs.named_resources_aws", "NAMED_RESOURCES", default={})
54
+ all_resources.update(aws_resources)
55
+
56
+ Raises:
57
+ AttributeError: If the module exists (e.g. can be imported)
58
+ but does not have an attribute with name ``attr``.
59
+ """
60
+ try :
61
+ mod = importlib .import_module (name )
62
+ except ModuleNotFoundError :
63
+ return default
64
+ else :
65
+ return getattr (mod , attr )
0 commit comments