Coverage for python/lsst/utils/doImport.py : 9%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# This file is part of utils.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (http://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <http://www.gnu.org/licenses/>.
23import importlib
25__all__ = ("doImport",)
28def doImport(importable):
29 """Import a python object given an importable string and return it.
31 Parameters
32 ----------
33 importable : `str`
34 String containing dot-separated path of a Python class, module,
35 or member function.
37 Returns
38 -------
39 type : `type`
40 Type object. Either a module or class or a function.
42 Raises
43 ------
44 TypeError
45 ``importable`` is not a `str`.
46 ModuleNotFoundError
47 No module in the supplied import string could be found.
48 ImportError
49 ``importable`` is found but can not be imported or the requested
50 item could not be retrieved from the imported module.
51 """
52 if not isinstance(importable, str):
53 raise TypeError(f"Unhandled type of importable, val: {importable}")
55 def tryImport(module, fromlist):
56 pytype = importlib.import_module(module)
57 # Can have functions inside classes inside modules
58 for f in fromlist:
59 try:
60 pytype = getattr(pytype, f)
61 except AttributeError:
62 raise ImportError(f"Could not get attribute '{f}' from '{module}'")
63 return pytype
65 # Go through the import path attempting to load the module
66 # and retrieve the class or function as an attribute. Shift components
67 # from the module list to the attribute list until something works.
68 moduleComponents = importable.split(".")
69 infileComponents = []
71 while moduleComponents:
72 try:
73 pytype = tryImport(".".join(moduleComponents), infileComponents)
74 if not infileComponents and hasattr(pytype, moduleComponents[-1]):
75 # This module has an attribute with the same name as the
76 # module itself (like doImport.doImport, actually!).
77 # If that attribute was lifted to the package, we should
78 # return the attribute, not the module.
79 try:
80 return tryImport(".".join(moduleComponents[:-1]), moduleComponents[-1:])
81 except ModuleNotFoundError:
82 pass
83 return pytype
84 except ModuleNotFoundError:
85 # Move element from module to file and try again
86 infileComponents.insert(0, moduleComponents.pop())
88 raise ModuleNotFoundError(f"Unable to import {importable}")