Merge lp:~barry/window-mocker/py3qt5 into lp:window-mocker
- py3qt5
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Thomi Richards |
Approved revision: | 42 |
Merged at revision: | 25 |
Proposed branch: | lp:~barry/window-mocker/py3qt5 |
Merge into: | lp:window-mocker |
Diff against target: |
663 lines (+148/-90) 17 files modified
.bzrignore (+2/-0) MANIFEST.in (+2/-0) bin/window-mocker (+6/-4) debian/changelog (+17/-0) debian/control (+6/-4) debian/copyright (+1/-1) debian/rules (+1/-0) setup.py (+3/-3) tests/__init__.py (+1/-1) tests/test_app_functional.py (+26/-22) tests/test_plugins.py (+19/-9) tests/test_testapp_module_functions.py (+30/-16) windowmocker/__init__.py (+13/-11) windowmocker/plugins/__init__.py (+3/-3) windowmocker/plugins/base.py (+9/-6) windowmocker/plugins/qt4.py (+4/-5) windowmocker/plugins/qt5.py (+5/-5) |
To merge this branch: | bzr merge lp:~barry/window-mocker/py3qt5 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot | continuous-integration | Approve | |
Thomi Richards (community) | Approve | ||
Review via email: mp+204990@code.launchpad.net |
This proposal supersedes a proposal from 2014-01-31.
Commit message
Description of the change
Now with cgoldberg's branch landed, this is rebased on trunk, and cleans up a few ancillary things.
window-mocker (1.4-0ubuntu1) UNRELEASED; urgency=medium
* Bump revision to 1.4.
* Add MANIFEST.in to prune build artifacts from tarball.
* Clean ups:
+ White space.
+ Use of insecure tempfile.mktemp()
+ Use of non-temporary file names.
+ Use of mutable default arguments.
+ Improve Python 2/3 compatibility.
* d/control:
+ Add dependency on python{,3}-six for Python 3 compatibility fix.
+ Remove dependency on python3-mock (use unittest.mock instead in Py3).
+ Bump Standards-Version to 3.9.5 with no other changes necessary.
-- Barry Warsaw <email address hidden> Thu, 30 Jan 2014 13:48:47 +0000
Corey Goldberg (coreygoldberg) wrote : Posted in a previous version of this proposal | # |
Barry Warsaw (barry) wrote : Posted in a previous version of this proposal | # |
Oops, sorry, that is the wrong branch. Let me try again.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:37
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Barry Warsaw (barry) wrote : Posted in a previous version of this proposal | # |
Thanks Corey. Sorry for not seeing your mp first. I left a comment on yours:
https:/
tl;dr: window-mocker should be Python 3 only to eliminate the Python 2 dependencies. I'll leave the PyQt4/5 decisions to you guys, but it's pretty easy to switch between the two (I could make it easier yet by fiddling with the imports), as long as you don't need to speak both versions. Maybe supporting both makes transition easier?
Barry Warsaw (barry) wrote : Posted in a previous version of this proposal | # |
FWIW, I think this is blocking my autopilot reexec branch:
https:/
so it would be good to resolve the issue and get this landed asap. Is there anything I can do to help move it along?
Barry Warsaw (barry) wrote : Posted in a previous version of this proposal | # |
After chatting w/thomi on IRC, it sounds like cgoldberg's branch is more aligned with the immediate needs, and thomi has reviewed it and says it looks good. WFM! Landing cgoldberg's branch will unblock my autopilot work, so let's do that asap, and if anything more is needed later, we can handle that.
It does mean we'll carry Python 2 stuff around for now, but that's just cruft that will eventually bitrot in the archive or get cleaned up later.
One note: we found one place in the unity7 test suite that imports windowmocker. It does it for silly reasons though afaict (since it only does it to see if window-mocker is available, but that could easily be done in other ways). AFAICT, windowmocker the module is never used outside of /usr/bin/
Or do you know of anything else that imports windowmocker?
- 42. By Barry Warsaw
-
Revert a few previous changes. Fix some typos.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:42
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Thomi Richards (thomir-deactivatedaccount) wrote : | # |
LGTM
PS Jenkins bot (ps-jenkins) : | # |
Preview Diff
1 | === added file '.bzrignore' |
2 | --- .bzrignore 1970-01-01 00:00:00 +0000 |
3 | +++ .bzrignore 2014-02-05 16:22:14 +0000 |
4 | @@ -0,0 +1,2 @@ |
5 | +__pycache__ |
6 | +*.egg-info |
7 | |
8 | === added file 'MANIFEST.in' |
9 | --- MANIFEST.in 1970-01-01 00:00:00 +0000 |
10 | +++ MANIFEST.in 2014-02-05 16:22:14 +0000 |
11 | @@ -0,0 +1,2 @@ |
12 | +prune debian |
13 | +prune dist |
14 | |
15 | === modified file 'bin/window-mocker' |
16 | --- bin/window-mocker 2014-01-21 20:26:48 +0000 |
17 | +++ bin/window-mocker 2014-02-05 16:22:14 +0000 |
18 | @@ -1,6 +1,6 @@ |
19 | -#!/usr/bin/env python |
20 | +#!/usr/bin/env python3 |
21 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
22 | -# Copyright 2012 Canonical |
23 | +# Copyright 2012-2014 Canonical, Ltd. |
24 | # Author: Thomi Richards |
25 | # |
26 | # This program is free software: you can redistribute it and/or modify it |
27 | @@ -11,8 +11,10 @@ |
28 | import argparse |
29 | import sys |
30 | |
31 | -from windowmocker import create_application_from_path, create_application_from_data |
32 | -from windowmocker.plugins import get_default_plugin_name, get_registered_plugin_names |
33 | +from windowmocker import ( |
34 | + create_application_from_path, create_application_from_data) |
35 | +from windowmocker.plugins import ( |
36 | + get_default_plugin_name, get_registered_plugin_names) |
37 | |
38 | |
39 | def main(): |
40 | |
41 | === modified file 'debian/changelog' |
42 | --- debian/changelog 2013-06-05 07:08:45 +0000 |
43 | +++ debian/changelog 2014-02-05 16:22:14 +0000 |
44 | @@ -1,3 +1,20 @@ |
45 | +window-mocker (1.4-0ubuntu1) UNRELEASED; urgency=medium |
46 | + |
47 | + * Bump revision to 1.4. |
48 | + * Add MANIFEST.in to prune build artifacts from tarball. |
49 | + * Clean ups: |
50 | + + White space. |
51 | + + Use of insecure tempfile.mktemp() |
52 | + + Use of non-temporary file names. |
53 | + + Use of mutable default arguments. |
54 | + + Improve Python 2/3 compatibility. |
55 | + * d/control: |
56 | + + Add dependency on python{,3}-six for Python 3 compatibility fix. |
57 | + + Remove dependency on python3-mock (use unittest.mock instead in Py3). |
58 | + + Bump Standards-Version to 3.9.5 with no other changes necessary. |
59 | + |
60 | + -- Barry Warsaw <barry@ubuntu.com> Thu, 30 Jan 2014 13:48:47 +0000 |
61 | + |
62 | window-mocker (1.3daily13.06.05-0ubuntu1) saucy; urgency=low |
63 | |
64 | [ Thomi Richards ] |
65 | |
66 | === modified file 'debian/control' |
67 | --- debian/control 2014-01-09 17:27:37 +0000 |
68 | +++ debian/control 2014-02-05 16:22:14 +0000 |
69 | @@ -9,15 +9,16 @@ |
70 | python-mock, |
71 | python-qt4, |
72 | python-setuptools, |
73 | + python-six, |
74 | python-testscenarios, |
75 | - python3, |
76 | + python3-all, |
77 | python3-distutils-extra, |
78 | - python3-mock, |
79 | python3-pyqt4, |
80 | python3-pyqt5, |
81 | python3-setuptools, |
82 | + python3-six, |
83 | python3-testscenarios, |
84 | -Standards-Version: 3.9.4 |
85 | +Standards-Version: 3.9.5 |
86 | # If you aren't a member of ~autopilot but need to upload packaging changes, |
87 | # just go ahead. ~autopilot will notice and sync up the code again. |
88 | Vcs-Bzr: http://bazaar.launchpad.net/~autopilot/window-mocker/trunk |
89 | @@ -29,6 +30,7 @@ |
90 | Depends: ${misc:Depends}, |
91 | ${python:Depends}, |
92 | python-qt4, |
93 | + python-six, |
94 | Provides: ${python:Provides}, |
95 | Description: create windows and applications from specifications |
96 | Window Mocker is a simple tool that allows developers to create windows and |
97 | @@ -42,10 +44,10 @@ |
98 | ${python:Depends}, |
99 | python3-pyqt4, |
100 | python3-pyqt5, |
101 | + python3-six, |
102 | Provides: ${python:Provides}, |
103 | Description: create windows and applications from specifications |
104 | Window Mocker is a simple tool that allows developers to create windows and |
105 | applications that follow a certain specification. This is especially useful |
106 | when testing applications that interact with other windows (like a window |
107 | manager, for example). |
108 | - |
109 | |
110 | === modified file 'debian/copyright' |
111 | --- debian/copyright 2013-02-07 16:41:10 +0000 |
112 | +++ debian/copyright 2014-02-05 16:22:14 +0000 |
113 | @@ -2,7 +2,7 @@ |
114 | Source: http://launchpad.net/window-mocker |
115 | |
116 | Files: * |
117 | -Copyright: 2012 Canonical, Ltd. |
118 | +Copyright: 2012-2014 Canonical, Ltd. |
119 | License: GPL-3 |
120 | |
121 | License: GPL-3 |
122 | |
123 | === modified file 'debian/rules' |
124 | --- debian/rules 2014-01-17 22:31:40 +0000 |
125 | +++ debian/rules 2014-02-05 16:22:14 +0000 |
126 | @@ -1,5 +1,6 @@ |
127 | #!/usr/bin/make -f |
128 | |
129 | +#export DH_VERBOSE=1 |
130 | export PYBUILD_NAME=windowmocker |
131 | |
132 | %: |
133 | |
134 | === modified file 'setup.py' |
135 | --- setup.py 2014-01-08 20:35:14 +0000 |
136 | +++ setup.py 2014-02-05 16:22:14 +0000 |
137 | @@ -1,6 +1,6 @@ |
138 | -#!/usr/bin/env python |
139 | +#!/usr/bin/env python3 |
140 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
141 | -# Copyright 2012, 2013 Canonical |
142 | +# Copyright 2012-2014 Canonical, Ltd. |
143 | # Author: Thomi Richards |
144 | # |
145 | # This program is free software: you can redistribute it and/or modify it |
146 | @@ -12,7 +12,7 @@ |
147 | |
148 | DistUtilsExtra.auto.setup( |
149 | name='window-mocker', |
150 | - version='1.3', |
151 | + version='1.4', |
152 | description=open('README').read(), |
153 | author='Thomi Richards', |
154 | author_email='thomi.richards@canonical.com', |
155 | |
156 | === modified file 'tests/__init__.py' |
157 | --- tests/__init__.py 2012-09-18 03:20:19 +0000 |
158 | +++ tests/__init__.py 2014-02-05 16:22:14 +0000 |
159 | @@ -1,5 +1,5 @@ |
160 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
161 | -# Copyright 2012 Canonical |
162 | +# Copyright 2012-2014 Canonical, Ltd. |
163 | # Author: Thomi Richards |
164 | # |
165 | # This program is free software: you can redistribute it and/or modify it |
166 | |
167 | === modified file 'tests/test_app_functional.py' |
168 | --- tests/test_app_functional.py 2014-01-21 20:56:11 +0000 |
169 | +++ tests/test_app_functional.py 2014-02-05 16:22:14 +0000 |
170 | @@ -1,5 +1,5 @@ |
171 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
172 | -# Copyright 2012, 2013 Canonical |
173 | +# Copyright 2012-2014 Canonical, Ltd. |
174 | # Author: Thomi Richards |
175 | # |
176 | # This program is free software: you can redistribute it and/or modify it |
177 | @@ -8,10 +8,10 @@ |
178 | |
179 | """Functional tests for the window-mocker application.""" |
180 | |
181 | -import os.path |
182 | +import os |
183 | import subprocess |
184 | -import sys |
185 | import tempfile |
186 | + |
187 | from time import sleep |
188 | |
189 | from testtools import TestCase |
190 | @@ -34,7 +34,8 @@ |
191 | if os.path.exists(source_path): |
192 | return source_path |
193 | |
194 | - return subprocess.check_output(['which', 'window-mocker']) |
195 | + return subprocess.check_output(['which', 'window-mocker'], |
196 | + universal_newlines=True) |
197 | |
198 | |
199 | def run_app_with_args(*args): |
200 | @@ -51,7 +52,8 @@ |
201 | application, |
202 | stdout=subprocess.PIPE, |
203 | stderr=subprocess.PIPE, |
204 | - shell=False |
205 | + shell=False, |
206 | + universal_newlines=True, |
207 | ) |
208 | |
209 | stdout = stderr = "" |
210 | @@ -63,7 +65,7 @@ |
211 | print("Killing process.") |
212 | process.kill() |
213 | if i == 8: |
214 | - print ("Terminating process.") |
215 | + print("Terminating process.") |
216 | process.terminate() |
217 | sleep(1) |
218 | stdout, stderr = process.communicate() |
219 | @@ -75,41 +77,43 @@ |
220 | """Functional tests for the window-mocker application.""" |
221 | |
222 | def run_with_spec_content(self, content_string): |
223 | - temp_filename = tempfile.mktemp() |
224 | + fd, temp_filename = tempfile.mkstemp() |
225 | + self.addCleanup(os.remove, temp_filename) |
226 | + os.close(fd) |
227 | with open(temp_filename, 'w') as f: |
228 | f.write(content_string) |
229 | - self.addCleanup(os.remove, temp_filename) |
230 | return run_app_with_args(temp_filename) |
231 | |
232 | def test_errors_with_missing_file(self): |
233 | retcode, stdout, stderr = run_app_with_args("bad_file_name") |
234 | - self.assertThat(stdout, Equals(b'')) |
235 | - self.assertThat(stderr, Equals(b'Error: Unable to open file: No such file or directory\n')) |
236 | + self.assertThat(stdout, Equals('')) |
237 | + self.assertThat(stderr, Equals('Error: Unable to open file: No such file or directory\n')) |
238 | self.assertThat(retcode, Equals(1)) |
239 | |
240 | def test_errors_with_inaccessible_file(self): |
241 | - file_name = 'cannot_read' |
242 | - with open(file_name, 'w') as f: |
243 | - os.chmod(file_name, 0) |
244 | - self.addCleanup(os.remove, file_name) |
245 | + fd, temp_filename = tempfile.mkstemp() |
246 | + self.addCleanup(os.remove, temp_filename) |
247 | + os.close(fd) |
248 | + with open(temp_filename, 'w'): |
249 | + pass |
250 | + os.chmod(temp_filename, 0) |
251 | |
252 | - retcode, stdout, stderr = run_app_with_args("cannot_read") |
253 | - self.assertThat(stdout, Equals(b'')) |
254 | - self.assertThat(stderr, Equals(b'Error: Unable to open file: Permission denied\n')) |
255 | + retcode, stdout, stderr = run_app_with_args(temp_filename) |
256 | + self.assertThat(stdout, Equals('')) |
257 | + self.assertThat(stderr, Equals('Error: Unable to open file: Permission denied\n')) |
258 | self.assertThat(retcode, Equals(1)) |
259 | |
260 | def test_errors_on_empty_file(self): |
261 | retcode, stdout, stderr = self.run_with_spec_content("") |
262 | |
263 | - self.assertThat(stdout, Equals(b'')) |
264 | + self.assertThat(stdout, Equals('')) |
265 | self.assertThat(retcode, Equals(3)) |
266 | - self.assertThat(stderr, Equals(b'Error: Unable to process request: No JSON object could be decoded\n')) |
267 | + self.assertThat(stderr, Equals('Error: Unable to process request: No JSON object could be decoded\n')) |
268 | |
269 | def test_accepts_testability_command_line_argument(self): |
270 | retcode, stdout, stderr = run_app_with_args("--help") |
271 | - self.assertThat(stdout.decode('utf-8'), Contains("-testability")) |
272 | + self.assertThat(stdout, Contains("-testability")) |
273 | |
274 | def test_accepts_plugin_type_command_line_argument(self): |
275 | retcode, stdout, stderr = run_app_with_args("--help") |
276 | - output = stdout.decode('utf-8') |
277 | - self.assertThat(stdout.decode('utf-8'), Contains("Qt4")) |
278 | + self.assertThat(stdout, Contains("Qt4")) |
279 | |
280 | === modified file 'tests/test_plugins.py' |
281 | --- tests/test_plugins.py 2014-01-15 20:35:41 +0000 |
282 | +++ tests/test_plugins.py 2014-02-05 16:22:14 +0000 |
283 | @@ -1,22 +1,26 @@ |
284 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
285 | -# Copyright 2012 Canonical |
286 | +# Copyright 2012-2014 Canonical, Ltd. |
287 | # Author: Thomi Richards |
288 | # |
289 | # This program is free software: you can redistribute it and/or modify it |
290 | # under the terms of the GNU General Public License version 3, as published |
291 | # by the Free Software Foundation. |
292 | |
293 | -from mock import patch |
294 | from testscenarios import TestWithScenarios |
295 | from testtools import TestCase |
296 | from testtools.matchers import Contains, Equals, raises |
297 | |
298 | +try: |
299 | + from unittest.mock import patch |
300 | +except ImportError: |
301 | + from mock import patch |
302 | + |
303 | from windowmocker.plugins import ( |
304 | base, |
305 | get_plugin_by_name, |
306 | register_plugin, |
307 | register_named_plugin, |
308 | - unregister_plugin_by_name |
309 | + unregister_plugin_by_name |
310 | ) |
311 | |
312 | class DummyAppPlugin(base.ApplicationTypePluginBase): |
313 | @@ -76,14 +80,16 @@ |
314 | DummyAppPlugin({}) |
315 | |
316 | self.assertThat(mock_create_window.call_count, Equals(1)) |
317 | - self.assertThat(mock_create_window.call_args[0][0], Equals(DummyAppPlugin._window_default)) |
318 | + self.assertThat(mock_create_window.call_args[0][0], |
319 | + Equals(DummyAppPlugin._window_default)) |
320 | |
321 | @patch.object(DummyAppPlugin, "create_window") |
322 | def test_calls_create_window_with_defaults_added(self, mock_create_window): |
323 | DummyAppPlugin({}) |
324 | |
325 | self.assertThat(mock_create_window.call_count, Equals(1)) |
326 | - self.assertThat(mock_create_window.call_args[0][0], Equals(DummyAppPlugin._window_default)) |
327 | + self.assertThat(mock_create_window.call_args[0][0], |
328 | + Equals(DummyAppPlugin._window_default)) |
329 | |
330 | @patch.object(DummyAppPlugin, "create_window") |
331 | def test_passes_params_to_create_window(self, mock_create_window): |
332 | @@ -103,8 +109,10 @@ |
333 | ]) |
334 | |
335 | self.assertThat(mock_create_window.call_count, Equals(2)) |
336 | - self.assertThat(mock_create_window.call_args_list[0][0][0]["Title"], Equals("Window 1")) |
337 | - self.assertThat(mock_create_window.call_args_list[1][0][0]["Title"], Equals("Window 2")) |
338 | + self.assertThat(mock_create_window.call_args_list[0][0][0]["Title"], |
339 | + Equals("Window 1")) |
340 | + self.assertThat(mock_create_window.call_args_list[1][0][0]["Title"], |
341 | + Equals("Window 2")) |
342 | |
343 | |
344 | class PluginWindowDefaultParameterTests(TestWithScenarios, TestCase): |
345 | @@ -112,10 +120,12 @@ |
346 | """Tests for various default values for required parameters.""" |
347 | |
348 | scenarios = [ |
349 | - ("Window Title", {'name': 'Title', 'expected': 'Default Window Title'}), |
350 | + ("Window Title", |
351 | + {'name': 'Title', 'expected': 'Default Window Title'}), |
352 | ("Maximised", {'name': 'Maximized', 'expected': False}), |
353 | ("Minimized", {'name': 'Minimized', 'expected': False}), |
354 | - ("MinimizeImmediatelyAfterShow", {'name': 'MinimizeImmediatelyAfterShow', 'expected': False}), |
355 | + ("MinimizeImmediatelyAfterShow", |
356 | + {'name': 'MinimizeImmediatelyAfterShow', 'expected': False}), |
357 | ("Menus", {'name': 'Menu', 'expected': []}), |
358 | ] |
359 | |
360 | |
361 | === renamed file 'tests/test_testapp_modlue_functions.py' => 'tests/test_testapp_module_functions.py' |
362 | --- tests/test_testapp_modlue_functions.py 2013-12-16 17:12:58 +0000 |
363 | +++ tests/test_testapp_module_functions.py 2014-02-05 16:22:14 +0000 |
364 | @@ -1,5 +1,5 @@ |
365 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
366 | -# Copyright 2012, 2013 Canonical |
367 | +# Copyright 2012-2014 Canonical, Ltd. |
368 | # Author: Thomi Richards |
369 | # |
370 | # This program is free software: you can redistribute it and/or modify it |
371 | @@ -8,9 +8,15 @@ |
372 | |
373 | |
374 | import os |
375 | +import tempfile |
376 | + |
377 | from io import StringIO |
378 | |
379 | -from mock import patch |
380 | +try: |
381 | + from unittest.mock import patch |
382 | +except ImportError: |
383 | + from mock import patch |
384 | + |
385 | from testtools import TestCase |
386 | from testtools.matchers import raises |
387 | |
388 | @@ -25,19 +31,21 @@ |
389 | """create_application_from_path function must raise IOError when asked |
390 | to open a file that does not exist. |
391 | """ |
392 | - self.assertThat(lambda: windowmocker.create_application_from_path("_does_not_exist"), |
393 | - raises(IOError)) |
394 | + self.assertThat(lambda: windowmocker.create_application_from_path("_does_not_exist"), raises(IOError)) |
395 | |
396 | - def test_create_application_from_path_raises_IOError_on_bad_perms(self): |
397 | - """create_application_from_path function must raise IOError when asked |
398 | - to open a file that does not exist. |
399 | + def test_create_application_from_path_raises_PermError_on_bad_perms(self): |
400 | + """create_application_from_path function must raise PermissionError |
401 | + when the file's permissions do not allow it to be read. |
402 | """ |
403 | - file_name = '_bad_perms' |
404 | - with open(file_name, 'w') as f: |
405 | - os.chmod(file_name, 0) |
406 | - self.addCleanup(os.remove, file_name) |
407 | + fd, temp_filename = tempfile.mkstemp() |
408 | + self.addCleanup(os.remove, temp_filename) |
409 | + os.close(fd) |
410 | + with open(temp_filename, 'w'): |
411 | + pass |
412 | + os.chmod(temp_filename, 0) |
413 | |
414 | - self.assertThat(lambda: windowmocker.create_application_from_path(file_name), |
415 | + self.assertThat( |
416 | + lambda: windowmocker.create_application_from_path(temp_filename), |
417 | raises(IOError)) |
418 | |
419 | |
420 | @@ -66,9 +74,15 @@ |
421 | |
422 | @patch('windowmocker.create_application_from_data') |
423 | def test_can_load_unicode_json(self, load_mock): |
424 | - windowmocker.create_application_from_file(StringIO(u'["ɥǝןןo", "ʍoɹןp"]')) |
425 | - load_mock.assert_called_once_with([u'\u0265\u01dd\u05df\u05dfo', u'\u028do\u0279\u05dfp'], None) |
426 | + windowmocker.create_application_from_file( |
427 | + StringIO(u'["ɥǝןןo", "ʍoɹןp"]')) |
428 | + load_mock.assert_called_once_with( |
429 | + [u'\u0265\u01dd\u05df\u05dfo', u'\u028do\u0279\u05dfp'], None) |
430 | |
431 | def test_raises_runtime_on_empty_file(self): |
432 | - fn = lambda: windowmocker.create_application_from_file(StringIO()) |
433 | - self.assertThat(fn, raises(RuntimeError("No JSON object could be decoded"))) |
434 | + # BAW 2014-01-31: We cannot assert on the exact error message |
435 | + # returned, because it's different between Python 3.3 and 3.4. |
436 | + # http://bugs.python.org/issue20453 |
437 | + self.assertThat( |
438 | + lambda: windowmocker.create_application_from_file(StringIO()), |
439 | + raises(RuntimeError)) |
440 | |
441 | === modified file 'windowmocker/__init__.py' |
442 | --- windowmocker/__init__.py 2014-01-07 20:05:34 +0000 |
443 | +++ windowmocker/__init__.py 2014-02-05 16:22:14 +0000 |
444 | @@ -1,5 +1,5 @@ |
445 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
446 | -# Copyright 2012 Canonical |
447 | +# Copyright 2012-2014 Canonical, Ltd. |
448 | # Author: Thomi Richards |
449 | # |
450 | # This program is free software: you can redistribute it and/or modify it |
451 | @@ -11,7 +11,7 @@ |
452 | import logging |
453 | import os |
454 | import subprocess |
455 | -from tempfile import mktemp |
456 | +import tempfile |
457 | from threading import Thread |
458 | |
459 | |
460 | @@ -38,8 +38,8 @@ |
461 | not readable. |
462 | |
463 | """ |
464 | - |
465 | - return create_application_from_file(open(path, 'r'), app_type_name) |
466 | + with open(path, 'r') as fp: |
467 | + return create_application_from_file(fp, app_type_name) |
468 | |
469 | |
470 | def create_application_from_file(file_object, app_type_name=None): |
471 | @@ -60,7 +60,7 @@ |
472 | return create_application_from_data(data, app_type_name) |
473 | |
474 | |
475 | -def create_application_from_data(data={}, app_type_name=None): |
476 | +def create_application_from_data(data=None, app_type_name=None): |
477 | """Create an application object from 'data'. |
478 | |
479 | If data is None (the default), a default application is constructed. |
480 | @@ -72,7 +72,8 @@ |
481 | expected format. |
482 | |
483 | """ |
484 | - |
485 | + if data is None: |
486 | + data = {} |
487 | if type(data) not in (dict, list): |
488 | raise RuntimeError( |
489 | "Top-level data structure must be a dictionary or list, not %r" % |
490 | @@ -111,13 +112,14 @@ |
491 | (type(data).__name__)) |
492 | |
493 | def run_thread(): |
494 | - file_path = mktemp() |
495 | - with open(file_path, 'w') as f: |
496 | - json.dump(data, f) |
497 | + fd, temp_filename = tempfile.mkstemp() |
498 | + os.close(fd) |
499 | try: |
500 | - subprocess.check_call(["window-mocker", file_path]) |
501 | + with open(temp_filename, 'w') as f: |
502 | + json.dump(data, f) |
503 | + subprocess.check_call(["window-mocker", temp_filename]) |
504 | finally: |
505 | - os.remove(file_path) |
506 | + os.remove(temp_filename) |
507 | |
508 | thread = Thread(target=run_thread) |
509 | thread.start() |
510 | |
511 | === modified file 'windowmocker/plugins/__init__.py' |
512 | --- windowmocker/plugins/__init__.py 2014-01-21 20:56:11 +0000 |
513 | +++ windowmocker/plugins/__init__.py 2014-02-05 16:22:14 +0000 |
514 | @@ -1,5 +1,5 @@ |
515 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
516 | -# Copyright 2012 Canonical |
517 | +# Copyright 2012-2014 Canonical, Ltd. |
518 | # Author: Thomi Richards |
519 | # |
520 | # This program is free software: you can redistribute it and/or modify it |
521 | @@ -45,7 +45,7 @@ |
522 | if sys.version_info[0] < 3: |
523 | del _plugin_registry['Qt5'] |
524 | return _plugin_registry.keys() |
525 | - |
526 | + |
527 | |
528 | def register_named_plugin(plugin_name, plugin_class): |
529 | global _plugin_registry |
530 | @@ -59,7 +59,7 @@ |
531 | |
532 | def register_plugin(plugin_class): |
533 | """Register plugin_class. Probably not ever needed, except by tests. |
534 | - |
535 | + |
536 | This function is deprecated and may be removed in a future release. |
537 | Use `register_named_plugin` instead.""" |
538 | global _plugin_registry |
539 | |
540 | === modified file 'windowmocker/plugins/base.py' |
541 | --- windowmocker/plugins/base.py 2014-01-15 19:17:26 +0000 |
542 | +++ windowmocker/plugins/base.py 2014-02-05 16:22:14 +0000 |
543 | @@ -1,5 +1,5 @@ |
544 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
545 | -# Copyright 2012 Canonical |
546 | +# Copyright 2012-2014 Canonical, Ltd. |
547 | # Author: Thomi Richards |
548 | # |
549 | # This program is free software: you can redistribute it and/or modify it |
550 | @@ -33,10 +33,10 @@ |
551 | if not spec_dictionary: |
552 | logger.warning("Specification contains no window specification. Creating a default window.") |
553 | |
554 | - if type(spec_dictionary) is dict: |
555 | + if isinstance(spec_dictionary, dict): |
556 | window_spec = self._create_window_spec(spec_dictionary) |
557 | self.create_window(window_spec) |
558 | - elif type(spec_dictionary) is list: |
559 | + elif isinstance(spec_dictionary, list): |
560 | for window in spec_dictionary: |
561 | window_spec = self._create_window_spec(window) |
562 | self.create_window(window_spec) |
563 | @@ -52,12 +52,15 @@ |
564 | |
565 | def create_application(self): |
566 | """Create an application.""" |
567 | - raise NotImplementedError("This method must be implemeneted by child classes.") |
568 | + raise NotImplementedError( |
569 | + "This method must be implemented by child classes.") |
570 | |
571 | def create_window(self, window_spec): |
572 | """Create a window, according to 'window_spec'.""" |
573 | - raise NotImplementedError("This method must be implemeneted by child classes.") |
574 | + raise NotImplementedError( |
575 | + "This method must be implemented by child classes.") |
576 | |
577 | def run(self): |
578 | """Enter the event loop - run the application & windows.""" |
579 | - raise NotImplementedError("This method must be implemeneted by child classes.") |
580 | + raise NotImplementedError( |
581 | + "This method must be implemented by child classes.") |
582 | |
583 | === modified file 'windowmocker/plugins/qt4.py' |
584 | --- windowmocker/plugins/qt4.py 2014-01-21 20:26:48 +0000 |
585 | +++ windowmocker/plugins/qt4.py 2014-02-05 16:22:14 +0000 |
586 | @@ -1,12 +1,11 @@ |
587 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
588 | -# Copyright 2012, 2013 Canonical |
589 | +# Copyright 2012-2014 Canonical, Ltd. |
590 | # Author: Thomi Richards |
591 | # |
592 | # This program is free software: you can redistribute it and/or modify it |
593 | # under the terms of the GNU General Public License version 3, as published |
594 | # by the Free Software Foundation. |
595 | |
596 | -from __future__ import print_function |
597 | import logging |
598 | from PyQt4 import QtCore, QtGui |
599 | import sys |
600 | @@ -47,8 +46,8 @@ |
601 | if not window_spec['Maximized'] and not window_spec['Minimized']: |
602 | win.showNormal() |
603 | |
604 | - # In some cases, it's also needed to have the appliaction start normally |
605 | - # but minimize itself right after starting |
606 | + # In some cases, it's also needed to have the application start |
607 | + # normally but minimize itself right after starting |
608 | if window_spec['MinimizeImmediatelyAfterShow']: |
609 | win.setWindowState(QtCore.Qt.WindowMinimized) |
610 | |
611 | @@ -63,7 +62,7 @@ |
612 | menu = parent.addMenu(title) |
613 | if 'Menu' in item: |
614 | self._create_menus(menu, item['Menu']) |
615 | - elif isinstance(item, basestring): |
616 | + elif isinstance(item, str): |
617 | parent.addAction(item) |
618 | else: |
619 | logger.error("Invalid menu item - is not a dict or string: %r", item) |
620 | |
621 | === modified file 'windowmocker/plugins/qt5.py' |
622 | --- windowmocker/plugins/qt5.py 2014-01-21 17:30:10 +0000 |
623 | +++ windowmocker/plugins/qt5.py 2014-02-05 16:22:14 +0000 |
624 | @@ -1,5 +1,5 @@ |
625 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
626 | -# Copyright 2012, 2013 Canonical |
627 | +# Copyright 2012-2014 Canonical, Ltd. |
628 | # |
629 | # This program is free software: you can redistribute it and/or modify it |
630 | # under the terms of the GNU General Public License version 3, as published |
631 | @@ -8,11 +8,11 @@ |
632 | from __future__ import print_function |
633 | import logging |
634 | from PyQt5 import QtCore, QtWidgets |
635 | +import six |
636 | import sys |
637 | |
638 | from windowmocker.plugins.base import ApplicationTypePluginBase |
639 | |
640 | - |
641 | logger = logging.getLogger(__name__) |
642 | |
643 | class QtPlugin(ApplicationTypePluginBase): |
644 | @@ -46,8 +46,8 @@ |
645 | if not window_spec['Maximized'] and not window_spec['Minimized']: |
646 | win.showNormal() |
647 | |
648 | - # In some cases, it's also needed to have the appliaction start normally |
649 | - # but minimize itself right after starting |
650 | + # In some cases, it's also needed to have the application start |
651 | + # normally but minimize itself right after starting |
652 | if window_spec['MinimizeImmediatelyAfterShow']: |
653 | win.setWindowState(QtCore.Qt.WindowMinimized) |
654 | |
655 | @@ -62,7 +62,7 @@ |
656 | menu = parent.addMenu(title) |
657 | if 'Menu' in item: |
658 | self._create_menus(menu, item['Menu']) |
659 | - elif isinstance(item, basestring): |
660 | + elif isinstance(item, six.string_types): |
661 | parent.addAction(item) |
662 | else: |
663 | logger.error("Invalid menu item - is not a dict or string: %r", item) |
Hi Barry,
I have a pending py3 branch also. Mine is Python 2/3 compatible and can select PyQt4 or PyQt5 in the python3 version.
The reason it has yet to be merged is because of a bug in PyQt5 causing a segfault:
the bug is here: /bugs.launchpad .net/window- mocker/ +bug/1273306
https:/
my branch is here: /code.launchpad .net/~coreygold berg/window- mocker/ py3
https:/
-Corey