Coverage for /builds/debichem-team/python-ase/ase/config.py: 60.00%

90 statements  

« prev     ^ index     » next       coverage.py v7.5.3, created at 2025-03-06 04:00 +0000

1import configparser 

2import os 

3import shlex 

4import warnings 

5from collections.abc import Mapping 

6from pathlib import Path 

7 

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

9 

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

11 

12 

13class ASEEnvDeprecationWarning(DeprecationWarning): 

14 def __init__(self, message): 

15 self.message = message 

16 

17 

18class Config(Mapping): 

19 def __init__(self): 

20 def argv_converter(argv): 

21 return shlex.split(argv) 

22 

23 self.parser = configparser.ConfigParser( 

24 converters={"argv": argv_converter}, 

25 interpolation=configparser.ExtendedInterpolation()) 

26 self.paths = [] 

27 

28 def _env(self): 

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

30 return self.parser['environment'] 

31 else: 

32 return {} 

33 

34 def __iter__(self): 

35 yield from self._env() 

36 

37 def __getitem__(self, item): 

38 # XXX We should replace the mapping behaviour with individual 

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

40 # 

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

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

43 

44 env = self._env() 

45 try: 

46 return env[item] 

47 except KeyError: 

48 pass 

49 

50 value = os.environ[item] 

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

52 'Please use configfile.', 

53 ASEEnvDeprecationWarning) 

54 

55 return value 

56 

57 def __len__(self): 

58 return len(self._env()) 

59 

60 def check_calculators(self): 

61 print("Calculators") 

62 print("===========") 

63 print() 

64 print("Configured in ASE") 

65 print(" | Installed on machine") 

66 print(" | | Name & version") 

67 print(" | | |") 

68 for name in names: 

69 # configured = False 

70 # installed = False 

71 template = templates.get(name) 

72 # if template is None: 

73 # XXX no template for this calculator. 

74 # We need templates for all calculators somehow, 

75 # but we can probably generate those for old FileIOCalculators 

76 # automatically. 

77 # continue 

78 

79 fullname = name 

80 try: 

81 codeconfig = self[name] 

82 except KeyError: 

83 codeconfig = None 

84 version = None 

85 else: 

86 if template is None: 

87 # XXX we should not be executing this 

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

89 # builtin calculators 

90 version = "builtin" 

91 else: 

92 version = None 

93 else: 

94 profile = template.load_profile(codeconfig) 

95 # XXX should be made robust to failure here: 

96 with warnings.catch_warnings(): 

97 warnings.simplefilter("ignore") 

98 version = profile.version() 

99 

100 fullname = name 

101 if version is not None: 

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

103 

104 def tickmark(thing): 

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

106 

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

108 configured=tickmark(codeconfig), 

109 installed=tickmark(version), 

110 fullname=fullname, 

111 ) 

112 print(msg) 

113 

114 def print_header(self): 

115 print("Configuration") 

116 print("-------------") 

117 print() 

118 if not self.paths: 

119 print("No configuration loaded.") 

120 

121 for path in self.paths: 

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

123 

124 def as_dict(self): 

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

126 

127 def _read_paths(self, paths): 

128 self.paths += self.parser.read(paths) 

129 

130 @classmethod 

131 def read(cls): 

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

133 if envpath is None: 

134 paths = [ASE_CONFIG_FILE, ] 

135 else: 

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

137 

138 cfg = cls() 

139 cfg._read_paths(paths) 

140 

141 # add sections for builtin calculators 

142 for name in builtin: 

143 cfg.parser.add_section(name) 

144 cfg.parser[name]["builtin"] = "True" 

145 return cfg 

146 

147 

148cfg = Config.read()