Coverage for /builds/kinetik161/ase/ase/config.py: 68.00%

100 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-12-10 11:04 +0000

1import os 

2import configparser 

3from collections.abc import Mapping 

4from pathlib import Path 

5import shlex 

6import warnings 

7 

8from ase.utils import lazymethod 

9from ase.calculators.names import names, builtin, templates 

10 

11 

12ASE_CONFIG_FILE = Path.home() / ".config/ase/config.ini" 

13 

14 

15class ASEEnvDeprecationWarning(DeprecationWarning): 

16 def __init__(self, message): 

17 self.message = message 

18 

19 

20class Config(Mapping): 

21 def _env(self): 

22 if self.parser.has_section('environment'): 

23 return self.parser['environment'] 

24 else: 

25 return {} 

26 

27 def __iter__(self): 

28 yield from self._env() 

29 

30 def __getitem__(self, item): 

31 # XXX We should replace the mapping behaviour with individual 

32 # methods to get from cfg or environment, or only from cfg. 

33 # 

34 # We cannot be a mapping very correctly without getting trouble 

35 # with mutable state needing synchronization with os.environ. 

36 

37 env = self._env() 

38 try: 

39 return env[item] 

40 except KeyError: 

41 pass 

42 

43 value = os.environ[item] 

44 warnings.warn(f'Loaded {item} from environment. ' 

45 'Please use configfile.', 

46 ASEEnvDeprecationWarning) 

47 

48 return value 

49 

50 def __len__(self): 

51 return len(self._env()) 

52 

53 @lazymethod 

54 def _paths_and_parser(self): 

55 def argv_converter(argv): 

56 return shlex.split(argv) 

57 

58 parser = configparser.ConfigParser(converters={"argv": argv_converter}) 

59 envpath = os.environ.get("ASE_CONFIG_PATH") 

60 if envpath is not None: 

61 paths = [Path(p) for p in envpath.split(":")] 

62 else: 

63 paths = [ASE_CONFIG_FILE, ] 

64 loaded_paths = parser.read(paths) 

65 # add sections for builtin calculators 

66 for name in builtin: 

67 parser.add_section(name) 

68 parser[name]["builtin"] = "True" 

69 return loaded_paths, parser 

70 

71 @property 

72 def paths(self): 

73 return self._paths_and_parser()[0] 

74 

75 @property 

76 def parser(self): 

77 return self._paths_and_parser()[1] 

78 

79 def check_calculators(self): 

80 

81 print("Calculators") 

82 print("===========") 

83 print() 

84 print("Configured in ASE") 

85 print(" | Installed on machine") 

86 print(" | | Name & version") 

87 print(" | | |") 

88 for name in names: 

89 # configured = False 

90 # installed = False 

91 template = templates.get(name) 

92 # if template is None: 

93 # XXX no template for this calculator. 

94 # We need templates for all calculators somehow, 

95 # but we can probably generate those for old FileIOCalculators 

96 # automatically. 

97 # continue 

98 

99 fullname = name 

100 try: 

101 codeconfig = self[name] 

102 except KeyError: 

103 codeconfig = None 

104 version = None 

105 else: 

106 if template is None: 

107 # XXX we should not be executing this 

108 if codeconfig is not None and "builtin" in codeconfig: 

109 # builtin calculators 

110 version = "builtin" 

111 else: 

112 version = None 

113 else: 

114 profile = template.load_profile(codeconfig) 

115 # XXX should be made robust to failure here: 

116 with warnings.catch_warnings(): 

117 warnings.simplefilter("ignore") 

118 version = profile.version() 

119 

120 fullname = name 

121 if version is not None: 

122 fullname += f"--{version}" 

123 

124 def tickmark(thing): 

125 return "[ ]" if thing is None else "[x]" 

126 

127 msg = " {configured} {installed} {fullname}".format( 

128 configured=tickmark(codeconfig), 

129 installed=tickmark(version), 

130 fullname=fullname, 

131 ) 

132 print(msg) 

133 

134 def print_everything(self): 

135 print("Configuration") 

136 print("-------------") 

137 print() 

138 if not self.paths: 

139 print("No configuration loaded.") 

140 

141 for path in self.paths: 

142 print(f"Loaded: {path}") 

143 

144 print() 

145 for name, section in self.parser.items(): 

146 print(name) 

147 if not section: 

148 print(" (Nothing configured)") 

149 for key, val in section.items(): 

150 print(f" {key}: {val}") 

151 print() 

152 

153 def as_dict(self): 

154 return {key: dict(val) for key, val in self.parser.items()} 

155 

156 

157cfg = Config()