Merge lp:~abentley/juju-ci-tools/more-py3-2 into lp:juju-ci-tools
- more-py3-2
- Merge into trunk
Proposed by
Aaron Bentley
Status: | Merged |
---|---|
Merged at revision: | 1932 |
Proposed branch: | lp:~abentley/juju-ci-tools/more-py3-2 |
Merge into: | lp:juju-ci-tools |
Prerequisite: | lp:~abentley/juju-ci-tools/more-py3 |
Diff against target: |
396 lines (+59/-42) 7 files modified
jujupy/client.py (+5/-3) jujupy/fake.py (+1/-1) jujupy/tests/test_client.py (+29/-22) jujupy/tests/test_version_client.py (+8/-8) jujupy/utility.py (+2/-2) jujupy/version_client.py (+3/-1) tests/__init__.py (+11/-5) |
To merge this branch: | bzr merge lp:~abentley/juju-ci-tools/more-py3-2 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Curtis Hovey (community) | code | Approve | |
Review via email: mp+319616@code.launchpad.net |
Commit message
Improve Python3 compatibility of jujupy.
Description of the change
This branch improves the Python3 compatibility of jujupy, along the same lines as the previous branch.
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 'jujupy/client.py' |
2 | --- jujupy/client.py 2017-03-10 19:57:45 +0000 |
3 | +++ jujupy/client.py 2017-03-10 19:57:46 +0000 |
4 | @@ -1914,7 +1914,8 @@ |
5 | |
6 | def get_env_option(self, option): |
7 | """Return the value of the environment's configured option.""" |
8 | - return self.get_juju_output('model-config', option) |
9 | + return self.get_juju_output( |
10 | + 'model-config', option).decode(getpreferredencoding()) |
11 | |
12 | def set_env_option(self, option, value): |
13 | """Set the value of the option in the environment.""" |
14 | @@ -2474,7 +2475,8 @@ |
15 | log.info(e.output) |
16 | raise |
17 | log.info(output) |
18 | - backup_file_pattern = re.compile('(juju-backup-[0-9-]+\.(t|tar.)gz)') |
19 | + backup_file_pattern = re.compile( |
20 | + '(juju-backup-[0-9-]+\.(t|tar.)gz)'.encode('ascii')) |
21 | match = backup_file_pattern.search(output) |
22 | if match is None: |
23 | raise Exception("The backup file was not found in output: %s" % |
24 | @@ -2482,7 +2484,7 @@ |
25 | backup_file_name = match.group(1) |
26 | backup_file_path = os.path.abspath(backup_file_name) |
27 | log.info("State-Server backup at %s", backup_file_path) |
28 | - return backup_file_path |
29 | + return backup_file_path.decode(getpreferredencoding()) |
30 | |
31 | def restore_backup(self, backup_file): |
32 | self.juju( |
33 | |
34 | === modified file 'jujupy/fake.py' |
35 | --- jujupy/fake.py 2017-03-10 19:57:45 +0000 |
36 | +++ jujupy/fake.py 2017-03-10 19:57:46 +0000 |
37 | @@ -1050,7 +1050,7 @@ |
38 | |
39 | |
40 | def get_user_register_token(username): |
41 | - return b64encode(sha512(username).digest()) |
42 | + return b64encode(sha512(username.encode('utf-8')).digest()).decode('ascii') |
43 | |
44 | |
45 | class FakeBackend2_1(FakeBackend): |
46 | |
47 | === modified file 'jujupy/tests/test_client.py' |
48 | --- jujupy/tests/test_client.py 2017-03-10 19:57:45 +0000 |
49 | +++ jujupy/tests/test_client.py 2017-03-10 19:57:46 +0000 |
50 | @@ -337,9 +337,9 @@ |
51 | self.assertEqual(300, conditions.timeout) |
52 | |
53 | def test_iter_blocking_state(self): |
54 | - mock_ab = Mock() |
55 | + mock_ab = Mock(timeout=0) |
56 | mock_ab.iter_blocking_state.return_value = [('a', 'b')] |
57 | - mock_cd = Mock() |
58 | + mock_cd = Mock(timeout=0) |
59 | mock_cd.iter_blocking_state.return_value = [('c', 'd')] |
60 | conditions = ConditionList([mock_ab, mock_cd]) |
61 | self.assertEqual([('a', 'b'), ('c', 'd')], |
62 | @@ -425,14 +425,15 @@ |
63 | self.assertEqual(client.env.juju_home, 'baz') |
64 | |
65 | def test_get_version(self): |
66 | - value = ' 5.6 \n' |
67 | + value = ' 5.6 \n'.encode('ascii') |
68 | with patch('subprocess.check_output', return_value=value) as vsn: |
69 | version = ModelClient.get_version() |
70 | self.assertEqual('5.6', version) |
71 | vsn.assert_called_with(('juju', '--version')) |
72 | |
73 | def test_get_version_path(self): |
74 | - with patch('subprocess.check_output', return_value=' 4.3') as vsn: |
75 | + with patch('subprocess.check_output', |
76 | + return_value=' 4.3'.encode('ascii')) as vsn: |
77 | ModelClient.get_version('foo/bar/baz') |
78 | vsn.assert_called_once_with(('foo/bar/baz', '--version')) |
79 | |
80 | @@ -982,7 +983,7 @@ |
81 | fake_popen = FakePopen('asdf', None, 0) |
82 | with patch('subprocess.Popen', return_value=fake_popen) as mock: |
83 | result = client.get_juju_output('bar') |
84 | - self.assertEqual('asdf', result) |
85 | + self.assertEqual('asdf'.encode('ascii'), result) |
86 | self.assertEqual((('juju', '--show-log', 'bar', '-m', 'foo:foo'),), |
87 | mock.call_args[0]) |
88 | |
89 | @@ -992,7 +993,7 @@ |
90 | client = ModelClient(env, None, 'juju') |
91 | with patch('subprocess.Popen', return_value=fake_popen) as mock: |
92 | result = client.get_juju_output('bar', 'baz', '--qux') |
93 | - self.assertEqual('asdf', result) |
94 | + self.assertEqual('asdf'.encode('ascii'), result) |
95 | self.assertEqual((('juju', '--show-log', 'bar', '-m', 'foo:foo', 'baz', |
96 | '--qux'),), mock.call_args[0]) |
97 | |
98 | @@ -1003,7 +1004,7 @@ |
99 | with self.assertRaises(subprocess.CalledProcessError) as exc: |
100 | with patch('subprocess.Popen', return_value=fake_popen): |
101 | client.get_juju_output('bar') |
102 | - self.assertEqual(exc.exception.stderr, 'Hello!') |
103 | + self.assertEqual(exc.exception.stderr, 'Hello!'.encode('ascii')) |
104 | |
105 | def test_get_juju_output_merge_stderr(self): |
106 | env = JujuData('foo') |
107 | @@ -1011,7 +1012,7 @@ |
108 | client = ModelClient(env, None, 'juju') |
109 | with patch('subprocess.Popen', return_value=fake_popen) as mock_popen: |
110 | result = client.get_juju_output('bar', merge_stderr=True) |
111 | - self.assertEqual(result, 'Err on out') |
112 | + self.assertEqual(result, 'Err on out'.encode('ascii')) |
113 | mock_popen.assert_called_once_with( |
114 | ('juju', '--show-log', 'bar', '-m', 'foo:foo'), |
115 | stdin=subprocess.PIPE, stderr=subprocess.STDOUT, |
116 | @@ -1062,7 +1063,7 @@ |
117 | - a |
118 | - b |
119 | - c |
120 | - """) |
121 | + """).encode('ascii') |
122 | env = JujuData('foo') |
123 | client = ModelClient(env, None, None) |
124 | with patch.object(client, 'get_juju_output', |
125 | @@ -1080,7 +1081,7 @@ |
126 | |
127 | def get_juju_output(command, *args, **kwargs): |
128 | if client.attempt == 1: |
129 | - return '"hello"' |
130 | + return '"hello"'.encode('ascii') |
131 | client.attempt += 1 |
132 | raise subprocess.CalledProcessError(1, command) |
133 | |
134 | @@ -1370,7 +1371,8 @@ |
135 | with patch.object(client, 'get_juju_output', return_value=status_txt): |
136 | result = list(client.status_until(-1)) |
137 | self.assertEqual( |
138 | - [r.status for r in result], [Status.from_text(status_txt).status]) |
139 | + [r.status for r in result], |
140 | + [Status.from_text(status_txt.decode('ascii')).status]) |
141 | |
142 | def test_status_until_timeout(self): |
143 | client = ModelClient( |
144 | @@ -1710,7 +1712,8 @@ |
145 | 'Timed out waiting for agents to start in local'): |
146 | client.wait_for_started(0) |
147 | self.assertEqual(writes, ['pending: 0', '\n']) |
148 | - self.assertEqual(self.log_stream.getvalue(), 'ERROR %s\n' % value) |
149 | + self.assertEqual( |
150 | + self.log_stream.getvalue(), 'ERROR %s\n' % value.decode('ascii')) |
151 | |
152 | def test_wait_for_subordinate_units(self): |
153 | value = dedent("""\ |
154 | @@ -1732,7 +1735,7 @@ |
155 | agent-state: started |
156 | sub3/0: |
157 | agent-state: started |
158 | - """) |
159 | + """).encode('ascii') |
160 | client = ModelClient(JujuData('local'), None, None) |
161 | now = datetime.now() + timedelta(days=1) |
162 | with patch('utility.until_timeout.now', return_value=now): |
163 | @@ -1770,7 +1773,7 @@ |
164 | sub3/0: |
165 | agent-status: |
166 | current: idle |
167 | - """) |
168 | + """).encode('ascii') |
169 | client = ModelClient(JujuData('local'), None, None) |
170 | now = datetime.now() + timedelta(days=1) |
171 | with patch('utility.until_timeout.now', return_value=now): |
172 | @@ -1801,7 +1804,7 @@ |
173 | subordinates: |
174 | sub/1: |
175 | agent-state: started |
176 | - """) |
177 | + """).encode('ascii') |
178 | client = ModelClient(JujuData('local'), None, None) |
179 | now = datetime.now() + timedelta(days=1) |
180 | with patch('utility.until_timeout.now', return_value=now): |
181 | @@ -1828,7 +1831,7 @@ |
182 | subordinates: |
183 | sub1: |
184 | agent-state: started |
185 | - """) |
186 | + """).encode('ascii') |
187 | client = ModelClient(JujuData('local'), None, None) |
188 | now = datetime.now() + timedelta(days=1) |
189 | with patch('utility.until_timeout.now', return_value=now): |
190 | @@ -1849,7 +1852,7 @@ |
191 | units: |
192 | jenkins/0: |
193 | agent-state: started |
194 | - """) |
195 | + """).encode('ascii') |
196 | client = ModelClient(JujuData('local'), None, None) |
197 | now = datetime.now() + timedelta(days=1) |
198 | with patch('utility.until_timeout.now', return_value=now): |
199 | @@ -2281,7 +2284,7 @@ |
200 | return client.get_controller_client() |
201 | |
202 | def test_wait_for_ha(self): |
203 | - value = yaml.safe_dump(self.make_ha_status()) |
204 | + value = yaml.safe_dump(self.make_ha_status()).encode('ascii') |
205 | client = self.make_controller_client() |
206 | with patch.object(client, 'get_juju_output', |
207 | return_value=value) as gjo_mock: |
208 | @@ -2339,7 +2342,7 @@ |
209 | '1': {'agent-state-info': 'error: foo'}, |
210 | }, |
211 | 'services': {}, |
212 | - }) |
213 | + }).encode('ascii') |
214 | client = self.make_controller_client() |
215 | with patch('jujupy.client.until_timeout', autospec=True, |
216 | return_value=[2, 1]): |
217 | @@ -2371,7 +2374,7 @@ |
218 | } |
219 | } |
220 | } |
221 | - }) |
222 | + }).encode('ascii') |
223 | client = ModelClient(JujuData('local'), None, None) |
224 | with patch.object(client, 'get_juju_output', return_value=value): |
225 | client.wait_for_deploy_started() |
226 | @@ -2476,7 +2479,7 @@ |
227 | 'machines': { |
228 | '0': {'agent-state': 'started'}, |
229 | }, |
230 | - }) |
231 | + }).encode('ascii') |
232 | client = ModelClient(JujuData('local'), None, None) |
233 | with patch.object(client, 'get_juju_output', return_value=value): |
234 | client.wait_for(WaitMachineNotPresent('1'), quiet=True) |
235 | @@ -4735,7 +4738,7 @@ |
236 | |
237 | def test_from_text(self): |
238 | text = TestModelClient.make_status_yaml( |
239 | - 'agent-state', 'pending', 'horsefeathers') |
240 | + 'agent-state', 'pending', 'horsefeathers').decode('ascii') |
241 | status = Status.from_text(text) |
242 | self.assertEqual(status.status_text, text) |
243 | self.assertEqual(status.status, { |
244 | @@ -5939,7 +5942,11 @@ |
245 | status = Status.from_text(self.machine_0_ipv6) |
246 | fake_client = Mock(spec=['status_until']) |
247 | fake_client.status_until.return_value = [status] |
248 | + socket_error = socket.error |
249 | with patch('jujupy.utility.socket', wraps=socket) as wrapped_socket: |
250 | + # Must not convert socket.error into a Mock, because Mocks don't |
251 | + # descend from BaseException |
252 | + wrapped_socket.error = socket_error |
253 | del wrapped_socket.inet_pton |
254 | host = get_machine_dns_name(fake_client, '0') |
255 | self.assertEqual(host, "2001:db8::3") |
256 | |
257 | === modified file 'jujupy/tests/test_version_client.py' |
258 | --- jujupy/tests/test_version_client.py 2017-03-10 19:57:45 +0000 |
259 | +++ jujupy/tests/test_version_client.py 2017-03-10 19:57:46 +0000 |
260 | @@ -657,7 +657,7 @@ |
261 | fake_popen = FakePopen('asdf', None, 0) |
262 | with patch('subprocess.Popen', return_value=fake_popen) as mock: |
263 | result = client.get_juju_output('bar') |
264 | - self.assertEqual('asdf', result) |
265 | + self.assertEqual('asdf', result.encode('ascii')) |
266 | self.assertEqual((('juju', '--show-log', 'bar', '-e', 'foo'),), |
267 | mock.call_args[0]) |
268 | |
269 | @@ -667,7 +667,7 @@ |
270 | client = EnvJujuClient1X(env, None, 'juju') |
271 | with patch('subprocess.Popen', return_value=fake_popen) as mock: |
272 | result = client.get_juju_output('bar', 'baz', '--qux') |
273 | - self.assertEqual('asdf', result) |
274 | + self.assertEqual('asdf'.encode('ascii'), result) |
275 | self.assertEqual((('juju', '--show-log', 'bar', '-e', 'foo', 'baz', |
276 | '--qux'),), mock.call_args[0]) |
277 | |
278 | @@ -678,8 +678,8 @@ |
279 | with self.assertRaises(subprocess.CalledProcessError) as exc: |
280 | with patch('subprocess.Popen', return_value=fake_popen): |
281 | client.get_juju_output('bar') |
282 | - self.assertEqual(exc.exception.output, 'Hello') |
283 | - self.assertEqual(exc.exception.stderr, 'Error!') |
284 | + self.assertEqual(exc.exception.output, 'Hello'.encode('ascii')) |
285 | + self.assertEqual(exc.exception.stderr, 'Error!'.encode('ascii')) |
286 | |
287 | def test_get_juju_output_full_cmd(self): |
288 | env = SimpleEnvironment('foo') |
289 | @@ -1046,7 +1046,7 @@ |
290 | subordinates: |
291 | sub/1: |
292 | agent-state: started |
293 | - """) |
294 | + """).encode('ascii') |
295 | client = EnvJujuClient1X(SimpleEnvironment('local'), None, None) |
296 | now = datetime.now() + timedelta(days=1) |
297 | with patch('utility.until_timeout.now', return_value=now): |
298 | @@ -1181,7 +1181,7 @@ |
299 | '2': {'state-server-member-status': 'has-vote'}, |
300 | }, |
301 | 'services': {}, |
302 | - }) |
303 | + }).encode('ascii') |
304 | client = EnvJujuClient1X(SimpleEnvironment('local'), None, None) |
305 | with patch.object(client, 'get_juju_output', return_value=value): |
306 | client.wait_for_ha() |
307 | @@ -1194,7 +1194,7 @@ |
308 | '2': {'state-server-member-status': 'no-vote'}, |
309 | }, |
310 | 'services': {}, |
311 | - }) |
312 | + }).encode('ascii') |
313 | client = EnvJujuClient1X(SimpleEnvironment('local'), None, None) |
314 | with patch.object(client, 'get_juju_output', return_value=value): |
315 | writes = [] |
316 | @@ -1240,7 +1240,7 @@ |
317 | } |
318 | } |
319 | } |
320 | - }) |
321 | + }).encode('ascii') |
322 | client = EnvJujuClient1X(SimpleEnvironment('local'), None, None) |
323 | with patch.object(client, 'get_juju_output', return_value=value): |
324 | client.wait_for_deploy_started() |
325 | |
326 | === modified file 'jujupy/utility.py' |
327 | --- jujupy/utility.py 2017-02-22 18:05:47 +0000 |
328 | +++ jujupy/utility.py 2017-03-10 19:57:46 +0000 |
329 | @@ -168,9 +168,9 @@ |
330 | |
331 | @contextmanager |
332 | def temp_yaml_file(yaml_dict, encoding="utf-8"): |
333 | - temp_file = NamedTemporaryFile(suffix='.yaml', delete=False) |
334 | + temp_file_cxt = NamedTemporaryFile(suffix='.yaml', delete=False) |
335 | try: |
336 | - with temp_file: |
337 | + with temp_file_cxt as temp_file: |
338 | yaml.safe_dump(yaml_dict, temp_file, encoding=encoding) |
339 | yield temp_file.name |
340 | finally: |
341 | |
342 | === modified file 'jujupy/version_client.py' |
343 | --- jujupy/version_client.py 2017-03-01 19:02:24 +0000 |
344 | +++ jujupy/version_client.py 2017-03-10 19:57:46 +0000 |
345 | @@ -1,5 +1,6 @@ |
346 | from contextlib import contextmanager |
347 | import json |
348 | +from locale import getpreferredencoding |
349 | import logging |
350 | import os |
351 | import re |
352 | @@ -370,7 +371,8 @@ |
353 | |
354 | def get_env_option(self, option): |
355 | """Return the value of the environment's configured option.""" |
356 | - return self.get_juju_output('get-env', option) |
357 | + return self.get_juju_output( |
358 | + 'get-env', option).decode(getpreferredencoding()) |
359 | |
360 | def set_env_option(self, option, value): |
361 | """Set the value of the option in the environment.""" |
362 | |
363 | === modified file 'tests/__init__.py' |
364 | --- tests/__init__.py 2017-03-10 19:57:45 +0000 |
365 | +++ tests/__init__.py 2017-03-10 19:57:46 +0000 |
366 | @@ -173,8 +173,8 @@ |
367 | """Create an artifical version of the Popen class.""" |
368 | |
369 | def __init__(self, out, err, returncode): |
370 | - self._out = out |
371 | - self._err = err |
372 | + self._out = out if out is None else out.encode('ascii') |
373 | + self._err = err if err is None else err.encode('ascii') |
374 | self._code = returncode |
375 | |
376 | def communicate(self): |
377 | @@ -191,10 +191,16 @@ |
378 | temporary_file = NamedTemporaryFile(delete=False) |
379 | try: |
380 | with temporary_file as temp_file: |
381 | + |
382 | + @contextmanager |
383 | + def nt(): |
384 | + # This is used to prevent NamedTemporaryFile.close from being |
385 | + # called. |
386 | + yield temporary_file |
387 | + |
388 | with patch('jujupy.utility.NamedTemporaryFile', |
389 | - return_value=temp_file): |
390 | - with patch.object(temp_file, '__exit__'): |
391 | - yield temp_file |
392 | + return_value=nt()): |
393 | + yield temp_file |
394 | finally: |
395 | # File may have already been deleted, e.g. by temp_yaml_file. |
396 | with utility.skip_on_missing_file(): |
Thank you.