Merge lp:~dobey/ubuntu/natty/ubuntuone-dev-tools/devtools-012 into lp:ubuntu/natty/ubuntuone-dev-tools
- Natty (11.04)
- devtools-012
- Merge into natty
Proposed by
dobey
Status: | Merged |
---|---|
Merged at revision: | 3 |
Proposed branch: | lp:~dobey/ubuntu/natty/ubuntuone-dev-tools/devtools-012 |
Merge into: | lp:ubuntu/natty/ubuntuone-dev-tools |
Diff against target: |
1346 lines (+649/-290) 17 files modified
MANIFEST.in (+1/-1) PKG-INFO (+1/-1) bin/u1lint (+56/-49) bin/u1trial (+107/-55) debian/changelog (+11/-0) debian/control (+12/-6) debian/rules (+1/-1) debian/watch (+1/-1) pylintrc (+223/-36) run-tests (+23/-0) setup.py (+9/-9) ubuntuone/devtools/__init__.py (+0/-1) ubuntuone/devtools/dbus_util.py (+0/-89) ubuntuone/devtools/handlers.py (+64/-0) ubuntuone/devtools/services/__init__.py (+1/-0) ubuntuone/devtools/services/dbus.py (+94/-0) ubuntuone/devtools/testcase.py (+45/-41) |
To merge this branch: | bzr merge lp:~dobey/ubuntu/natty/ubuntuone-dev-tools/devtools-012 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Daniel Holbach (community) | Approve | ||
Ubuntu branches | Pending | ||
Review via email: mp+42295@code.launchpad.net |
Commit message
Description of the change
* New upstream release.
* Fix debian/watch to use the right file extension.
* Remove python-oauth as a dependency.
* Update build and runtime dependencies.
* Require pep8 to run tests during build.
* Use ./run-tests during the build instead of setup.py lint to run tests.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'MANIFEST.in' |
2 | --- MANIFEST.in 2010-08-02 13:45:54 +0000 |
3 | +++ MANIFEST.in 2010-11-30 19:41:01 +0000 |
4 | @@ -1,4 +1,4 @@ |
5 | include MANIFEST.in |
6 | -include COPYING pylintrc |
7 | +include COPYING pylintrc run-tests |
8 | recursive-include data *.conf |
9 | recursive-include man *.1 |
10 | |
11 | === modified file 'PKG-INFO' |
12 | --- PKG-INFO 2010-08-02 13:45:54 +0000 |
13 | +++ PKG-INFO 2010-11-30 19:41:01 +0000 |
14 | @@ -1,6 +1,6 @@ |
15 | Metadata-Version: 1.0 |
16 | Name: ubuntuone-dev-tools |
17 | -Version: 0.1.1 |
18 | +Version: 0.1.2 |
19 | Summary: Ubuntu One development tools and utilities |
20 | Home-page: http://launchpad.net/ubuntuone-dev-tools |
21 | Author: UNKNOWN |
22 | |
23 | === modified file 'bin/u1lint' |
24 | --- bin/u1lint 2010-08-02 13:45:54 +0000 |
25 | +++ bin/u1lint 2010-11-30 19:41:01 +0000 |
26 | @@ -6,18 +6,19 @@ |
27 | # |
28 | # Copyright 2009-2010 Canonical Ltd. |
29 | # |
30 | -# This program is free software: you can redistribute it and/or modify it |
31 | -# under the terms of the GNU General Public License version 3, as published |
32 | +# This program is free software: you can redistribute it and/or modify it |
33 | +# under the terms of the GNU General Public License version 3, as published |
34 | # by the Free Software Foundation. |
35 | # |
36 | -# This program is distributed in the hope that it will be useful, but |
37 | -# WITHOUT ANY WARRANTY; without even the implied warranties of |
38 | -# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
39 | +# This program is distributed in the hope that it will be useful, but |
40 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
41 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
42 | # PURPOSE. See the GNU General Public License for more details. |
43 | # |
44 | -# You should have received a copy of the GNU General Public License along |
45 | +# You should have received a copy of the GNU General Public License along |
46 | # with this program. If not, see <http://www.gnu.org/licenses/>. |
47 | -"""Wrapper script for pylint command""" |
48 | + |
49 | +"""Wrapper script for pylint command.""" |
50 | |
51 | import ConfigParser |
52 | import os |
53 | @@ -104,45 +105,51 @@ |
54 | return pyfiles |
55 | |
56 | |
57 | -failed = False |
58 | - |
59 | -ignored = _read_pylintrc_ignored() |
60 | - |
61 | -# So that we can match the path correctly |
62 | -if ignored: |
63 | - moreignores = [os.path.join(SRCDIR, item) for item in ignored] |
64 | - ignored.extend(moreignores) |
65 | -else: |
66 | - ignored = [] |
67 | - |
68 | -if os.environ.get('USE_PYFLAKES'): |
69 | - pylint_args = ["pyflakes"] |
70 | -else: |
71 | - pylint_args = ["pylint", |
72 | - "--output-format=parseable", |
73 | - "--include-ids=yes",] |
74 | - if PYLINTRC: |
75 | - pylint_args.append("--rcfile=" + PYLINTRC) |
76 | - |
77 | -for path in _find_files(): |
78 | - if path not in ignored and not path.startswith(os.path.join(SRCDIR, |
79 | - "_build")): |
80 | - pylint_args.append(path) |
81 | - |
82 | -p = subprocess.Popen(pylint_args, |
83 | - bufsize=4096, stdout=subprocess.PIPE) |
84 | -notices = p.stdout |
85 | - |
86 | -output = "".join(notices.readlines()) |
87 | -if output != "": |
88 | - print "== Python Lint Notices ==" |
89 | - (failed, grouped) = _group_lines_by_file(output) |
90 | - print grouped |
91 | - print "" |
92 | - |
93 | -returncode = p.wait() |
94 | -if returncode != 0: |
95 | - exit(returncode) |
96 | - |
97 | -if failed: |
98 | - exit(1) |
99 | +def main(): |
100 | + """Do the deed.""" |
101 | + failed = False |
102 | + ignored = _read_pylintrc_ignored() |
103 | + |
104 | + # So that we can match the path correctly |
105 | + if ignored: |
106 | + moreignores = [os.path.join(SRCDIR, item) for item in ignored] |
107 | + ignored.extend(moreignores) |
108 | + else: |
109 | + ignored = [] |
110 | + |
111 | + if os.environ.get('USE_PYFLAKES'): |
112 | + pylint_args = ["pyflakes"] |
113 | + else: |
114 | + pylint_args = ["pylint", |
115 | + "--output-format=parseable", |
116 | + "--include-ids=yes",] |
117 | + if PYLINTRC: |
118 | + pylint_args.append("--rcfile=" + PYLINTRC) |
119 | + |
120 | + for path in _find_files(): |
121 | + is_build = path.startswith(os.path.join(SRCDIR, "_build")) |
122 | + if path not in ignored and not is_build: |
123 | + pylint_args.append(path) |
124 | + |
125 | + sp = subprocess.Popen(pylint_args, |
126 | + bufsize=4096, stdout=subprocess.PIPE) |
127 | + notices = sp.stdout |
128 | + |
129 | + output = "".join(notices.readlines()) |
130 | + if output != "": |
131 | + print "== Python Lint Notices ==" |
132 | + (failed, grouped) = _group_lines_by_file(output) |
133 | + print grouped |
134 | + print "" |
135 | + |
136 | + returncode = sp.wait() |
137 | + # XXX Testing that W0511 does not cause a failure |
138 | + if failed: |
139 | + if returncode != 0: |
140 | + exit(returncode) |
141 | + else: |
142 | + exit(1) |
143 | + |
144 | + |
145 | +if __name__ == '__main__': |
146 | + main() |
147 | |
148 | === modified file 'bin/u1trial' |
149 | --- bin/u1trial 2010-08-02 13:45:54 +0000 |
150 | +++ bin/u1trial 2010-11-30 19:41:01 +0000 |
151 | @@ -6,38 +6,78 @@ |
152 | # |
153 | # Copyright 2009-2010 Canonical Ltd. |
154 | # |
155 | -# This program is free software: you can redistribute it and/or modify it |
156 | -# under the terms of the GNU General Public License version 3, as published |
157 | +# This program is free software: you can redistribute it and/or modify it |
158 | +# under the terms of the GNU General Public License version 3, as published |
159 | # by the Free Software Foundation. |
160 | # |
161 | -# This program is distributed in the hope that it will be useful, but |
162 | -# WITHOUT ANY WARRANTY; without even the implied warranties of |
163 | -# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
164 | +# This program is distributed in the hope that it will be useful, but |
165 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
166 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
167 | # PURPOSE. See the GNU General Public License for more details. |
168 | # |
169 | -# You should have received a copy of the GNU General Public License along |
170 | +# You should have received a copy of the GNU General Public License along |
171 | # with this program. If not, see <http://www.gnu.org/licenses/>. |
172 | + |
173 | """Test runner that uses a private dbus session and glib main loop.""" |
174 | |
175 | +import coverage |
176 | +import gc |
177 | +import inspect |
178 | import os |
179 | import re |
180 | import sys |
181 | import unittest |
182 | |
183 | +from twisted.trial.runner import TrialRunner |
184 | + |
185 | sys.path.insert(0, os.path.abspath(".")) |
186 | |
187 | -# pylint: disable=W0212 |
188 | |
189 | -class TestRunner(object): |
190 | +class TestRunner(TrialRunner): |
191 | """The test runner implementation.""" |
192 | |
193 | + def __init__(self): |
194 | + # install the glib2reactor before any import of the reactor to avoid |
195 | + # using the default SelectReactor and be able to run the dbus tests |
196 | + from twisted.internet import glib2reactor |
197 | + glib2reactor.install() |
198 | + from twisted.trial.reporter import TreeReporter |
199 | + |
200 | + # setup a custom XDG_CACHE_HOME and create the logs directory |
201 | + xdg_cache = os.path.join(os.getcwd(), "_trial_temp", "xdg_cache") |
202 | + os.environ["XDG_CACHE_HOME"] = xdg_cache |
203 | + # setup the ROOTDIR env var |
204 | + os.environ['ROOTDIR'] = os.getcwd() |
205 | + if not os.path.exists(xdg_cache): |
206 | + os.makedirs(xdg_cache) |
207 | + |
208 | + self.tempdir = os.path.join(os.getcwd(), "_trial_temp") |
209 | + working_dir = os.path.join(self.tempdir, 'tmp') |
210 | + super(TestRunner, self).__init__(reporterFactory=TreeReporter, |
211 | + realTimeErrors=True, |
212 | + workingDirectory=working_dir, |
213 | + forceGarbageCollection=True) |
214 | + self.required_services = [] |
215 | + self.source_files = [] |
216 | + |
217 | def _load_unittest(self, relpath): |
218 | - """Load unit tests from a Python module with the given relative path.""" |
219 | + """Load unit tests from a Python module with the given 'relpath'.""" |
220 | assert relpath.endswith(".py"), ( |
221 | "%s does not appear to be a Python module" % relpath) |
222 | + if not os.path.basename(relpath).startswith('test_'): |
223 | + return |
224 | modpath = relpath.replace(os.path.sep, ".")[:-3] |
225 | module = __import__(modpath, None, None, [""]) |
226 | |
227 | + # If the module specifies required_services, make sure we get them |
228 | + members = [x[1] for x in inspect.getmembers(module, inspect.isclass)] |
229 | + for member_type in members: |
230 | + if hasattr(member_type, 'required_services'): |
231 | + member = member_type() |
232 | + self.required_services.extend(member.required_services()) |
233 | + del member |
234 | + gc.collect() |
235 | + |
236 | # If the module has a 'suite' or 'test_suite' function, use that |
237 | # to load the tests. |
238 | if hasattr(module, "suite"): |
239 | @@ -53,8 +93,11 @@ |
240 | if test_pattern: |
241 | pattern = re.compile('.*%s.*' % test_pattern) |
242 | else: |
243 | - pattern = None |
244 | + pattern = None |
245 | |
246 | + # Disable this lint warning as we need to access _tests in the |
247 | + # test suites, to collect the tests |
248 | + # pylint: disable=W0212 |
249 | if path: |
250 | try: |
251 | module_suite = self._load_unittest(path) |
252 | @@ -69,83 +112,92 @@ |
253 | except AssertionError: |
254 | pass |
255 | else: |
256 | - parser.print_help() |
257 | + print 'Path should be defined.' |
258 | exit(1) |
259 | |
260 | # We don't use the dirs variable, so ignore the warning |
261 | # pylint: disable=W0612 |
262 | for root, dirs, files in os.walk(path): |
263 | for test in files: |
264 | - path = os.path.join(root, test) |
265 | - if test.endswith(".py") and test.startswith("test_"): |
266 | - module_suite = self._load_unittest(path) |
267 | - if pattern: |
268 | - for inner_suite in module_suite._tests: |
269 | - for test in inner_suite._tests: |
270 | - if pattern.match(test.id()): |
271 | - suite.addTest(test) |
272 | - else: |
273 | - suite.addTests(module_suite) |
274 | + filepath = os.path.join(root, test) |
275 | + if test.endswith(".py"): |
276 | + self.source_files.append(filepath) |
277 | + if test.startswith("test_"): |
278 | + module_suite = self._load_unittest(filepath) |
279 | + if pattern: |
280 | + for inner_suite in module_suite._tests: |
281 | + for test in inner_suite._tests: |
282 | + if pattern.match(test.id()): |
283 | + suite.addTest(test) |
284 | + else: |
285 | + suite.addTests(module_suite) |
286 | return suite |
287 | |
288 | - def run(self, path, test_pattern=None, loops=None): |
289 | - """run the tests. """ |
290 | - # install the glib2reactor before any import of the reactor to avoid |
291 | - # using the default SelectReactor and be able to run the dbus tests |
292 | - from twisted.internet import glib2reactor |
293 | - glib2reactor.install() |
294 | - from twisted.trial.reporter import TreeReporter |
295 | - from twisted.trial.runner import TrialRunner |
296 | - |
297 | - from ubuntuone.devtools.dbus_util import DBusRunner |
298 | - dbus_runner = DBusRunner() |
299 | - dbus_runner.startDBus() |
300 | - |
301 | - working_dir = os.path.join(os.getcwd(), "_trial_temp", "tmp") |
302 | - runner = TrialRunner(reporterFactory=TreeReporter, realTimeErrors=True, |
303 | - workingDirectory=working_dir) |
304 | - |
305 | - # setup a custom XDG_CACHE_HOME and create the logs directory |
306 | - xdg_cache = os.path.join(os.getcwd(), "_trial_temp", "xdg_cache") |
307 | - os.environ["XDG_CACHE_HOME"] = xdg_cache |
308 | - # setup the ROOTDIR env var |
309 | - os.environ['ROOTDIR'] = os.getcwd() |
310 | - if not os.path.exists(xdg_cache): |
311 | - os.makedirs(xdg_cache) |
312 | + # pylint: disable=E0202 |
313 | + def run(self, path, options=None): |
314 | + """run the tests.""" |
315 | success = 0 |
316 | + running_services = [] |
317 | + if options.coverage: |
318 | + coverage.erase() |
319 | + coverage.start() |
320 | + |
321 | try: |
322 | - suite = self._collect_tests(path, test_pattern) |
323 | - if loops: |
324 | + suite = self._collect_tests(path, options.test) |
325 | + if options.loops: |
326 | old_suite = suite |
327 | suite = unittest.TestSuite() |
328 | - for _ in xrange(loops): |
329 | + for _ in xrange(options.loops): |
330 | suite.addTest(old_suite) |
331 | - result = runner.run(suite) |
332 | + |
333 | + # Start any required services |
334 | + for service in self.required_services: |
335 | + runner = service() |
336 | + runner.start_service(tempdir=self.tempdir) |
337 | + running_services.append(runner) |
338 | + |
339 | + result = super(TestRunner, self).run(suite) |
340 | success = result.wasSuccessful() |
341 | finally: |
342 | - dbus_runner.stopDBus() |
343 | + # Stop all the running services |
344 | + for runner in running_services: |
345 | + runner.stop_service() |
346 | + |
347 | + if options.coverage: |
348 | + coverage.stop() |
349 | + coverage.report(self.source_files, ignore_errors=True, |
350 | + show_missing=False) |
351 | + |
352 | if not success: |
353 | sys.exit(1) |
354 | else: |
355 | sys.exit(0) |
356 | |
357 | |
358 | -if __name__ == '__main__': |
359 | +def main(): |
360 | + """Do the deed.""" |
361 | from optparse import OptionParser |
362 | usage = '%prog [options] path' |
363 | parser = OptionParser(usage=usage) |
364 | parser.add_option("-t", "--test", dest="test", |
365 | help = "run specific tests, e.g: className.methodName") |
366 | parser.add_option("-l", "--loop", dest="loops", type="int", default=1, |
367 | - help = "loop selected tests LOOPS number of times", |
368 | + help = "loop selected tests LOOPS number of times", |
369 | metavar="LOOPS") |
370 | + parser.add_option("-c", "--coverage", action="store_true", dest="coverage", |
371 | + help="print a coverage report when finished") |
372 | |
373 | (options, args) = parser.parse_args() |
374 | if args: |
375 | testpath = args[0] |
376 | if not os.path.exists(testpath): |
377 | print "the path to test does not exists!" |
378 | - sys.exit() |
379 | + sys.exit(1) |
380 | else: |
381 | - testpath = None |
382 | - TestRunner().run(testpath, options.test, options.loops) |
383 | + parser.print_help() |
384 | + sys.exit(2) |
385 | + |
386 | + TestRunner().run(testpath, options) |
387 | + |
388 | +if __name__ == '__main__': |
389 | + main() |
390 | |
391 | === modified file 'debian/changelog' |
392 | --- debian/changelog 2010-08-02 13:45:54 +0000 |
393 | +++ debian/changelog 2010-11-30 19:41:01 +0000 |
394 | @@ -1,3 +1,14 @@ |
395 | +ubuntuone-dev-tools (0.1.2-0ubuntu1) natty; urgency=low |
396 | + |
397 | + * New upstream release. |
398 | + * Fix debian/watch to use the right file extension. |
399 | + * Remove python-oauth as a dependency. |
400 | + * Update build and runtime dependencies. |
401 | + * Require pep8 to run tests during build. |
402 | + * Use ./run-tests during the build instead of setup.py lint to run tests. |
403 | + |
404 | + -- Rodney Dawes <rodney.dawes@ubuntu.com> Mon, 29 Nov 2010 13:43:06 -0500 |
405 | + |
406 | ubuntuone-dev-tools (0.1.1-0ubuntu1) maverick; urgency=low |
407 | |
408 | * Initial packaging for ubuntuone-dev-tools. (LP:#610576) |
409 | |
410 | === modified file 'debian/control' |
411 | --- debian/control 2010-08-02 13:45:54 +0000 |
412 | +++ debian/control 2010-11-30 19:41:01 +0000 |
413 | @@ -5,20 +5,23 @@ |
414 | Priority: optional |
415 | Standards-Version: 3.9.1 |
416 | Build-Depends-Indep: |
417 | + dbus, |
418 | + pep8, |
419 | + pylint (>= 0.21.0), |
420 | + python-coverage, |
421 | + python-dbus, |
422 | + python-gobject, |
423 | python-setuptools, |
424 | python-support, |
425 | - python-xdg, |
426 | python-twisted-core, |
427 | - python-dbus, |
428 | - python-oauth, |
429 | - pylint (>= 0.21.0) |
430 | + python-xdg |
431 | Build-Depends: cdbs (>= 0.4.43), debhelper (>= 7.0.17), python-all |
432 | Homepage: http://launchpad.net/ubuntuone-dev-tools |
433 | |
434 | Package: python-ubuntuone-devtools |
435 | Architecture: all |
436 | Depends: ${python:Depends}, ${misc:Depends}, |
437 | - python-oauth, |
438 | + dbus, |
439 | python-dbus |
440 | Description: Ubuntu One development tools - Python modules |
441 | Ubuntu One development tools provides scripts, test cases, and other |
442 | @@ -29,8 +32,11 @@ |
443 | Package: ubuntuone-dev-tools |
444 | Architecture: all |
445 | Depends: ${python:Depends}, ${misc:Depends}, python, |
446 | + pylint (>= 0.21.0) | pyflakes, |
447 | + python-coverage, |
448 | + python-gobject, |
449 | + python-twisted-core, |
450 | python-ubuntuone-devtools (= ${binary:Version}), |
451 | - python-twisted-core, |
452 | python-xdg |
453 | Description: Ubuntu One development tools |
454 | Ubuntu One development tools provides scripts, test cases, and other |
455 | |
456 | === modified file 'debian/rules' |
457 | --- debian/rules 2010-08-02 13:45:54 +0000 |
458 | +++ debian/rules 2010-11-30 19:41:01 +0000 |
459 | @@ -6,7 +6,7 @@ |
460 | |
461 | common-build-arch common-build-indep:: debian/stamp-check |
462 | debian/stamp-check: |
463 | - cd $(DEB_SRCDIR) && $(call cdbs_python_binary,python$(cdbs_python_compile_version)) $(DEB_PYTHON_SETUP_CMD) lint |
464 | + cd $(DEB_SRCDIR) && ./run-tests |
465 | touch $@ |
466 | |
467 | makefile-clean:: |
468 | |
469 | === modified file 'debian/watch' |
470 | --- debian/watch 2010-08-02 13:45:54 +0000 |
471 | +++ debian/watch 2010-11-30 19:41:01 +0000 |
472 | @@ -1,3 +1,3 @@ |
473 | version=3 |
474 | -http://launchpad.net/ubuntuone-dev-tools/+download .*/ubuntuone-dev-tools-([0-9.]+)\.tar\.bz2 |
475 | +http://launchpad.net/ubuntuone-dev-tools/+download .*/ubuntuone-dev-tools-([0-9.]+)\.tar\.gz |
476 | |
477 | |
478 | === modified file 'pylintrc' |
479 | --- pylintrc 2010-08-02 13:45:54 +0000 |
480 | +++ pylintrc 2010-11-30 19:41:01 +0000 |
481 | @@ -1,39 +1,137 @@ |
482 | # lint Python modules using external checkers. |
483 | # |
484 | -# This is the main checker controling the other ones and the reports |
485 | +# This is the main checker controlling the other ones and the reports |
486 | # generation. It is itself both a raw checker and an astng checker in order |
487 | # to: |
488 | # * handle message activation / deactivation at the module level |
489 | -# * handle some basic but necessary stats data (number of classes, methods...) |
490 | +# * handle some basic but necessary stats'data (number of classes, methods...) |
491 | # |
492 | [MASTER] |
493 | -# Set the cache size for astng objects. |
494 | -cache-size=500 |
495 | + |
496 | +# Specify a configuration file. |
497 | +#rcfile= |
498 | + |
499 | +# Python code to execute, usually for sys.path manipulation such as |
500 | +# pygtk.require(). |
501 | +#init-hook= |
502 | + |
503 | +# Profiled execution. |
504 | +profile=no |
505 | + |
506 | +# Add <file or directory> to the black list. It should be a base name, not a |
507 | +# path. You may set this option multiple times. |
508 | +#ignore=<somedir> |
509 | + |
510 | +# Pickle collected data for later comparisons. |
511 | +persistent=no |
512 | + |
513 | +# List of plugins (as comma separated values of python modules names) to load, |
514 | +# usually to register additional checkers. |
515 | +load-plugins= |
516 | + |
517 | |
518 | [MESSAGES CONTROL] |
519 | -# Disable some checkers |
520 | + |
521 | +# Enable only checker(s) with the given id(s). This option conflicts with the |
522 | +# disable-checker option |
523 | +#enable-checker= |
524 | + |
525 | +# Enable all checker(s) except those with the given id(s). This option |
526 | +# conflicts with the enable-checker option |
527 | +#disable-checker= |
528 | + |
529 | +# Enable all messages in the listed categories. |
530 | +#enable-cat= |
531 | + |
532 | # Disable all messages in the listed categories. |
533 | -# Disable the message(s) with the given id(s). |
534 | -# :E0101: *Explicit return in __init__* |
535 | -# :E0202: An attribute inherited from %s hide this method |
536 | -# :W0142: *Used * or ** magic* |
537 | -# :W0201: Attribute '%s' defined outside __init__ |
538 | -# :W0221: *Arguments number differs from %s method* (pylint is confused by * and **) |
539 | -# :W0613: *Unused argument %r* (We get lots of these from interfaces) |
540 | -# :W0621: *Redefining name %r from outer scope (line %s)* (pylint does a poor evaluation) |
541 | -# :W0622: *Redefining built-in '%r' |
542 | -disable=typecheck,design,similarities,R,I,E0101,E0202,W0142,W0201,W0221,W0613,W0621,W0622,C0322 |
543 | +#disable-cat= |
544 | + |
545 | +# Disable the message(s) with the given id(s) or categories |
546 | +# W0142: Used * or ** magic |
547 | +# W0221: Arguments number differs from %s method (pylint is confused by * and **) |
548 | +# W0613: Unused argument %r (We get lots of these from interfaces) |
549 | +disable=R,I,W0142,W0221,W0613 |
550 | |
551 | |
552 | [REPORTS] |
553 | -# Tells wether to display a full report or only the messages |
554 | + |
555 | +# Set the output format. Available formats are text, parseable, colorized, msvs |
556 | +# (visual studio) and html |
557 | +output-format=colorized |
558 | + |
559 | +# Include message's id in output |
560 | +include-ids=yes |
561 | + |
562 | +# Put messages in a separate file for each module / package specified on the |
563 | +# command line instead of printing them on stdout. Reports (if any) will be |
564 | +# written in a file name "pylint_global.[txt|html]". |
565 | +files-output=no |
566 | + |
567 | +# Tells whether to display a full report or only the messages |
568 | reports=no |
569 | |
570 | +# Python expression which should return a note less than 10 (10 is the highest |
571 | +# note). You have access to the variables errors warning, statement which |
572 | +# respectively contain the number of errors / warnings messages and the total |
573 | +# number of statements analyzed. This is used by the global evaluation report |
574 | +# (R0004). |
575 | +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) |
576 | + |
577 | +# Add a comment according to your evaluation note. This is used by the global |
578 | +# evaluation report (R0004). |
579 | +comment=no |
580 | + |
581 | +# Enable the report(s) with the given id(s). |
582 | +#enable-report= |
583 | + |
584 | +# Disable the report(s) with the given id(s). |
585 | +#disable-report= |
586 | + |
587 | + |
588 | +# try to find bugs in the code using type inference |
589 | +# |
590 | +[TYPECHECK] |
591 | + |
592 | +# Tells whether missing members accessed in mixin class should be ignored. A |
593 | +# mixin class is detected if its name ends with "mixin" (case insensitive). |
594 | +ignore-mixin-members=yes |
595 | + |
596 | +# List of classes names for which member attributes should not be checked |
597 | +# (useful for classes with attributes dynamically set). |
598 | +ignored-classes= |
599 | + |
600 | +# When zope mode is activated, add a predefined set of Zope acquired attributes |
601 | +# to generated-members. |
602 | +zope=no |
603 | + |
604 | +# List of members which are set dynamically and missed by pylint inference |
605 | +# system, and so shouldn't trigger E0201 when accessed. |
606 | +generated-members=REQUEST,acl_users,aq_parent |
607 | + |
608 | + |
609 | +# checks for |
610 | +# * unused variables / imports |
611 | +# * undefined variables |
612 | +# * redefinition of variable from builtins or from an outer scope |
613 | +# * use of variable before assignment |
614 | +# |
615 | +[VARIABLES] |
616 | + |
617 | +# Tells whether we should check for unused import in __init__ files. |
618 | +init-import=yes |
619 | + |
620 | +# A regular expression matching names used for dummy variables (i.e. not used). |
621 | +dummy-variables-rgx=_|dummy |
622 | + |
623 | +# List of additional names supposed to be defined in builtins. Remember that |
624 | +# you should avoid to define new builtins when possible. |
625 | +additional-builtins= |
626 | + |
627 | |
628 | # checks for : |
629 | # * doc strings |
630 | # * modules / classes / functions / methods / arguments / variables name |
631 | -# * number of arguments, local variables, branchs, returns and statements in |
632 | +# * number of arguments, local variables, branches, returns and statements in |
633 | # functions, methods |
634 | # * required module attributes |
635 | # * dangerous default values as arguments |
636 | @@ -41,7 +139,6 @@ |
637 | # * uses of the global statement |
638 | # |
639 | [BASIC] |
640 | -enable-basic=yes |
641 | |
642 | # Required attributes for module, separated by a comma |
643 | required-attributes= |
644 | @@ -54,34 +151,32 @@ |
645 | module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ |
646 | |
647 | # Regular expression which should only match correct module level names |
648 | -const-rgx=([a-z_][a-z0-9_]*|[A-Z_][A-Z0-9_]*)$ |
649 | +const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ |
650 | |
651 | # Regular expression which should only match correct class names |
652 | class-rgx=[A-Z_][a-zA-Z0-9]+$ |
653 | |
654 | # Regular expression which should only match correct function names |
655 | -function-rgx=[a-z_][a-zA-Z0-9_]*$ |
656 | +function-rgx=[a-z_][a-z0-9_]{2,79}$ |
657 | |
658 | # Regular expression which should only match correct method names |
659 | -method-rgx=[a-z_][a-zA-Z0-9_]*$ |
660 | +method-rgx=([a-z_][a-z0-9_]{2,79}$|setUp|tearDown) |
661 | |
662 | # Regular expression which should only match correct instance attribute names |
663 | -attr-rgx=[a-z_][a-zA-Z0-9_]*$ |
664 | +attr-rgx=[a-z_][a-z0-9_]{1,30}$ |
665 | |
666 | # Regular expression which should only match correct argument names |
667 | -argument-rgx=[a-z_][a-zA-Z0-9_]{1,30}$ |
668 | +argument-rgx=[a-z_][a-z0-9_]{1,30}$ |
669 | |
670 | # Regular expression which should only match correct variable names |
671 | -# They are normally all lowercase, but when a constant, they are all uppercase. |
672 | -variable-rgx=([a-z_][a-z0-9_]*|[A-Z_][A-Z0-9_]*)$ |
673 | +variable-rgx=[a-z_][a-z0-9_]{1,30}$ |
674 | |
675 | # Regular expression which should only match correct list comprehension / |
676 | # generator expression variable names |
677 | inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ |
678 | |
679 | # Good variable names which should always be accepted, separated by a comma |
680 | -# Update this to supress warnings about inherrited names (C0103) |
681 | -good-names=_,a,b,c,i,j,k,v,d,f,s,t,l,ex,_,orderBy,getByName,clauseTables |
682 | +good-names=d,e,f,g,i,j,k,ex,logger,Run,_ |
683 | |
684 | # Bad variable names which should always be refused, separated by a comma |
685 | bad-names=foo,bar,baz,toto,tutu,tata |
686 | @@ -90,13 +185,80 @@ |
687 | bad-functions=apply,input,reduce |
688 | |
689 | |
690 | -# checks for: |
691 | -# * warning notes in the code like FIXME, XXX |
692 | -# * PEP 263: source code with non ascii character but no encoding declaration |
693 | -# |
694 | -[MISCELLANEOUS] |
695 | -# List of note tags to take in consideration, separated by a comma. |
696 | -notes=FIXME,XXX,TODO,fixme,todo |
697 | +# checks for sign of poor/misdesign: |
698 | +# * number of methods, attributes, local variables... |
699 | +# * size, complexity of functions, methods |
700 | +# |
701 | +[DESIGN] |
702 | + |
703 | +# Maximum number of arguments for function / method |
704 | +max-args=5 |
705 | + |
706 | +# Maximum number of locals for function / method body |
707 | +max-locals=15 |
708 | + |
709 | +# Maximum number of return / yield for function / method body |
710 | +max-returns=6 |
711 | + |
712 | +# Maximum number of branch for function / method body |
713 | +max-branchs=12 |
714 | + |
715 | +# Maximum number of statements in function / method body |
716 | +max-statements=50 |
717 | + |
718 | +# Maximum number of parents for a class (see R0901). |
719 | +max-parents=7 |
720 | + |
721 | +# Maximum number of attributes for a class (see R0902). |
722 | +max-attributes=7 |
723 | + |
724 | +# Minimum number of public methods for a class (see R0903). |
725 | +min-public-methods=2 |
726 | + |
727 | +# Maximum number of public methods for a class (see R0904). |
728 | +max-public-methods=20 |
729 | + |
730 | + |
731 | +# checks for : |
732 | +# * methods without self as first argument |
733 | +# * overridden methods signature |
734 | +# * access only to existent members via self |
735 | +# * attributes not defined in the __init__ method |
736 | +# * supported interfaces implementation |
737 | +# * unreachable code |
738 | +# |
739 | +[CLASSES] |
740 | + |
741 | +# List of interface methods to ignore, separated by a comma. This is used for |
742 | +# instance to not check methods defines in Zopes Interface base class. |
743 | +#ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by,providedBy |
744 | + |
745 | +# List of method names used to declare (i.e. assign) instance attributes. |
746 | +defining-attr-methods=__init__,__new__,setUp |
747 | + |
748 | + |
749 | +# checks for |
750 | +# * external modules dependencies |
751 | +# * relative / wildcard imports |
752 | +# * cyclic imports |
753 | +# * uses of deprecated modules |
754 | +# |
755 | +[IMPORTS] |
756 | + |
757 | +# Deprecated modules which should not be used, separated by a comma |
758 | +deprecated-modules=regsub,string,TERMIOS,Bastion,rexec |
759 | + |
760 | +# Create a graph of every (i.e. internal and external) dependencies in the |
761 | +# given file (report RP0402 must not be disabled) |
762 | +import-graph= |
763 | + |
764 | +# Create a graph of external dependencies in the given file (report RP0402 must |
765 | +# not be disabled) |
766 | +ext-import-graph= |
767 | + |
768 | +# Create a graph of internal dependencies in the given file (report RP0402 must |
769 | +# not be disabled) |
770 | +int-import-graph= |
771 | |
772 | |
773 | # checks for : |
774 | @@ -106,10 +268,9 @@ |
775 | # * use of <> instead of != |
776 | # |
777 | [FORMAT] |
778 | -enable-format=yes |
779 | |
780 | # Maximum number of characters on a single line. |
781 | -max-line-length=80 |
782 | +max-line-length=79 |
783 | |
784 | # Maximum number of lines in a module |
785 | max-module-lines=2000 |
786 | @@ -117,3 +278,29 @@ |
787 | # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 |
788 | # tab). |
789 | indent-string=' ' |
790 | + |
791 | + |
792 | +# checks for similarities and duplicated code. This computation may be |
793 | +# memory / CPU intensive, so you should disable it if you experiments some |
794 | +# problems. |
795 | +# |
796 | +[SIMILARITIES] |
797 | + |
798 | +# Minimum lines number of a similarity. |
799 | +min-similarity-lines=4 |
800 | + |
801 | +# Ignore comments when computing similarities. |
802 | +ignore-comments=yes |
803 | + |
804 | +# Ignore docstrings when computing similarities. |
805 | +ignore-docstrings=yes |
806 | + |
807 | + |
808 | +# checks for: |
809 | +# * warning notes in the code like FIXME, XXX |
810 | +# * PEP 263: source code with non ascii character but no encoding declaration |
811 | +# |
812 | +[MISCELLANEOUS] |
813 | + |
814 | +# List of note tags to take in consideration, separated by a comma. |
815 | +notes=FIXME,XXX,TODO,fixme,xxx,todo |
816 | |
817 | === added file 'run-tests' |
818 | --- run-tests 1970-01-01 00:00:00 +0000 |
819 | +++ run-tests 2010-11-30 19:41:01 +0000 |
820 | @@ -0,0 +1,23 @@ |
821 | +#!/bin/bash |
822 | +# Author: Natalia Bidart <natalia.bidart@canonical.com> |
823 | +# |
824 | +# Copyright 2010 Canonical Ltd. |
825 | +# |
826 | +# This program is free software: you can redistribute it and/or modify it |
827 | +# under the terms of the GNU General Public License version 3, as published |
828 | +# by the Free Software Foundation. |
829 | +# |
830 | +# This program is distributed in the hope that it will be useful, but |
831 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
832 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
833 | +# PURPOSE. See the GNU General Public License for more details. |
834 | +# |
835 | +# You should have received a copy of the GNU General Public License along |
836 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
837 | +set -e |
838 | + |
839 | +bin/u1trial -c ubuntuone |
840 | +bin/u1lint |
841 | +pep8 --repeat . |
842 | +rm -rf _trial_temp |
843 | +rm -rf .coverage |
844 | |
845 | === modified file 'setup.py' |
846 | --- setup.py 2010-08-02 13:45:54 +0000 |
847 | +++ setup.py 2010-11-30 19:41:01 +0000 |
848 | @@ -21,10 +21,11 @@ |
849 | from distutils.core import setup, Command |
850 | |
851 | PACKAGE = 'ubuntuone-dev-tools' |
852 | -VERSION = '0.1.1' |
853 | +VERSION = '0.1.2' |
854 | |
855 | U1LINT = 'bin/u1lint' |
856 | |
857 | + |
858 | class Lint(Command): |
859 | """Command to run the lint checks.""" |
860 | description = 'run python lint checks' |
861 | @@ -37,7 +38,7 @@ |
862 | def finalize_options(self): |
863 | pass |
864 | |
865 | - def run (self): |
866 | + def run(self): |
867 | """Run u1lint to check the code.""" |
868 | retcode = subprocess.call([U1LINT]) |
869 | if retcode != 0: |
870 | @@ -48,21 +49,20 @@ |
871 | description='Ubuntu One development tools and utilities', |
872 | url='http://launchpad.net/ubuntuone-dev-tools', |
873 | packages=['ubuntuone', |
874 | - 'ubuntuone.devtools'], |
875 | + 'ubuntuone.devtools', |
876 | + 'ubuntuone.devtools.services'], |
877 | scripts=['bin/u1lint', |
878 | 'bin/u1trial', |
879 | ], |
880 | data_files=[('share/%s' % PACKAGE, |
881 | ['pylintrc', |
882 | - 'data/dbus-session.conf'] |
883 | - ), |
884 | + 'data/dbus-session.conf']), |
885 | ('share/man/man1', |
886 | ['man/u1lint.1', |
887 | - 'man/u1trial.1',] |
888 | - ), |
889 | + 'man/u1trial.1']), |
890 | ], |
891 | |
892 | - cmdclass = { |
893 | - 'lint' : Lint, |
894 | + cmdclass={ |
895 | + 'lint': Lint, |
896 | }, |
897 | ) |
898 | |
899 | === modified file 'ubuntuone/devtools/__init__.py' |
900 | --- ubuntuone/devtools/__init__.py 2010-08-02 13:45:54 +0000 |
901 | +++ ubuntuone/devtools/__init__.py 2010-11-30 19:41:01 +0000 |
902 | @@ -1,2 +1,1 @@ |
903 | """Testing utilities for Ubuntu One client code.""" |
904 | - |
905 | |
906 | === removed file 'ubuntuone/devtools/dbus_util.py' |
907 | --- ubuntuone/devtools/dbus_util.py 2010-08-02 13:45:54 +0000 |
908 | +++ ubuntuone/devtools/dbus_util.py 1970-01-01 00:00:00 +0000 |
909 | @@ -1,89 +0,0 @@ |
910 | -# |
911 | -# Author: Guillermo Gonzalez <guillermo.gonzalez@canonical.com> |
912 | -# |
913 | -# Copyright 2009-2010 Canonical Ltd. |
914 | -# |
915 | -# This program is free software: you can redistribute it and/or modify it |
916 | -# under the terms of the GNU General Public License version 3, as published |
917 | -# by the Free Software Foundation. |
918 | -# |
919 | -# This program is distributed in the hope that it will be useful, but |
920 | -# WITHOUT ANY WARRANTY; without even the implied warranties of |
921 | -# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
922 | -# PURPOSE. See the GNU General Public License for more details. |
923 | -# |
924 | -# You should have received a copy of the GNU General Public License along |
925 | -# with this program. If not, see <http://www.gnu.org/licenses/>. |
926 | -"""Utilities for finding and running a dbus session bus for testing.""" |
927 | - |
928 | -import os |
929 | -import signal |
930 | -import subprocess |
931 | - |
932 | -from distutils.spawn import find_executable |
933 | -from xdg.BaseDirectory import load_data_paths |
934 | - |
935 | - |
936 | -class DBusLaunchError(Exception): |
937 | - """Error while launching dbus-daemon""" |
938 | - pass |
939 | - |
940 | -class NotFoundError(Exception): |
941 | - """Not found error""" |
942 | - pass |
943 | - |
944 | - |
945 | -class DBusRunner(object): |
946 | - """Class for running dbus-daemon with a private session.""" |
947 | - |
948 | - def __init__(self): |
949 | - self.dbus_address = None |
950 | - self.dbus_pid = None |
951 | - self.running = False |
952 | - |
953 | - def _find_config_file(self): |
954 | - """Find the first appropriate dbus-session.conf to use.""" |
955 | - # In case we're running from within the source tree |
956 | - path = os.path.join(os.path.dirname(__file__), "..", "..", |
957 | - "data", "dbus-session.conf") |
958 | - if os.path.exists(path): |
959 | - return path |
960 | - |
961 | - # Use the installed file in $pkgdatadir |
962 | - for i in load_data_paths("ubuntuone-dev-tools", "dbus-session.conf"): |
963 | - if os.path.exists(i): |
964 | - return i |
965 | - |
966 | - |
967 | - def startDBus(self): |
968 | - """Start our own session bus daemon for testing.""" |
969 | - dbus = find_executable("dbus-daemon") |
970 | - if not dbus: |
971 | - raise NotFoundError("dbus-daemon was not found.") |
972 | - |
973 | - config_file = self._find_config_file() |
974 | - |
975 | - dbus_args = ["--fork", |
976 | - "--config-file=" + config_file, |
977 | - "--print-address=1", |
978 | - "--print-pid=2"] |
979 | - p = subprocess.Popen([dbus] + dbus_args, |
980 | - bufsize=4096, stdout=subprocess.PIPE, |
981 | - stderr=subprocess.PIPE) |
982 | - |
983 | - self.dbus_address = "".join(p.stdout.readlines()).strip() |
984 | - self.dbus_pid = int("".join(p.stderr.readlines()).strip()) |
985 | - |
986 | - if self.dbus_address != "": |
987 | - os.environ["DBUS_SESSION_BUS_ADDRESS"] = self.dbus_address |
988 | - else: |
989 | - os.kill(self.dbus_pid, signal.SIGKILL) |
990 | - raise DBusLaunchError("There was a problem launching dbus-daemon.") |
991 | - self.running = True |
992 | - |
993 | - def stopDBus(self): |
994 | - """Stop our DBus session bus daemon.""" |
995 | - del os.environ["DBUS_SESSION_BUS_ADDRESS"] |
996 | - os.kill(self.dbus_pid, signal.SIGKILL) |
997 | - self.running = False |
998 | - |
999 | |
1000 | === added file 'ubuntuone/devtools/handlers.py' |
1001 | --- ubuntuone/devtools/handlers.py 1970-01-01 00:00:00 +0000 |
1002 | +++ ubuntuone/devtools/handlers.py 2010-11-30 19:41:01 +0000 |
1003 | @@ -0,0 +1,64 @@ |
1004 | +# -*- coding: utf-8 -*- |
1005 | + |
1006 | +# Author: Guillermo Gonzalez <guillermo.gonzalez@canonical.com> |
1007 | +# Author: Facundo Batista <facundo@canonical.com> |
1008 | +# |
1009 | +# Copyright 2009-2010 Canonical Ltd. |
1010 | +# |
1011 | +# This program is free software: you can redistribute it and/or modify it |
1012 | +# under the terms of the GNU General Public License version 3, as published |
1013 | +# by the Free Software Foundation. |
1014 | +# |
1015 | +# This program is distributed in the hope that it will be useful, but |
1016 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
1017 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
1018 | +# PURPOSE. See the GNU General Public License for more details. |
1019 | +# |
1020 | +# You should have received a copy of the GNU General Public License along |
1021 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
1022 | + |
1023 | +"""Set of helpers handlers.""" |
1024 | + |
1025 | +import logging |
1026 | + |
1027 | + |
1028 | +class MementoHandler(logging.Handler): |
1029 | + """ A handler class which store logging records in a list """ |
1030 | + |
1031 | + def __init__(self, *args, **kwargs): |
1032 | + """ Create the instance, and add a records attribute. """ |
1033 | + logging.Handler.__init__(self, *args, **kwargs) |
1034 | + self.records = [] |
1035 | + self.debug = False |
1036 | + |
1037 | + def emit(self, record): |
1038 | + """ Just add the record to self.records. """ |
1039 | + self.format(record) |
1040 | + self.records.append(record) |
1041 | + |
1042 | + def check(self, level, *msgs): |
1043 | + """Verifies that the msgs are logged in the specified level.""" |
1044 | + for rec in self.records: |
1045 | + if rec.levelno == level and all(m in rec.message for m in msgs): |
1046 | + return True |
1047 | + if self.debug: |
1048 | + recorded = [(logging.getLevelName(r.levelno), r.message) |
1049 | + for r in self.records] |
1050 | + print "Memento messages:", recorded |
1051 | + return False |
1052 | + |
1053 | + def check_debug(self, *msgs): |
1054 | + """Shortcut for checking in DEBUG.""" |
1055 | + return self.check(logging.DEBUG, *msgs) |
1056 | + |
1057 | + def check_info(self, *msgs): |
1058 | + """Shortcut for checking in INFO.""" |
1059 | + return self.check(logging.INFO, *msgs) |
1060 | + |
1061 | + def check_warning(self, *msgs): |
1062 | + """Shortcut for checking in WARNING.""" |
1063 | + return self.check(logging.WARNING, *msgs) |
1064 | + |
1065 | + def check_error(self, *msgs): |
1066 | + """Shortcut for checking in ERROR.""" |
1067 | + return self.check(logging.ERROR, *msgs) |
1068 | |
1069 | === added directory 'ubuntuone/devtools/services' |
1070 | === added file 'ubuntuone/devtools/services/__init__.py' |
1071 | --- ubuntuone/devtools/services/__init__.py 1970-01-01 00:00:00 +0000 |
1072 | +++ ubuntuone/devtools/services/__init__.py 2010-11-30 19:41:01 +0000 |
1073 | @@ -0,0 +1,1 @@ |
1074 | +"""Service runners for testing.""" |
1075 | |
1076 | === added file 'ubuntuone/devtools/services/dbus.py' |
1077 | --- ubuntuone/devtools/services/dbus.py 1970-01-01 00:00:00 +0000 |
1078 | +++ ubuntuone/devtools/services/dbus.py 2010-11-30 19:41:01 +0000 |
1079 | @@ -0,0 +1,94 @@ |
1080 | +# |
1081 | +# Author: Guillermo Gonzalez <guillermo.gonzalez@canonical.com> |
1082 | +# |
1083 | +# Copyright 2009-2010 Canonical Ltd. |
1084 | +# |
1085 | +# This program is free software: you can redistribute it and/or modify it |
1086 | +# under the terms of the GNU General Public License version 3, as published |
1087 | +# by the Free Software Foundation. |
1088 | +# |
1089 | +# This program is distributed in the hope that it will be useful, but |
1090 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
1091 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
1092 | +# PURPOSE. See the GNU General Public License for more details. |
1093 | +# |
1094 | +# You should have received a copy of the GNU General Public License along |
1095 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
1096 | +"""Utilities for finding and running a dbus session bus for testing.""" |
1097 | + |
1098 | +import os |
1099 | +import signal |
1100 | +import subprocess |
1101 | + |
1102 | +from distutils.spawn import find_executable |
1103 | +from xdg.BaseDirectory import load_data_paths |
1104 | + |
1105 | + |
1106 | +class DBusLaunchError(Exception): |
1107 | + """Error while launching dbus-daemon""" |
1108 | + pass |
1109 | + |
1110 | + |
1111 | +class NotFoundError(Exception): |
1112 | + """Not found error""" |
1113 | + pass |
1114 | + |
1115 | + |
1116 | +class DBusRunner(object): |
1117 | + """Class for running dbus-daemon with a private session.""" |
1118 | + |
1119 | + def __init__(self): |
1120 | + self.dbus_address = None |
1121 | + self.dbus_pid = None |
1122 | + self.running = False |
1123 | + |
1124 | + def _find_config_file(self): |
1125 | + """Find the first appropriate dbus-session.conf to use.""" |
1126 | + # In case we're running from within the source tree |
1127 | + path = os.path.join(os.path.dirname(__file__), "..", "..", ".." |
1128 | + "data", "dbus-session.conf") |
1129 | + if os.path.exists(path): |
1130 | + return path |
1131 | + |
1132 | + # Use the installed file in $pkgdatadir |
1133 | + for i in load_data_paths("ubuntuone-dev-tools", "dbus-session.conf"): |
1134 | + if os.path.exists(i): |
1135 | + return i |
1136 | + |
1137 | + def start_service(self, tempdir=None): |
1138 | + """Start our own session bus daemon for testing.""" |
1139 | + if not tempdir: |
1140 | + tempdir = os.path.join(os.getcwd(), '_trial_temp') |
1141 | + dbus = find_executable("dbus-daemon") |
1142 | + if not dbus: |
1143 | + raise NotFoundError("dbus-daemon was not found.") |
1144 | + |
1145 | + config_file = self._find_config_file() |
1146 | + |
1147 | + dbus_args = ["--fork", |
1148 | + "--config-file=" + config_file, |
1149 | + "--print-address=1", |
1150 | + "--print-pid=2", |
1151 | + "--address=unix:tmpdir=%s" % tempdir] |
1152 | + sp = subprocess.Popen([dbus] + dbus_args, |
1153 | + bufsize=4096, stdout=subprocess.PIPE, |
1154 | + stderr=subprocess.PIPE) |
1155 | + |
1156 | + self.dbus_address = "".join(sp.stdout.readlines()).strip() |
1157 | + self.dbus_pid = int("".join(sp.stderr.readlines()).strip()) |
1158 | + |
1159 | + if self.dbus_address != "": |
1160 | + os.environ["DBUS_SESSION_BUS_ADDRESS"] = self.dbus_address |
1161 | + else: |
1162 | + os.kill(self.dbus_pid, signal.SIGKILL) |
1163 | + raise DBusLaunchError("There was a problem launching dbus-daemon.") |
1164 | + self.running = True |
1165 | + |
1166 | + def stop_service(self): |
1167 | + """Stop our DBus session bus daemon.""" |
1168 | + try: |
1169 | + del os.environ["DBUS_SESSION_BUS_ADDRESS"] |
1170 | + except KeyError: |
1171 | + pass |
1172 | + os.kill(self.dbus_pid, signal.SIGKILL) |
1173 | + self.running = False |
1174 | |
1175 | === modified file 'ubuntuone/devtools/testcase.py' |
1176 | --- ubuntuone/devtools/testcase.py 2010-08-02 13:45:54 +0000 |
1177 | +++ ubuntuone/devtools/testcase.py 2010-11-30 19:41:01 +0000 |
1178 | @@ -1,4 +1,5 @@ |
1179 | -# |
1180 | +# -*- coding: utf-8 -*- |
1181 | + |
1182 | # Author: Guillermo Gonzalez <guillermo.gonzalez@canonical.com> |
1183 | # |
1184 | # Copyright 2009-2010 Canonical Ltd. |
1185 | @@ -14,19 +15,26 @@ |
1186 | # |
1187 | # You should have received a copy of the GNU General Public License along |
1188 | # with this program. If not, see <http://www.gnu.org/licenses/>. |
1189 | -""" Base tests cases and test utilities """ |
1190 | + |
1191 | +"""Base tests cases and test utilities.""" |
1192 | + |
1193 | from __future__ import with_statement |
1194 | |
1195 | -import dbus |
1196 | -from dbus.mainloop.glib import DBusGMainLoop |
1197 | import contextlib |
1198 | import os |
1199 | import shutil |
1200 | |
1201 | +import dbus |
1202 | +import dbus.service |
1203 | + |
1204 | +from dbus.mainloop.glib import DBusGMainLoop |
1205 | + |
1206 | from twisted.internet import defer |
1207 | from twisted.python import failure |
1208 | -from unittest import TestCase |
1209 | -from oauth import oauth |
1210 | +from twisted.trial.unittest import TestCase |
1211 | + |
1212 | +# DBusRunner for DBusTestCase using tests |
1213 | +from ubuntuone.devtools.services.dbus import DBusRunner |
1214 | |
1215 | |
1216 | @contextlib.contextmanager |
1217 | @@ -41,21 +49,9 @@ |
1218 | os.environ[env_var] = old_value |
1219 | |
1220 | |
1221 | -class FakeOAuthClient(object): |
1222 | - """ Fake OAuthClient""" |
1223 | - |
1224 | - def __init__(self, realm): |
1225 | - """ create the instance. """ |
1226 | - self.realm = realm |
1227 | - self.consumer = oauth.OAuthConsumer('ubuntuone', 'hammertime') |
1228 | - |
1229 | - def get_access_token(self): |
1230 | - """ returns a Token""" |
1231 | - return 'a token' |
1232 | - |
1233 | - |
1234 | class FakeDBusInterface(object): |
1235 | """A fake DBusInterface...""" |
1236 | + |
1237 | def shutdown(self, with_restart=False): |
1238 | """...that only knows how to go away""" |
1239 | |
1240 | @@ -67,10 +63,15 @@ |
1241 | mktemp(name): helper to create temporary dirs |
1242 | rmtree(path): support read-only shares |
1243 | makedirs(path): support read-only shares |
1244 | + |
1245 | """ |
1246 | |
1247 | + def required_services(self): |
1248 | + """Return the list of required services for DBusTestCase.""" |
1249 | + return [] |
1250 | + |
1251 | def mktemp(self, name='temp'): |
1252 | - """ Customized mktemp that accepts an optional name argument. """ |
1253 | + """Customized mktemp that accepts an optional name argument.""" |
1254 | tempdir = os.path.join(self.tmpdir, name) |
1255 | if os.path.exists(tempdir): |
1256 | self.rmtree(tempdir) |
1257 | @@ -84,10 +85,10 @@ |
1258 | root_dir = getattr(self, '__root', None) |
1259 | if root_dir: |
1260 | return root_dir |
1261 | - MAX_FILENAME = 32 # some platforms limit lengths of filenames |
1262 | - base = os.path.join(self.__class__.__module__[:MAX_FILENAME], |
1263 | - self.__class__.__name__[:MAX_FILENAME], |
1264 | - self._testMethodName[:MAX_FILENAME]) |
1265 | + max_filename = 32 # some platforms limit lengths of filenames |
1266 | + base = os.path.join(self.__class__.__module__[:max_filename], |
1267 | + self.__class__.__name__[:max_filename], |
1268 | + self._testMethodName[:max_filename]) |
1269 | # use _trial_temp dir, it should be os.gwtcwd() |
1270 | # define the root temp dir of the testcase, pylint: disable=W0201 |
1271 | self.__root = os.path.join(os.getcwd(), base) |
1272 | @@ -116,19 +117,20 @@ |
1273 | os.chmod(parent, 0755) |
1274 | os.makedirs(path) |
1275 | |
1276 | - def setUp(self): |
1277 | - TestCase.setUp(self) |
1278 | - |
1279 | - def tearDown(self): |
1280 | - """ cleanup the temp dir. """ |
1281 | - return TestCase.tearDown(self) |
1282 | - |
1283 | |
1284 | class DBusTestCase(BaseTestCase): |
1285 | - """ Test the DBus event handling """ |
1286 | + """Test the DBus event handling.""" |
1287 | + |
1288 | + def required_services(self): |
1289 | + """Return the list of required services for DBusTestCase.""" |
1290 | + services = super(DBusTestCase, self).required_services() |
1291 | + services.extend([DBusRunner]) |
1292 | + return services |
1293 | |
1294 | def setUp(self): |
1295 | - """ Setup the infrastructure fo the test (dbus service). """ |
1296 | + """Setup the infrastructure fo the test (dbus service).""" |
1297 | + # Class 'BaseTestCase' has no 'setUp' member |
1298 | + # pylint: disable=E1101 |
1299 | BaseTestCase.setUp(self) |
1300 | self.loop = DBusGMainLoop(set_as_default=True) |
1301 | self.bus = dbus.bus.BusConnection(mainloop=self.loop) |
1302 | @@ -139,29 +141,32 @@ |
1303 | self.signal_receivers = set() |
1304 | |
1305 | def tearDown(self): |
1306 | - """ Cleanup the test. """ |
1307 | + """Cleanup the test.""" |
1308 | + # Class 'BaseTestCase' has no 'tearDown' member |
1309 | + # pylint: disable=E1101 |
1310 | d = self.cleanup_signal_receivers(self.signal_receivers) |
1311 | - d.addBoth(self._tearDown) |
1312 | + d.addBoth(self._tear_down) |
1313 | d.addBoth(lambda _: BaseTestCase.tearDown(self)) |
1314 | return d |
1315 | |
1316 | - def _tearDown(self): |
1317 | - """ shutdown """ |
1318 | + def _tear_down(self): |
1319 | + """Shutdown.""" |
1320 | self.bus.flush() |
1321 | self.bus.close() |
1322 | |
1323 | def error_handler(self, error): |
1324 | - """ default error handler for DBus calls. """ |
1325 | + """Default error handler for DBus calls.""" |
1326 | if isinstance(error, failure.Failure): |
1327 | self.fail(error.getErrorMessage()) |
1328 | |
1329 | def cleanup_signal_receivers(self, signal_receivers): |
1330 | - """ cleanup self.signal_receivers and returns a deferred """ |
1331 | + """Cleanup self.signal_receivers and returns a deferred.""" |
1332 | deferreds = [] |
1333 | for match in signal_receivers: |
1334 | d = defer.Deferred() |
1335 | + |
1336 | def callback(*args): |
1337 | - """ callback that accepts *args. """ |
1338 | + """Callback that accepts *args.""" |
1339 | if not d.called: |
1340 | d.callback(args) |
1341 | self.bus.call_async(dbus.bus.BUS_DAEMON_NAME, |
1342 | @@ -173,4 +178,3 @@ |
1343 | return defer.DeferredList(deferreds) |
1344 | else: |
1345 | return defer.succeed(True) |
1346 | - |
Good work.