Merge lp:~verterok/ubuntuone-client/dbus-iface-docs into lp:ubuntuone-client
- dbus-iface-docs
- Merge into trunk
Proposed by
Guillermo Gonzalez
Status: | Merged |
---|---|
Approved by: | Rick McBride |
Approved revision: | not available |
Merged at revision: | not available |
Proposed branch: | lp:~verterok/ubuntuone-client/dbus-iface-docs |
Merge into: | lp:ubuntuone-client |
Diff against target: |
408 lines (+305/-32) 6 files modified
.bzrignore (+1/-0) Makefile.am (+4/-0) contrib/dbus-docs (+193/-0) contrib/dbus_util.py (+72/-0) contrib/test (+4/-32) ubuntuone/syncdaemon/dbus_interface.py (+31/-0) |
To merge this branch: | bzr merge lp:~verterok/ubuntuone-client/dbus-iface-docs |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Rick McBride (community) | Approve | ||
Eric Casteleijn (community) | Approve | ||
Review via email: mp+16259@code.launchpad.net |
Commit message
export method and signal docstrings via DBus Introspect, add script to generate a simple text file with SyncDaemon DBus API
Description of the change
To post a comment you must log in.
Revision history for this message
Guillermo Gonzalez (verterok) wrote : | # |
- 292. By Guillermo Gonzalez
-
remove commented code
Revision history for this message
Eric Casteleijn (thisfred) wrote : | # |
Looks good, tests pass.
review:
Approve
Revision history for this message
Rick McBride (rmcbride) wrote : | # |
Very nice! neat diagram too.
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file '.bzrignore' | |||
2 | --- .bzrignore 2009-07-15 21:47:57 +0000 | |||
3 | +++ .bzrignore 2009-12-16 20:33:18 +0000 | |||
4 | @@ -42,3 +42,4 @@ | |||
5 | 42 | icons | 42 | icons |
6 | 43 | storageprotocol | 43 | storageprotocol |
7 | 44 | clientdefs.py | 44 | clientdefs.py |
8 | 45 | docs/syncdaemon_dbus_api.txt | ||
9 | 45 | 46 | ||
10 | === modified file 'Makefile.am' | |||
11 | --- Makefile.am 2009-09-25 18:48:03 +0000 | |||
12 | +++ Makefile.am 2009-12-16 20:33:18 +0000 | |||
13 | @@ -62,6 +62,10 @@ | |||
14 | 62 | fi | 62 | fi |
15 | 63 | rm -rf _trial_temp | 63 | rm -rf _trial_temp |
16 | 64 | 64 | ||
17 | 65 | docs: protocol Makefile | ||
18 | 66 | PYTHONPATH="$(PYTHONPATH)" $(PYTHON) $(srcdir)/contrib/dbus-docs | ||
19 | 67 | |||
20 | 68 | |||
21 | 65 | protocol: ubuntuone Makefile | 69 | protocol: ubuntuone Makefile |
22 | 66 | PROTOCOL="ubuntuone/storageprotocol"; \ | 70 | PROTOCOL="ubuntuone/storageprotocol"; \ |
23 | 67 | if [ ! -d $(USP_PATH) ]; then \ | 71 | if [ ! -d $(USP_PATH) ]; then \ |
24 | 68 | 72 | ||
25 | === added file 'contrib/dbus-docs' | |||
26 | --- contrib/dbus-docs 1970-01-01 00:00:00 +0000 | |||
27 | +++ contrib/dbus-docs 2009-12-16 20:33:18 +0000 | |||
28 | @@ -0,0 +1,193 @@ | |||
29 | 1 | #!/usr/bin/env python | ||
30 | 2 | # | ||
31 | 3 | # Author: Guillermo Gonzalez <guillermo.gonzalez@canonical.com> | ||
32 | 4 | # | ||
33 | 5 | # Copyright 2009 Canonical Ltd. | ||
34 | 6 | # | ||
35 | 7 | # This program is free software: you can redistribute it and/or modify it | ||
36 | 8 | # under the terms of the GNU General Public License version 3, as published | ||
37 | 9 | # by the Free Software Foundation. | ||
38 | 10 | # | ||
39 | 11 | # This program is distributed in the hope that it will be useful, but | ||
40 | 12 | # WITHOUT ANY WARRANTY; without even the implied warranties of | ||
41 | 13 | # MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | ||
42 | 14 | # PURPOSE. See the GNU General Public License for more details. | ||
43 | 15 | # | ||
44 | 16 | # You should have received a copy of the GNU General Public License along | ||
45 | 17 | # with this program. If not, see <http://www.gnu.org/licenses/>. | ||
46 | 18 | |||
47 | 19 | from twisted.internet import glib2reactor | ||
48 | 20 | glib2reactor.install() | ||
49 | 21 | |||
50 | 22 | import sys | ||
51 | 23 | import os | ||
52 | 24 | import signal | ||
53 | 25 | import dbus | ||
54 | 26 | import subprocess | ||
55 | 27 | import shutil | ||
56 | 28 | |||
57 | 29 | from xml.etree import ElementTree | ||
58 | 30 | |||
59 | 31 | sys.path.insert(0, os.path.abspath(".")) | ||
60 | 32 | |||
61 | 33 | from contrib.dbus_util import DBusRunner | ||
62 | 34 | from contrib.testing.testcase import ( | ||
63 | 35 | FakeMain, | ||
64 | 36 | DBusGMainLoop, | ||
65 | 37 | DBusInterface, | ||
66 | 38 | FakeNetworkManager, | ||
67 | 39 | ) | ||
68 | 40 | |||
69 | 41 | from ubuntuone.syncdaemon.dbus_interface import ( | ||
70 | 42 | DBUS_IFACE_SYNC_NAME, | ||
71 | 43 | DBUS_IFACE_STATUS_NAME, | ||
72 | 44 | DBUS_IFACE_EVENTS_NAME, | ||
73 | 45 | DBUS_IFACE_FS_NAME, | ||
74 | 46 | DBUS_IFACE_SHARES_NAME, | ||
75 | 47 | DBUS_IFACE_CONFIG_NAME, | ||
76 | 48 | ) | ||
77 | 49 | from ubuntuone.syncdaemon.tools import DBusClient | ||
78 | 50 | from twisted.internet import reactor, defer | ||
79 | 51 | |||
80 | 52 | |||
81 | 53 | iface_path = ((DBUS_IFACE_SYNC_NAME, '/'), (DBUS_IFACE_CONFIG_NAME, '/config'), | ||
82 | 54 | (DBUS_IFACE_EVENTS_NAME, '/events'), | ||
83 | 55 | (DBUS_IFACE_FS_NAME, '/filesystem'), | ||
84 | 56 | (DBUS_IFACE_SHARES_NAME, '/shares'), | ||
85 | 57 | (DBUS_IFACE_STATUS_NAME, '/status')) | ||
86 | 58 | |||
87 | 59 | |||
88 | 60 | def parse_introspect_data(xml): | ||
89 | 61 | """Parse the xml returned by Introspect and returns a dict""" | ||
90 | 62 | info = dict() | ||
91 | 63 | e = ElementTree.fromstring(xml) | ||
92 | 64 | for c in e.findall('interface'): | ||
93 | 65 | # ignore other interfaces | ||
94 | 66 | if not c.attrib['name'].startswith('com.ubuntuone'): | ||
95 | 67 | continue | ||
96 | 68 | iface_name = c.attrib['name'] | ||
97 | 69 | info[iface_name] = dict() | ||
98 | 70 | # methods | ||
99 | 71 | methods = dict() | ||
100 | 72 | for method in c.findall('method'): | ||
101 | 73 | meth_name = method.attrib['name'] | ||
102 | 74 | args = [] | ||
103 | 75 | for arg in method.findall('arg'): | ||
104 | 76 | dir = arg.attrib['direction'] | ||
105 | 77 | type = arg.attrib['type'] | ||
106 | 78 | if 'name' in arg.attrib: | ||
107 | 79 | name = arg.attrib['name'] | ||
108 | 80 | args.append((type, dir, name)) | ||
109 | 81 | else: | ||
110 | 82 | args.append((type, dir)) | ||
111 | 83 | docstrings = method.findall('docstring') | ||
112 | 84 | docstring = docstrings[0].text if docstrings else 'No docstring' | ||
113 | 85 | methods[meth_name] = dict(args=args, docstring=docstring) | ||
114 | 86 | info[iface_name]['methods'] = methods | ||
115 | 87 | # signals | ||
116 | 88 | signals = dict() | ||
117 | 89 | for signal in c.findall('signal'): | ||
118 | 90 | sig_name = signal.attrib['name'] | ||
119 | 91 | args = [] | ||
120 | 92 | for arg in signal.findall('arg'): | ||
121 | 93 | type = arg.attrib['type'] | ||
122 | 94 | name = arg.attrib['name'] | ||
123 | 95 | args.append((type, name)) | ||
124 | 96 | docstrings = signal.findall('docstring') | ||
125 | 97 | docstring = docstrings[0].text if docstrings else 'No docstring' | ||
126 | 98 | signals[sig_name] = dict(args=args, docstring=docstring) | ||
127 | 99 | info[iface_name]['signals'] = signals | ||
128 | 100 | return info | ||
129 | 101 | |||
130 | 102 | |||
131 | 103 | def get_info(path): | ||
132 | 104 | """Get all the introspectable info from 'path'""" | ||
133 | 105 | d = defer.Deferred() | ||
134 | 106 | client = DBusClient(bus, path, 'org.freedesktop.DBus.Introspectable') | ||
135 | 107 | client.call_method('Introspect', reply_handler=d.callback, | ||
136 | 108 | error_handler=d.errback) | ||
137 | 109 | return d | ||
138 | 110 | |||
139 | 111 | |||
140 | 112 | def dump_to_stream(info_by_path, stream): | ||
141 | 113 | print >>stream, "SyncDaemon DBus API\n" | ||
142 | 114 | for path, interfaces in info_by_path.items(): | ||
143 | 115 | print >>stream, "Object path: %s" % path | ||
144 | 116 | for iface_name, kinds in interfaces.items(): | ||
145 | 117 | print >>stream, " Interface: %s" % iface_name | ||
146 | 118 | print >>stream, " Methods:" | ||
147 | 119 | for meth_name, val in kinds['methods'].items(): | ||
148 | 120 | in_args = ','.join([arg[2] + '=' + arg[0] for arg in | ||
149 | 121 | val['args'] if arg[1] == 'in']) | ||
150 | 122 | out_args = ','.join([arg[0] for arg in val['args'] | ||
151 | 123 | if arg[1] == 'out']) | ||
152 | 124 | if out_args and in_args: | ||
153 | 125 | print >>stream, " %s(%s) -> %s" % (meth_name, in_args, | ||
154 | 126 | out_args) | ||
155 | 127 | elif in_args: | ||
156 | 128 | print >>stream, " %s(%s)" % (meth_name, in_args) | ||
157 | 129 | else: | ||
158 | 130 | print >>stream, " %s()" % meth_name | ||
159 | 131 | print >>stream, " %s\n" % val['docstring'] | ||
160 | 132 | print >>stream, " Signals:" | ||
161 | 133 | for signal_name, val in kinds['signals'].items(): | ||
162 | 134 | in_args = ','.join([arg[1] + '=' + arg[0] \ | ||
163 | 135 | for arg in val['args']]) | ||
164 | 136 | if in_args: | ||
165 | 137 | print >>stream, " %s(%s)" % (signal_name, in_args) | ||
166 | 138 | else: | ||
167 | 139 | print >>stream, " %s(%s)" % signal_name | ||
168 | 140 | print >>stream, " %s\n" % val['docstring'] | ||
169 | 141 | |||
170 | 142 | |||
171 | 143 | @defer.inlineCallbacks | ||
172 | 144 | def main(bus): | ||
173 | 145 | """Entry point""" | ||
174 | 146 | info_by_path = dict() | ||
175 | 147 | for iface, path in iface_path: | ||
176 | 148 | xml = yield get_info(path) | ||
177 | 149 | obj_info = parse_introspect_data(xml) | ||
178 | 150 | info_by_path[path] = obj_info | ||
179 | 151 | dest_file = os.path.join(os.getcwd(), 'docs', 'syncdaemon_dbus_api.txt') | ||
180 | 152 | with open(dest_file, 'w') as f: | ||
181 | 153 | dump_to_stream(info_by_path, f) | ||
182 | 154 | reactor.stop() | ||
183 | 155 | |||
184 | 156 | |||
185 | 157 | def start_syncdaemon(tmp_dir): | ||
186 | 158 | """Starts a syncdaemon instance just like the one used in the test suite""" | ||
187 | 159 | xdg_cache = os.path.join(tmp_dir, 'xdg_cache') | ||
188 | 160 | data_dir = os.path.join(xdg_cache, 'data') | ||
189 | 161 | partials_dir = os.path.join(xdg_cache, 'partials') | ||
190 | 162 | root_dir = os.path.join(tmp_dir, 'root') | ||
191 | 163 | shares_dir = os.path.join(tmp_dir, 'shares') | ||
192 | 164 | main = FakeMain(root_dir, shares_dir, data_dir, partials_dir) | ||
193 | 165 | loop = DBusGMainLoop(set_as_default=True) | ||
194 | 166 | bus = dbus.bus.BusConnection(mainloop=loop) | ||
195 | 167 | nm = FakeNetworkManager(bus) | ||
196 | 168 | dbus_iface = DBusInterface(bus, main, system_bus=bus) | ||
197 | 169 | main.dbus_iface = dbus_iface | ||
198 | 170 | return main, bus | ||
199 | 171 | |||
200 | 172 | |||
201 | 173 | if __name__ == '__main__': | ||
202 | 174 | dbus_runner = DBusRunner() | ||
203 | 175 | dbus_runner.startDBus() | ||
204 | 176 | tmp_dir = os.path.join(os.getcwd(), 'tmp') | ||
205 | 177 | try: | ||
206 | 178 | |||
207 | 179 | m, bus = start_syncdaemon(tmp_dir) | ||
208 | 180 | try: | ||
209 | 181 | reactor.callWhenRunning(main, bus) | ||
210 | 182 | reactor.run() | ||
211 | 183 | finally: | ||
212 | 184 | m.quit() | ||
213 | 185 | finally: | ||
214 | 186 | dbus_runner.stopDBus() | ||
215 | 187 | # remove the tmp dir | ||
216 | 188 | os.chmod(tmp_dir, 0777) | ||
217 | 189 | for dirpath, dirs, _ in os.walk(tmp_dir): | ||
218 | 190 | for dir in dirs: | ||
219 | 191 | os.chmod(os.path.join(dirpath, dir), 0777) | ||
220 | 192 | shutil.rmtree(tmp_dir) | ||
221 | 193 | |||
222 | 0 | 194 | ||
223 | === added file 'contrib/dbus_util.py' | |||
224 | --- contrib/dbus_util.py 1970-01-01 00:00:00 +0000 | |||
225 | +++ contrib/dbus_util.py 2009-12-16 20:33:18 +0000 | |||
226 | @@ -0,0 +1,72 @@ | |||
227 | 1 | # | ||
228 | 2 | # Author: Guillermo Gonzalez <guillermo.gonzalez@canonical.com> | ||
229 | 3 | # | ||
230 | 4 | # Copyright 2009 Canonical Ltd. | ||
231 | 5 | # | ||
232 | 6 | # This program is free software: you can redistribute it and/or modify it | ||
233 | 7 | # under the terms of the GNU General Public License version 3, as published | ||
234 | 8 | # by the Free Software Foundation. | ||
235 | 9 | # | ||
236 | 10 | # This program is distributed in the hope that it will be useful, but | ||
237 | 11 | # WITHOUT ANY WARRANTY; without even the implied warranties of | ||
238 | 12 | # MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | ||
239 | 13 | # PURPOSE. See the GNU General Public License for more details. | ||
240 | 14 | # | ||
241 | 15 | # You should have received a copy of the GNU General Public License along | ||
242 | 16 | # with this program. If not, see <http://www.gnu.org/licenses/>. | ||
243 | 17 | |||
244 | 18 | import os | ||
245 | 19 | import signal | ||
246 | 20 | import subprocess | ||
247 | 21 | |||
248 | 22 | from distutils.spawn import find_executable | ||
249 | 23 | |||
250 | 24 | |||
251 | 25 | class DBusLaunchError(Exception): | ||
252 | 26 | """Error while launching dbus-daemon""" | ||
253 | 27 | pass | ||
254 | 28 | |||
255 | 29 | class NotFoundError(Exception): | ||
256 | 30 | """Not found error""" | ||
257 | 31 | pass | ||
258 | 32 | |||
259 | 33 | |||
260 | 34 | class DBusRunner(object): | ||
261 | 35 | |||
262 | 36 | def __init__(self): | ||
263 | 37 | self.dbus_address = None | ||
264 | 38 | self.dbus_pid = None | ||
265 | 39 | self.running = False | ||
266 | 40 | |||
267 | 41 | def startDBus(self): | ||
268 | 42 | """Start our own session bus daemon for testing.""" | ||
269 | 43 | dbus = find_executable("dbus-daemon") | ||
270 | 44 | if not dbus: | ||
271 | 45 | raise NotFoundError("dbus-daemon was not found.") | ||
272 | 46 | |||
273 | 47 | config_file = os.path.join(os.getcwd(), "contrib", "testing", | ||
274 | 48 | "dbus-session.conf") | ||
275 | 49 | dbus_args = ["--fork", | ||
276 | 50 | "--config-file=" + config_file, | ||
277 | 51 | "--print-address=1", | ||
278 | 52 | "--print-pid=2"] | ||
279 | 53 | p = subprocess.Popen([dbus] + dbus_args, | ||
280 | 54 | bufsize=4096, stdout=subprocess.PIPE, | ||
281 | 55 | stderr=subprocess.PIPE) | ||
282 | 56 | |||
283 | 57 | self.dbus_address = "".join(p.stdout.readlines()).strip() | ||
284 | 58 | self.dbus_pid = int("".join(p.stderr.readlines()).strip()) | ||
285 | 59 | |||
286 | 60 | if self.dbus_address != "": | ||
287 | 61 | os.environ["DBUS_SESSION_BUS_ADDRESS"] = self.dbus_address | ||
288 | 62 | else: | ||
289 | 63 | os.kill(self.dbus_pid, signal.SIGKILL) | ||
290 | 64 | raise DBusLaunchError("There was a problem launching dbus-daemon.") | ||
291 | 65 | self.running = True | ||
292 | 66 | |||
293 | 67 | def stopDBus(self): | ||
294 | 68 | """Stop our DBus session bus daemon.""" | ||
295 | 69 | del os.environ["DBUS_SESSION_BUS_ADDRESS"] | ||
296 | 70 | os.kill(self.dbus_pid, signal.SIGKILL) | ||
297 | 71 | self.running = False | ||
298 | 72 | |||
299 | 0 | 73 | ||
300 | === modified file 'contrib/test' | |||
301 | --- contrib/test 2009-11-06 19:31:17 +0000 | |||
302 | +++ contrib/test 2009-12-16 20:33:18 +0000 | |||
303 | @@ -66,36 +66,6 @@ | |||
304 | 66 | suite.addTests(module_suite) | 66 | suite.addTests(module_suite) |
305 | 67 | return suite | 67 | return suite |
306 | 68 | 68 | ||
307 | 69 | def startDBus(self): | ||
308 | 70 | """Start our own session bus daemon for testing.""" | ||
309 | 71 | dbus = find_executable("dbus-daemon") | ||
310 | 72 | if not dbus: | ||
311 | 73 | raise NotFoundError("dbus-daemon was not found.") | ||
312 | 74 | |||
313 | 75 | config_file = os.path.join(os.getcwd(), "contrib", "testing", | ||
314 | 76 | "dbus-session.conf") | ||
315 | 77 | dbus_args = ["--fork", | ||
316 | 78 | "--config-file=" + config_file, | ||
317 | 79 | "--print-address=1", | ||
318 | 80 | "--print-pid=2"] | ||
319 | 81 | p = subprocess.Popen([dbus] + dbus_args, | ||
320 | 82 | bufsize=4096, stdout=subprocess.PIPE, | ||
321 | 83 | stderr=subprocess.PIPE) | ||
322 | 84 | |||
323 | 85 | self.dbus_address = "".join(p.stdout.readlines()).strip() | ||
324 | 86 | self.dbus_pid = int("".join(p.stderr.readlines()).strip()) | ||
325 | 87 | |||
326 | 88 | if self.dbus_address != "": | ||
327 | 89 | os.environ["DBUS_SESSION_BUS_ADDRESS"] = self.dbus_address | ||
328 | 90 | else: | ||
329 | 91 | os.kill(self.dbus_pid, signal.SIGKILL) | ||
330 | 92 | raise DBusLaunchError("There was a problem launching dbus-daemon.") | ||
331 | 93 | |||
332 | 94 | def stopDBus(self): | ||
333 | 95 | """Stop our DBus session bus daemon.""" | ||
334 | 96 | del os.environ["DBUS_SESSION_BUS_ADDRESS"] | ||
335 | 97 | os.kill(self.dbus_pid, signal.SIGKILL) | ||
336 | 98 | |||
337 | 99 | def run(self, testpath, test_pattern=None): | 69 | def run(self, testpath, test_pattern=None): |
338 | 100 | """run the tests. """ | 70 | """run the tests. """ |
339 | 101 | # install the glib2reactor before any import of the reactor to avoid | 71 | # install the glib2reactor before any import of the reactor to avoid |
340 | @@ -106,7 +76,9 @@ | |||
341 | 106 | from twisted.trial.reporter import TreeReporter | 76 | from twisted.trial.reporter import TreeReporter |
342 | 107 | from twisted.trial.runner import TrialRunner | 77 | from twisted.trial.runner import TrialRunner |
343 | 108 | 78 | ||
345 | 109 | self.startDBus() | 79 | from contrib.dbus_util import DBusRunner |
346 | 80 | dbus_runner = DBusRunner() | ||
347 | 81 | dbus_runner.startDBus() | ||
348 | 110 | 82 | ||
349 | 111 | workingDirectory = os.path.join(os.getcwd(), "_trial_temp", "tmp") | 83 | workingDirectory = os.path.join(os.getcwd(), "_trial_temp", "tmp") |
350 | 112 | runner = TrialRunner(reporterFactory=TreeReporter, realTimeErrors=True, | 84 | runner = TrialRunner(reporterFactory=TreeReporter, realTimeErrors=True, |
351 | @@ -125,7 +97,7 @@ | |||
352 | 125 | result = runner.run(suite) | 97 | result = runner.run(suite) |
353 | 126 | success = result.wasSuccessful() | 98 | success = result.wasSuccessful() |
354 | 127 | finally: | 99 | finally: |
356 | 128 | self.stopDBus() | 100 | dbus_runner.stopDBus() |
357 | 129 | if not success: | 101 | if not success: |
358 | 130 | sys.exit(1) | 102 | sys.exit(1) |
359 | 131 | else: | 103 | else: |
360 | 132 | 104 | ||
361 | === modified file 'ubuntuone/syncdaemon/dbus_interface.py' | |||
362 | --- ubuntuone/syncdaemon/dbus_interface.py 2009-12-07 20:49:54 +0000 | |||
363 | +++ ubuntuone/syncdaemon/dbus_interface.py 2009-12-16 20:33:18 +0000 | |||
364 | @@ -22,6 +22,7 @@ | |||
365 | 22 | 22 | ||
366 | 23 | from dbus import DBusException | 23 | from dbus import DBusException |
367 | 24 | from itertools import groupby, chain | 24 | from itertools import groupby, chain |
368 | 25 | from xml.etree import ElementTree | ||
369 | 25 | 26 | ||
370 | 26 | from twisted.internet import defer | 27 | from twisted.internet import defer |
371 | 27 | from twisted.python.failure import Failure | 28 | from twisted.python.failure import Failure |
372 | @@ -90,6 +91,36 @@ | |||
373 | 90 | """ emit's a Error signal. """ | 91 | """ emit's a Error signal. """ |
374 | 91 | self.SignalError(signal, extra_args) | 92 | self.SignalError(signal, extra_args) |
375 | 92 | 93 | ||
376 | 94 | @classmethod | ||
377 | 95 | def _add_docstring(cls, func, reflection_data): | ||
378 | 96 | """add <docstring> tag to reflection_data if func.__doc__ isn't None.""" | ||
379 | 97 | # add docstring element | ||
380 | 98 | if getattr(func, '__doc__', None) is not None: | ||
381 | 99 | |||
382 | 100 | element = ElementTree.fromstring(reflection_data) | ||
383 | 101 | doc = element.makeelement('docstring', dict()) | ||
384 | 102 | data = '<![CDATA[' + func.__doc__ + ']]>' | ||
385 | 103 | doc.text = '%s' | ||
386 | 104 | element.insert(0, doc) | ||
387 | 105 | return ElementTree.tostring(element) % data | ||
388 | 106 | else: | ||
389 | 107 | return reflection_data | ||
390 | 108 | |||
391 | 109 | @classmethod | ||
392 | 110 | def _reflect_on_method(cls, func): | ||
393 | 111 | """override _reflect_on_method to provide an extra <docstring> element | ||
394 | 112 | in the xml. | ||
395 | 113 | """ | ||
396 | 114 | reflection_data = dbus.service.Object._reflect_on_method(func) | ||
397 | 115 | reflection_data = cls._add_docstring(func, reflection_data) | ||
398 | 116 | return reflection_data | ||
399 | 117 | |||
400 | 118 | @classmethod | ||
401 | 119 | def _reflect_on_signal(cls, func): | ||
402 | 120 | reflection_data = dbus.service.Object._reflect_on_signal(func) | ||
403 | 121 | reflection_data = cls._add_docstring(func, reflection_data) | ||
404 | 122 | return reflection_data | ||
405 | 123 | |||
406 | 93 | 124 | ||
407 | 94 | class Status(DBusExposedObject): | 125 | class Status(DBusExposedObject): |
408 | 95 | """ Represent the status of the syncdaemon """ | 126 | """ Represent the status of the syncdaemon """ |
This branch adds a script to generate simple text file with the syncdaemon DBus API description.
In order to include the method docstrings I overrided a dbus-python magic method in the parent class of the DBus exposed objects to add an extra <docstring> tag to the Introspect xml, so we can get all the information directly from DBus
Also adds a new make target: 'docs'.