Hide keyboard shortcuts

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/>. 

21 

22 

23import importlib 

24 

25__all__ = ("doImport",) 

26 

27 

28def doImport(importable): 

29 """Import a python object given an importable string and return it. 

30 

31 Parameters 

32 ---------- 

33 importable : `str` 

34 String containing dot-separated path of a Python class, module, 

35 or member function. 

36 

37 Returns 

38 ------- 

39 type : `type` 

40 Type object. Either a module or class or a function. 

41 

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}") 

54 

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 

64 

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 = [] 

70 

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()) 

87 

88 raise ModuleNotFoundError(f"Unable to import {importable}")