5 key_pattern = re.compile("\A[A-Za-z0-9_-]+\Z")
7 class InvalidStatusFile(Exception):
12 (One subtree of) Moe status file.
18 def __getitem__(self, k):
21 def __setitem__(self, k, v):
30 def update(self, stat2):
32 Updates values of `self` with values of `stat2`, recursively.
34 Directly references objects (values and subtrees) of `stat2`, so making a deep copy of `stat2`
35 may be necessary if you intend to modify `stat2` afterwards.
38 for k,v2 in stat2.d.items():
43 if isinstance(v, Status) != isinstance(v2, Status):
44 raise TypeError("Mixing Status and value while updating key %r"%k)
45 if isinstance(v, Status):
50 def dump(self, prefix=""):
52 Dump Status in status file format.
53 Returns a list of lines, ``prefix`` is indentation prefix.
57 for k,v in self.d.items():
58 if isinstance(v, Status):
59 l.append(prefix + k + " (")
60 l.extend(v.dump(prefix+" "))
61 l.append(prefix + ")")
63 d = str(v).split('\n')
64 l.append(prefix + k + ":" + d[0])
66 l.append(prefix + ' '*len(k) + ':' + i)
69 def write(self, f=None, name=None):
71 Write Status to File ``f`` or overwrite file ``name`` or write to ``stdout`` (otherwise).
74 if not f and name is not None:
75 with open(name, "w") as f:
84 def read(self, f=None, name=None, lines=None):
88 * or from file ``name`` opened for reading 8-bit ASCII
89 * or from ``lines`` (a list/iterator of lines)
91 Deletes all previous contents of the Status.
96 return self.do_read(f.readlines())
98 with open(name, 'r') as f:
99 return self.do_read(f.readlines())
100 if lines is not None:
101 return self.do_read(lines)
102 raise ValueError('Provide at least one parameter to Status.read()')
104 def read_val(self, k, v):
106 Internal: Safely add a new value to Status
109 if not key_pattern.match(k):
110 raise InvalidStatusFile("Parse error: invalid key %r"%k)
112 raise InvalidStatusFile("Multiple occurences of key %r"%k)
115 def do_read(self, lines):
117 Internal: Parse a status file given as list/iterator of lines
121 this = self # currently read nested Status
122 lastk = None # for multiline appending
124 x = x.rstrip("\n").lstrip(" \t")
125 if x=="" or x.startswith("#"):
129 if sep > 0: # key:value
130 k = x[:sep].rstrip(" \t")
134 elif sep == 0: # continuation of multiline :value
136 raise InvalidStatusFile("Parse error: key expected before ':'")
138 this[lastk] += '\n' + v
139 elif x.endswith("("): # close subtree
140 k = x[:-1].rstrip(" \t")
142 this.read_val(k, new)
149 raise InvalidStatusFile("Parse error: incorrect nesting")
153 raise InvalidStatusFile("Parse error: malformed line")