3 # vi:si:et:sw=4:sts=4:ts=4
6 parse, update and write .signals and .args files
15 # OrderedDict class based on
16 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/107747
17 # Licensed under the Python License
18 class OrderedDict(dict):
19 def __init__(self, dict = None):
21 dict.__init__(self, dict)
23 def __delitem__(self, key):
24 dict.__delitem__(self, key)
25 self._keys.remove(key)
27 def __setitem__(self, key, item):
28 dict.__setitem__(self, key, item)
29 if key not in self._keys: self._keys.append(key)
36 dict = dict.copy(self)
37 dict._keys = self._keys[:]
41 return zip(self._keys, self.values())
50 raise KeyError('dictionary is empty')
57 def setdefault(self, key, failobj = None):
58 dict.setdefault(self, key, failobj)
59 if key not in self._keys: self._keys.append(key)
61 def update(self, dict):
62 dict.update(self, dict)
63 for key in dict.keys():
64 if key not in self._keys: self._keys.append(key)
67 return map(self.get, self._keys)
70 def __init__(self, name):
71 self._signals = OrderedDict()
72 self._args = OrderedDict()
76 return "<Object %s>" % self.name
78 def add_signal(self, signal, overwrite=True):
79 if not overwrite and self._signals.has_key(signal.name):
80 raise IndexError, "signal %s already in %r" % (signal.name, self)
81 self._signals[signal.name] = signal
83 def add_arg(self, arg, overwrite=True):
84 if not overwrite and self._args.has_key(arg.name):
85 raise IndexError, "arg %s already in %r" % (arg.name, self)
86 self._args[arg.name] = arg
89 def __init__(self, **kwargs):
90 for key in self.attrs:
91 setattr(self, key, kwargs[key])
95 return "<%r %s>" % (str(self.__class__), self.name)
97 class Signal(Docable):
98 attrs = ['name', 'returns', 'args']
101 attrs = ['name', 'type', 'range', 'flags', 'nick', 'blurb', 'default']
104 def load_file(self, filename):
106 lines = open(filename).readlines()
107 self.load_data("".join(lines))
109 print "WARNING - could not read from %s" % filename
111 def save_file(self, filename, backup=False):
113 Save the signals information to the given .signals file if the
114 file content changed.
118 lines = open(filename).readlines()
119 olddata = "".join(lines)
121 print "WARNING - could not read from %s" % filename
122 newdata = self.get_data()
123 if olddata and olddata == newdata:
128 os.rename(filename, filename + '.bak')
130 handle = open(filename, "w")
131 handle.write(newdata)
136 self._objects = OrderedDict()
138 def load_data(self, data):
140 Load the .signals lines, creating our list of objects and signals.
143 smatcher = re.compile(
144 '(?s)' # make . match \n
145 '<SIGNAL>\n(.*?)</SIGNAL>\n'
147 nmatcher = re.compile(
149 '(?P<object>\S*)' # store object
151 '(?P<signal>\S*)' # store signal
154 rmatcher = re.compile(
155 '(?s)' # make . match \n
156 '<RETURNS>(?P<returns>\S*)</RETURNS>\n' # store returns
157 '(?P<args>.*)' # store args
159 for block in smatcher.findall(data):
160 nmatch = nmatcher.search(block)
162 o = nmatch.group('object')
163 debug("Found object", o)
164 debug("Found signal", nmatch.group('signal'))
165 if not self._objects.has_key(o):
167 self._objects[o] = object
169 rmatch = rmatcher.search(block)
171 dict = rmatch.groupdict().copy()
172 dict['name'] = nmatch.group('signal')
173 signal = Signal(**dict)
174 self._objects[o].add_signal(signal)
178 for o in self._objects.values():
179 for s in o._signals.values():
181 <NAME>%(object)s::%(name)s</NAME>
182 <RETURNS>%(returns)s</RETURNS>
187 lines.append(block % d)
189 return "\n".join(lines) + '\n'
193 self._objects = OrderedDict()
195 def load_data(self, data):
197 Load the .args lines, creating our list of objects and args.
200 amatcher = re.compile(
201 '(?s)' # make . match \n
202 '<ARG>\n(.*?)</ARG>\n'
204 nmatcher = re.compile(
206 '(?P<object>\S*)' # store object
208 '(?P<arg>\S*)' # store arg
211 rmatcher = re.compile(
212 '(?s)' # make . match \n
213 '<TYPE>(?P<type>\S*)</TYPE>\n' # store type
214 '<RANGE>(?P<range>.*?)</RANGE>\n' # store range
215 '<FLAGS>(?P<flags>\S*)</FLAGS>\n' # store flags
216 '<NICK>(?P<nick>.*?)</NICK>\n' # store nick
217 '<BLURB>(?P<blurb>.*?)</BLURB>\n' # store blurb
218 '<DEFAULT>(?P<default>.*?)</DEFAULT>\n' # store default
220 for block in amatcher.findall(data):
221 nmatch = nmatcher.search(block)
223 o = nmatch.group('object')
224 debug("Found object", o)
225 debug("Found arg", nmatch.group('arg'))
226 if not self._objects.has_key(o):
228 self._objects[o] = object
230 rmatch = rmatcher.search(block)
232 dict = rmatch.groupdict().copy()
233 dict['name'] = nmatch.group('arg')
235 self._objects[o].add_arg(arg)
237 print "ERROR: could not match arg from block %s" % block
241 for o in self._objects.values():
242 for a in o._args.values():
244 <NAME>%(object)s::%(name)s</NAME>
245 <TYPE>%(type)s</TYPE>
246 <RANGE>%(range)s</RANGE>
247 <FLAGS>%(flags)s</FLAGS>
248 <NICK>%(nick)s</NICK>
249 <BLURB>%(blurb)s</BLURB>
250 <DEFAULT>%(default)s</DEFAULT>
255 lines.append(block % d)
257 return "\n".join(lines) + '\n'
264 sys.stderr.write('Pleae provide a documentation module name\n')
267 print "Merging scangobj output for %s" % modulename
269 signals.load_file(modulename + '.signals')
270 signals.load_file(modulename + '.signals.new')
271 signals.save_file(modulename + '.signals', backup=True)
274 args.load_file(modulename + '.args')
275 args.load_file(modulename + '.args.new')
276 args.save_file(modulename + '.args', backup=True)