Coverage for /builds/hweiske/ase/ase/io/espresso_namelist/namelist.py: 95.31%
64 statements
« prev ^ index » next coverage.py v7.2.7, created at 2024-04-22 11:22 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2024-04-22 11:22 +0000
1import re
2import warnings
3from collections import UserDict
4from collections.abc import MutableMapping
5from pathlib import Path
7from ase.io.espresso_namelist.keys import ALL_KEYS
10class Namelist(UserDict):
11 def __getitem__(self, key):
12 return super().__getitem__(key.lower())
14 def __setitem__(self, key, value):
15 super().__setitem__(
16 key.lower(), Namelist(value) if isinstance(
17 value, MutableMapping) else value)
19 def __delitem__(self, key):
20 super().__delitem__(key.lower())
22 @staticmethod
23 def search_key(to_find, keys):
24 """Search for a key in the namelist, case-insensitive.
25 Returns the section and key if found, None otherwise.
26 """
27 for section in keys:
28 for key in keys[section]:
29 if re.match(rf"({key})\b(\(+.*\)+)?$", to_find):
30 return section
32 def to_string(self, indent=0, list_form=False):
33 """Format a Namelist object as a string for writing to a file.
34 Assume sections are ordered (taken care of in namelist construction)
35 and that repr converts to a QE readable representation (except bools)
37 Parameters
38 ----------
39 indent : int
40 Number of spaces to indent each line
41 list_form : bool
42 If True, return a list of strings instead of a single string
44 Returns
45 -------
46 pwi : List[str] | str
47 Input line for the namelist
48 """
49 pwi = []
50 for key, value in self.items():
51 if isinstance(value, (Namelist, dict)):
52 pwi.append(f"{' '* indent}&{key.upper()}\n")
53 pwi.extend(Namelist.to_string(value, indent=indent + 3))
54 pwi.append(f"{' '* indent}/\n")
55 else:
56 if value is True:
57 pwi.append(f"{' '* indent}{key:16} = .true.\n")
58 elif value is False:
59 pwi.append(f"{' '* indent}{key:16} = .false.\n")
60 elif isinstance(value, Path):
61 pwi.append(f"{' '* indent}{key:16} = '{value}'\n")
62 else:
63 pwi.append(f"{' '* indent}{key:16} = {value!r}\n")
64 if list_form:
65 return pwi
66 else:
67 return "".join(pwi)
69 def to_nested(self, binary='pw', warn=False, **kwargs):
70 keys = ALL_KEYS[binary]
72 constructed_namelist = {
73 section: self.pop(section, {}) for section in keys
74 }
76 constructed_namelist.update({
77 key: value for key, value in self.items()
78 if isinstance(value, Namelist)
79 })
81 unused_keys = []
82 for arg_key in list(self):
83 section = Namelist.search_key(arg_key, keys)
84 value = self.pop(arg_key)
85 if section:
86 constructed_namelist[section][arg_key] = value
87 else:
88 unused_keys.append(arg_key)
90 for arg_key in list(kwargs):
91 section = Namelist.search_key(arg_key, keys)
92 value = kwargs.pop(arg_key)
93 if section:
94 warnings.warn(
95 ("Use of kwarg(s) as keyword(s) is deprecated,"
96 "use input_data instead"),
97 DeprecationWarning,
98 )
99 constructed_namelist[section][arg_key] = value
100 else:
101 unused_keys.append(arg_key)
103 if unused_keys and warn:
104 warnings.warn(
105 f"Unused keys: {', '.join(unused_keys)}",
106 UserWarning,
107 )
109 for section in constructed_namelist:
110 sorted_section = {}
112 def sorting_rule(item):
113 return keys[section].index(item.split('(')[0]) if item.split(
114 '(')[0] in keys.get(section, {}) else float('inf')
116 for key in sorted(constructed_namelist[section], key=sorting_rule):
117 sorted_section[key] = constructed_namelist[section][key]
119 constructed_namelist[section] = sorted_section
121 super().update(Namelist(constructed_namelist))