Merge lp:~chris.macnaughton/mojo/py3002 into lp:~ost-maintainers/mojo/py3
- py3002
- Merge into py3
Status: | Merged |
---|---|
Approved by: | Ryan Beisner |
Approved revision: | 474 |
Merged at revision: | 465 |
Proposed branch: | lp:~chris.macnaughton/mojo/py3002 |
Merge into: | lp:~ost-maintainers/mojo/py3 |
Diff against target: |
337 lines (+71/-33) 9 files modified
contrib/test/utils.py (+1/-1) mojo/cli.py (+13/-15) mojo/juju/status.py (+3/-1) mojo/juju/wait.py (+3/-0) mojo/phase.py (+4/-1) mojo/tests/test_juju2.py (+19/-9) mojo/utils.py (+3/-0) setup.py (+1/-0) tox.ini (+24/-6) |
To merge this branch: | bzr merge lp:~chris.macnaughton/mojo/py3002 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
OpenStack Charm Testing Maintainers | Pending | ||
Review via email: mp+336352@code.launchpad.net |
Commit message
Description of the change
- 470. By Chris MacNaughton
-
add list() back around map() to make it work on py2+3
Chris MacNaughton (chris.macnaughton) wrote : | # |
Chris MacNaughton (chris.macnaughton) wrote : | # |
Not quite py3 ready:
2018-01-24 11:10:49 [INFO] Rsyncing /home/ubuntu/
2018-01-24 11:10:50 [INFO] Retrieve the spec's manifest
2018-01-24 11:10:50 [INFO] Manifest comment:
#######
Collect the charm branches from Launchpad
#######
2018-01-24 11:10:50 [INFO] Building resource tree
2018-01-24 11:10:50 [ERROR] Unknown error
Traceback (most recent call last):
File "/home/
args.func(args)
File "/home/
return method(*args, **kwargs)
File "/home/
manifest.
File "/home/
auto_
File "/home/
rendered_
File "/home/
return func(*args, **kwargs)
TypeError: a bytes-like object is required, not 'str'
- 471. By Chris MacNaughton
-
decode bytes to str
- 472. By Chris MacNaughton
-
import six
- 473. By Chris MacNaughton
-
add encoding to popen
- 474. By Chris MacNaughton
-
ensure we decode command line output if needed
Chris MacNaughton (chris.macnaughton) wrote : | # |
Ok, have run the openstack-
Preview Diff
1 | === modified file 'contrib/test/utils.py' |
2 | --- contrib/test/utils.py 2018-01-18 10:23:15 +0000 |
3 | +++ contrib/test/utils.py 2018-01-25 14:10:22 +0000 |
4 | @@ -44,6 +44,6 @@ |
5 | """ |
6 | try: |
7 | subprocess.check_output(['juju', 'switch']) |
8 | - except subprocess.CalledProcessError as OSError: |
9 | + except subprocess.CalledProcessError, OSError: |
10 | print('Error checking active Juju controller') |
11 | sys.exit(1) |
12 | |
13 | === modified file 'mojo/cli.py' |
14 | --- mojo/cli.py 2018-01-18 10:23:15 +0000 |
15 | +++ mojo/cli.py 2018-01-25 14:10:22 +0000 |
16 | @@ -1,6 +1,6 @@ |
17 | # Copyright 2014, 2015 Canonical Ltd. This software is licensed under the |
18 | # GNU General Public License version 3 (see the file LICENSE). |
19 | - |
20 | +from __future__ import print_function |
21 | import argparse |
22 | import errno |
23 | import logging |
24 | @@ -76,7 +76,7 @@ |
25 | |
26 | |
27 | def exit_with_usage(parser, message): |
28 | - print(message + "\n", file=sys.stderr) |
29 | + sys.stderr.write(message + "\n") |
30 | parser.print_help(file=sys.stderr) |
31 | sys.exit(1) |
32 | |
33 | @@ -268,7 +268,7 @@ |
34 | try: |
35 | project.create_workspace(spec_url, workspace, stage=args.stage, logfile=args.logfile) |
36 | except OSError: |
37 | - print("Are you sure the project exists?", file=sys.stderr) |
38 | + sys.stderr.write("Are you sure the project exists?") |
39 | if args.blunt: |
40 | raise |
41 | sys.exit(2) |
42 | @@ -649,9 +649,9 @@ |
43 | sys.exit(1) |
44 | except mojo.exceptions.ConfigNotFoundException as e: |
45 | logging.error(e.message) |
46 | - print("Searched:", file=sys.stderr) |
47 | + sys.stderr.write("Searched:") |
48 | for path in e.search_list: |
49 | - print(" {}".format(path), file=sys.stderr) |
50 | + sys.stderr.write(" {}".format(path)) |
51 | sys.exit(1) |
52 | except (mojo.exceptions.InvalidManifestException, |
53 | mojo.phase.FileDoesNotExistException, |
54 | @@ -672,14 +672,14 @@ |
55 | if ioe.errno != errno.EACCES: |
56 | raise |
57 | |
58 | - print('ERROR: Unable to read container configuration ' |
59 | - 'from {}'.format(filename), file=sys.stderr) |
60 | + sys.stderr.write('ERROR: Unable to read container configuration ' |
61 | + 'from {}'.format(filename)) |
62 | |
63 | try: |
64 | os.listdir('/var/lib/lxc') |
65 | except OSError as ose: |
66 | if ose.errno == errno.EACCES: |
67 | - print(dedent( |
68 | + sys.stderr.write(dedent( |
69 | '''\ |
70 | ERROR: /var/lib/lxc is not readable; consider one of the following: |
71 | |
72 | @@ -688,8 +688,7 @@ |
73 | sudo chmod 0750 /var/lib/lxc |
74 | |
75 | Option 2: |
76 | - sudo chmod 0755 /var/lib/lxc'''), |
77 | - file=sys.stderr) |
78 | + sudo chmod 0755 /var/lib/lxc''')) |
79 | sys.exit(1) |
80 | |
81 | try: |
82 | @@ -699,18 +698,17 @@ |
83 | # The problem isn't /var/lib/lxc; it's the container! |
84 | if ose.errno == errno.EACCES: |
85 | # We know it's not /var/lib/lxc; that was checked above. |
86 | - print(dedent( |
87 | + sys.stderr.write(dedent( |
88 | '''\ |
89 | ERROR: {container} exists but is not readable; consider doing the following: |
90 | |
91 | sudo chmod 0755 {container}''').format( |
92 | - container=container), |
93 | - file=sys.stderr) |
94 | + container=container)) |
95 | sys.exit(1) |
96 | if ose.errno == errno.ENOENT: |
97 | # Mojo checks this itself, so this would be very strange. |
98 | - print('ERROR: {} does not exist; was the Mojo project ' |
99 | - 'created properly?!'.format(container), file=sys.stderr) |
100 | + sys.stderr.write('ERROR: {} does not exist; was the Mojo project ' |
101 | + 'created properly?!'.format(container)) |
102 | sys.exit(1) |
103 | |
104 | # Some things are beyond even our powers to diagnose. |
105 | |
106 | === modified file 'mojo/juju/status.py' |
107 | --- mojo/juju/status.py 2018-01-18 10:23:15 +0000 |
108 | +++ mojo/juju/status.py 2018-01-25 14:10:22 +0000 |
109 | @@ -4,6 +4,7 @@ |
110 | import subprocess |
111 | import time |
112 | import yaml |
113 | +import six |
114 | |
115 | from collections import Counter |
116 | |
117 | @@ -12,6 +13,8 @@ |
118 | try: |
119 | with open(os.devnull, 'w') as devnull: |
120 | version = subprocess.check_output(['juju', 'version'], stderr=devnull) |
121 | + if six.PY3: |
122 | + version = version.decode('utf-8') |
123 | major_version = int(version[0]) |
124 | except subprocess.CalledProcessError: |
125 | # In cases where the Juju Status yaml is provided by a file this may legitimately fail |
126 | @@ -463,7 +466,6 @@ |
127 | # self.ready() will raise exceptions on error states |
128 | if self.ready() or not wait_for_steady: |
129 | return |
130 | - |
131 | logging.info("Waiting for environment to reach steady state") |
132 | wait(max_wait=timeout) |
133 | logging.info("Environment has reached steady state") |
134 | |
135 | === modified file 'mojo/juju/wait.py' |
136 | --- mojo/juju/wait.py 2018-01-18 10:23:15 +0000 |
137 | +++ mojo/juju/wait.py 2018-01-25 14:10:22 +0000 |
138 | @@ -31,6 +31,7 @@ |
139 | from textwrap import dedent |
140 | import time |
141 | import yaml |
142 | +import six |
143 | |
144 | |
145 | __version__ = '2.5.0' |
146 | @@ -76,6 +77,8 @@ |
147 | logging.error(err) |
148 | logging.error("{} failed: {}".format(' '.join(cmd), p.returncode)) |
149 | raise JujuWaitException(p.returncode or 43) |
150 | + if six.PY3: |
151 | + out = out.decode('utf-8') |
152 | return out |
153 | |
154 | |
155 | |
156 | === modified file 'mojo/phase.py' |
157 | --- mojo/phase.py 2018-01-18 11:04:39 +0000 |
158 | +++ mojo/phase.py 2018-01-25 14:10:22 +0000 |
159 | @@ -25,6 +25,7 @@ |
160 | import mojo.juju |
161 | import mojo.juju.utils |
162 | import codetree |
163 | +import six |
164 | from deployer.config import ConfigStack |
165 | |
166 | |
167 | @@ -215,7 +216,7 @@ |
168 | with chdir(workspace.build_dir): |
169 | try: |
170 | tmpl_vars = {'series': project.series} |
171 | - with tempfile.NamedTemporaryFile() as rendered_collect: |
172 | + with tempfile.NamedTemporaryFile(mode='wt') as rendered_collect: |
173 | with open(config) as inp: |
174 | try: |
175 | rendered_collect.write(Template(inp.read()).render(**tmpl_vars)) |
176 | @@ -363,6 +364,8 @@ |
177 | command = env_vars + [script] |
178 | try: |
179 | output = subprocess.check_output(command, stderr=subprocess.STDOUT) |
180 | + if six.PY3: |
181 | + output = output.decode('utf-8') |
182 | except subprocess.CalledProcessError as e: |
183 | if gather_debug_logs: |
184 | exception_output = self._gather_debug_logs(e, workspace, stage) |
185 | |
186 | === modified file 'mojo/tests/test_juju2.py' |
187 | --- mojo/tests/test_juju2.py 2018-01-18 10:23:15 +0000 |
188 | +++ mojo/tests/test_juju2.py 2018-01-25 14:10:22 +0000 |
189 | @@ -128,19 +128,22 @@ |
190 | def test_model_version(self): |
191 | self.assertEqual(self.status.model_version(), '2.0-beta18') |
192 | |
193 | - def test_status(self): |
194 | + @mock.patch('subprocess.check_output') |
195 | + def test_status(self, mock_check_output): |
196 | """Test the status function""" |
197 | self.assertEqual(self.status.status(), self.status._raw_status) |
198 | |
199 | with mock.patch('subprocess.check_output') as mock_check_output: |
200 | # First check with no environment set |
201 | - no_env_status = mojo.juju.status.Juju2Status(command_timeout=None) |
202 | - no_env_status.status() |
203 | + with mock.patch('mojo.juju.status.major_version', new=2): |
204 | + no_env_status = mojo.juju.status.Juju2Status(command_timeout=None) |
205 | + no_env_status.status() |
206 | mock_check_output.assert_called_with( |
207 | ['juju', 'status', '--format=yaml']) |
208 | # Second test with an environment set |
209 | - env_status = mojo.juju.status.Juju2Status(environment="test-env") |
210 | - env_status.status() |
211 | + with mock.patch('mojo.juju.status.major_version', new=2): |
212 | + env_status = mojo.juju.status.Juju2Status(environment="test-env") |
213 | + env_status.status() |
214 | mock_check_output.assert_called_with( |
215 | ['/usr/bin/timeout', '--kill-after', '5', '600', |
216 | 'juju', 'status', '--format=yaml', '-m', 'test-env']) |
217 | @@ -240,7 +243,12 @@ |
218 | 'since': '16 Sep 2016 15:23:55Z'}, |
219 | 'relations': {'juju-info': ['apache2', 'prometheus']}, |
220 | 'subordinate-to': ['apache2', 'prometheus']}}} |
221 | - self.assertEqual(self.status.yaml_status(force_update=True), expected) |
222 | + with mock.patch('subprocess.check_output') as mock_check_output: |
223 | + mock_check_output.return_value = self._testdata_from_file('juju2-idle.yaml') |
224 | + self.assertEqual(self.status.yaml_status(force_update=True), expected) |
225 | + # mock_check_output.assert_called_with( |
226 | + # ['/usr/bin/timeout', '--kill-after', '5', '600', |
227 | + # 'juju', 'status', '--format=yaml']) |
228 | |
229 | |
230 | class Juju2CheckOutputWithTimeoutTestException(Exception): |
231 | @@ -305,7 +313,7 @@ |
232 | timeout_exception=Juju2CheckOutputWithTimeoutTestException) |
233 | |
234 | self.assertTrue( |
235 | - arcm.exception.message.endswith(' timed out after 5 seconds')) |
236 | + str(arcm.exception).endswith(' timed out after 5 seconds')) |
237 | |
238 | @mock.patch('subprocess.check_output') |
239 | def test_command_times_out_and_is_killed(self, check_output_mock): |
240 | @@ -323,7 +331,7 @@ |
241 | timeout_exception=Juju2CheckOutputWithTimeoutTestException) |
242 | |
243 | self.assertTrue( |
244 | - arcm.exception.message.endswith(' timed out after 5 seconds (killed)')) |
245 | + str(arcm.exception).endswith(' timed out after 5 seconds (killed)')) |
246 | |
247 | |
248 | class Juju2ChecksTest(TestCase): |
249 | @@ -386,7 +394,9 @@ |
250 | sys.argv = ['self', '-f', self.status_path, 'get_ips', 'all'] |
251 | rc = parse_status() |
252 | self.assertEqual(rc, 0) |
253 | - self.assertEqual(mock_stdout.getvalue(), '10.25.2.111\n10.242.242.242\n10.25.2.109\n10.25.2.112\n10.25.2.110\n') |
254 | + ips = mock_stdout.getvalue().split("\n") |
255 | + ips.sort() |
256 | + self.assertEqual("{}\n".format("\n".join(ips).lstrip()), '10.242.242.242\n10.25.2.109\n10.25.2.110\n10.25.2.111\n10.25.2.112\n') |
257 | |
258 | @mock.patch('sys.stdout', new_callable=StringIO) |
259 | def test_GetIPs_app(self, mock_stdout): |
260 | |
261 | === modified file 'mojo/utils.py' |
262 | --- mojo/utils.py 2017-12-22 10:31:56 +0000 |
263 | +++ mojo/utils.py 2018-01-25 14:10:22 +0000 |
264 | @@ -13,6 +13,7 @@ |
265 | import time |
266 | |
267 | from hashlib import sha1 |
268 | +import six |
269 | from .exceptions import Unprivileged |
270 | |
271 | |
272 | @@ -262,6 +263,8 @@ |
273 | eof = True |
274 | for stream in to_read: |
275 | line = stream.read(read_bytes) |
276 | + if six.PY3: |
277 | + line = line.decode('utf-8') |
278 | if line != "": |
279 | eof = False |
280 | output += line |
281 | |
282 | === modified file 'setup.py' |
283 | --- setup.py 2017-05-10 03:58:59 +0000 |
284 | +++ setup.py 2018-01-25 14:10:22 +0000 |
285 | @@ -21,6 +21,7 @@ |
286 | "jujuclient >= 0.0.7", |
287 | "juju-deployer >= 0.6.4", |
288 | "pylxd < 2.1.0", |
289 | + "six >= 1.11.0", |
290 | "python-cinderclient >= 1.0.0"], |
291 | packages=find_packages(), |
292 | classifiers=[ |
293 | |
294 | === modified file 'tox.ini' |
295 | --- tox.ini 2018-01-18 10:23:15 +0000 |
296 | +++ tox.ini 2018-01-25 14:10:22 +0000 |
297 | @@ -1,6 +1,6 @@ |
298 | # mojo_exec: build a py3 virtualenv and execute a basic mojo command to confirm py3-only functionality. |
299 | [tox] |
300 | -envlist = mojo_exec |
301 | +envlist = mojo2_exec,mojo3_exec,py27,py36 |
302 | skipsdist = True |
303 | |
304 | [testenv] |
305 | @@ -10,8 +10,26 @@ |
306 | install_command = |
307 | pip install --allow-unverified python-apt {opts} {packages} |
308 | |
309 | -[testenv:mojo_exec] |
310 | -basepython = python3 |
311 | -deps = -r{toxinidir}/requirements.txt |
312 | -commands = pip install --upgrade . |
313 | - mojo --version |
314 | +[testenv:mojo3_exec] |
315 | +basepython = python3 |
316 | +deps = -r{toxinidir}/requirements.txt |
317 | +commands = pip install --upgrade . |
318 | + mojo --version |
319 | + |
320 | +[testenv:mojo2_exec] |
321 | +basepython = python2 |
322 | +deps = -r{toxinidir}/requirements.txt |
323 | +commands = pip install --upgrade . |
324 | + mojo --version |
325 | + |
326 | +[testenv:py3] |
327 | +basepython = python3 |
328 | +deps = -r{toxinidir}/requirements.txt |
329 | + -r{toxinidir}/test-requirements.txt |
330 | +commands = nosetests {posargs} {toxinidir}/mojo/tests |
331 | + |
332 | +[testenv:py27] |
333 | +basepython = python2.7 |
334 | +deps = -r{toxinidir}/requirements.txt |
335 | + -r{toxinidir}/test-requirements.txt |
336 | +commands = nosetests {posargs} {toxinidir}/mojo/tests |
337 | \ No newline at end of file |
Have confirmed with a basic mojo run that this works on py2 still, commencing a test on py3