Merge ~pappacena/turnip:py3-strings-compat into turnip:master
- Git
- lp:~pappacena/turnip
- py3-strings-compat
- Merge into master
Proposed by
Thiago F. Pappacena
Status: | Merged |
---|---|
Approved by: | Thiago F. Pappacena |
Approved revision: | 75d004fdfe0011fc49dca6ffbb8505af1de9a1ad |
Merge reported by: | Otto Co-Pilot |
Merged at revision: | not available |
Proposed branch: | ~pappacena/turnip:py3-strings-compat |
Merge into: | turnip:master |
Diff against target: |
259 lines (+80/-29) 5 files modified
turnip/api/store.py (+11/-9) turnip/api/tests/test_api.py (+10/-13) turnip/api/tests/test_helpers.py (+30/-7) turnip/tests/__init__.py (+13/-0) turnip/tests/logging.py (+16/-0) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Colin Watson (community) | Approve | ||
Review via email: mp+380451@code.launchpad.net |
Commit message
Making some strings compatible both with python2 and python3
Description of the change
This MP should only be merged once we have the new dependencies in place.
It reduces the total amount of failing tests on python3:
From (failures=10, errors=28) to (failures=6, errors=21)
To post a comment you must log in.
Revision history for this message
Thiago F. Pappacena (pappacena) : | # |
Revision history for this message
Thiago F. Pappacena (pappacena) wrote : | # |
Pushed the required changes.
Revision history for this message
Colin Watson (cjwatson) : | # |
review:
Approve
Revision history for this message
Thiago F. Pappacena (pappacena) wrote : | # |
Thanks for the review, cjwatson. Pushed the changes. Landing this now.
Revision history for this message
Otto Co-Pilot (otto-copilot) wrote : | # |
Running landing tests failed
https:/
Revision history for this message
Otto Co-Pilot (otto-copilot) wrote : | # |
Running landing tests failed
https:/
Revision history for this message
Otto Co-Pilot (otto-copilot) wrote : | # |
Running landing tests failed
https:/
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/turnip/api/store.py b/turnip/api/store.py | |||
2 | index 11b4756..934dd71 100644 | |||
3 | --- a/turnip/api/store.py | |||
4 | +++ b/turnip/api/store.py | |||
5 | @@ -2,10 +2,6 @@ | |||
6 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
7 | 3 | 3 | ||
8 | 4 | import base64 | 4 | import base64 |
9 | 5 | from contextlib2 import ( | ||
10 | 6 | contextmanager, | ||
11 | 7 | ExitStack, | ||
12 | 8 | ) | ||
13 | 9 | import itertools | 5 | import itertools |
14 | 10 | import os | 6 | import os |
15 | 11 | import re | 7 | import re |
16 | @@ -13,14 +9,18 @@ import shutil | |||
17 | 13 | import subprocess | 9 | import subprocess |
18 | 14 | import uuid | 10 | import uuid |
19 | 15 | 11 | ||
20 | 12 | from contextlib2 import ( | ||
21 | 13 | contextmanager, | ||
22 | 14 | ExitStack, | ||
23 | 15 | ) | ||
24 | 16 | from pygit2 import ( | 16 | from pygit2 import ( |
25 | 17 | GitError, | ||
26 | 18 | GIT_OBJ_BLOB, | 17 | GIT_OBJ_BLOB, |
27 | 19 | GIT_OBJ_COMMIT, | 18 | GIT_OBJ_COMMIT, |
28 | 20 | GIT_OBJ_TREE, | ||
29 | 21 | GIT_OBJ_TAG, | 19 | GIT_OBJ_TAG, |
30 | 20 | GIT_OBJ_TREE, | ||
31 | 22 | GIT_REF_OID, | 21 | GIT_REF_OID, |
32 | 23 | GIT_SORT_TOPOLOGICAL, | 22 | GIT_SORT_TOPOLOGICAL, |
33 | 23 | GitError, | ||
34 | 24 | IndexEntry, | 24 | IndexEntry, |
35 | 25 | init_repository, | 25 | init_repository, |
36 | 26 | Oid, | 26 | Oid, |
37 | @@ -335,12 +335,14 @@ def get_refs(repo_store, repo_name, exclude_prefixes=None): | |||
38 | 335 | """Return all refs for a git repository.""" | 335 | """Return all refs for a git repository.""" |
39 | 336 | with open_repo(repo_store, repo_name) as repo: | 336 | with open_repo(repo_store, repo_name) as repo: |
40 | 337 | refs = {} | 337 | refs = {} |
43 | 338 | for ref in repo.listall_references(): | 338 | for ref_obj in repo.listall_reference_objects(): |
42 | 339 | git_object = repo.references[ref].peel() | ||
44 | 340 | # Filter non-unicode refs, as refs are treated as unicode | 339 | # Filter non-unicode refs, as refs are treated as unicode |
45 | 341 | # given json is unable to represent arbitrary byte strings. | 340 | # given json is unable to represent arbitrary byte strings. |
46 | 342 | try: | 341 | try: |
48 | 343 | ref = ref.decode('utf-8') | 342 | ref = ref_obj.name |
49 | 343 | if isinstance(ref, bytes): | ||
50 | 344 | ref = ref.decode('utf-8') | ||
51 | 345 | git_object = repo.references[ref].peel() | ||
52 | 344 | except UnicodeDecodeError: | 346 | except UnicodeDecodeError: |
53 | 345 | pass | 347 | pass |
54 | 346 | else: | 348 | else: |
55 | diff --git a/turnip/api/tests/test_api.py b/turnip/api/tests/test_api.py | |||
56 | index 2ff34d0..396369b 100644 | |||
57 | --- a/turnip/api/tests/test_api.py | |||
58 | +++ b/turnip/api/tests/test_api.py | |||
59 | @@ -10,16 +10,13 @@ import os | |||
60 | 10 | import subprocess | 10 | import subprocess |
61 | 11 | from textwrap import dedent | 11 | from textwrap import dedent |
62 | 12 | import unittest | 12 | import unittest |
63 | 13 | try: | ||
64 | 14 | from urllib.parse import quote | ||
65 | 15 | except ImportError: | ||
66 | 16 | from urllib import quote | ||
67 | 17 | import uuid | 13 | import uuid |
68 | 18 | 14 | ||
69 | 19 | from fixtures import ( | 15 | from fixtures import ( |
70 | 20 | EnvironmentVariable, | 16 | EnvironmentVariable, |
71 | 21 | TempDir, | 17 | TempDir, |
72 | 22 | ) | 18 | ) |
73 | 19 | from six.moves.urllib.parse import quote | ||
74 | 23 | from testtools import TestCase | 20 | from testtools import TestCase |
75 | 24 | from testtools.matchers import ( | 21 | from testtools.matchers import ( |
76 | 25 | Equals, | 22 | Equals, |
77 | @@ -217,7 +214,7 @@ class ApiTestCase(TestCase): | |||
78 | 217 | """Ensure non-unicode refs are dropped from ref collection.""" | 214 | """Ensure non-unicode refs are dropped from ref collection.""" |
79 | 218 | factory = RepoFactory(self.repo_store) | 215 | factory = RepoFactory(self.repo_store) |
80 | 219 | commit_oid = factory.add_commit('foo', 'foobar.txt') | 216 | commit_oid = factory.add_commit('foo', 'foobar.txt') |
82 | 220 | tag = '\xe9\xe9\xe9' # latin-1 | 217 | tag = b'\xe9\xe9\xe9' # latin-1 |
83 | 221 | tag_message = 'tag message' | 218 | tag_message = 'tag message' |
84 | 222 | factory.add_tag(tag, tag_message, commit_oid) | 219 | factory.add_tag(tag, tag_message, commit_oid) |
85 | 223 | 220 | ||
86 | @@ -335,7 +332,7 @@ class ApiTestCase(TestCase): | |||
87 | 335 | def test_repo_diff_non_unicode_commits(self): | 332 | def test_repo_diff_non_unicode_commits(self): |
88 | 336 | """Ensure non utf-8 chars are handled but stripped from diff.""" | 333 | """Ensure non utf-8 chars are handled but stripped from diff.""" |
89 | 337 | factory = RepoFactory(self.repo_store) | 334 | factory = RepoFactory(self.repo_store) |
91 | 338 | message = 'not particularly sensible latin-1: \xe9\xe9\xe9.' | 335 | message = b'not particularly sensible latin-1: \xe9\xe9\xe9.' |
92 | 339 | oid = factory.add_commit(message, 'foo.py') | 336 | oid = factory.add_commit(message, 'foo.py') |
93 | 340 | oid2 = factory.add_commit('a sensible commit message', 'foo.py', [oid]) | 337 | oid2 = factory.add_commit('a sensible commit message', 'foo.py', [oid]) |
94 | 341 | 338 | ||
95 | @@ -406,7 +403,7 @@ class ApiTestCase(TestCase): | |||
96 | 406 | self.repo_path, quote('{}^'.format(c2)), c2) | 403 | self.repo_path, quote('{}^'.format(c2)), c2) |
97 | 407 | resp = self.app.get(path) | 404 | resp = self.app.get(path) |
98 | 408 | self.assertIn( | 405 | self.assertIn( |
100 | 409 | b'diff --git a/foo.txt b/bar.txt\n', resp.json_body['patch']) | 406 | 'diff --git a/foo.txt b/bar.txt\n', resp.json_body['patch']) |
101 | 410 | 407 | ||
102 | 411 | def test_repo_diff_rename_and_change_content_conflict(self): | 408 | def test_repo_diff_rename_and_change_content_conflict(self): |
103 | 412 | # Create repo1 with foo.txt. | 409 | # Create repo1 with foo.txt. |
104 | @@ -576,7 +573,7 @@ class ApiTestCase(TestCase): | |||
105 | 576 | resp = self.app.get('/repo/{}/compare-merge/{}:{}'.format( | 573 | resp = self.app.get('/repo/{}/compare-merge/{}:{}'.format( |
106 | 577 | self.repo_path, c1, c2)) | 574 | self.repo_path, c1, c2)) |
107 | 578 | self.assertIn( | 575 | self.assertIn( |
109 | 579 | b'diff --git a/foo.txt b/bar.txt\n', resp.json_body['patch']) | 576 | 'diff --git a/foo.txt b/bar.txt\n', resp.json_body['patch']) |
110 | 580 | 577 | ||
111 | 581 | def test_repo_get_commit(self): | 578 | def test_repo_get_commit(self): |
112 | 582 | factory = RepoFactory(self.repo_store) | 579 | factory = RepoFactory(self.repo_store) |
113 | @@ -671,7 +668,7 @@ class ApiTestCase(TestCase): | |||
114 | 671 | def test_repo_get_non_unicode_log(self): | 668 | def test_repo_get_non_unicode_log(self): |
115 | 672 | """Ensure that non-unicode data is discarded.""" | 669 | """Ensure that non-unicode data is discarded.""" |
116 | 673 | factory = RepoFactory(self.repo_store) | 670 | factory = RepoFactory(self.repo_store) |
118 | 674 | message = '\xe9\xe9\xe9' # latin-1 | 671 | message = b'\xe9\xe9\xe9' # latin-1 |
119 | 675 | oid = factory.add_commit(message, 'foo.py') | 672 | oid = factory.add_commit(message, 'foo.py') |
120 | 676 | resp = self.app.get('/repo/{}/log/{}'.format(self.repo_path, oid)) | 673 | resp = self.app.get('/repo/{}/log/{}'.format(self.repo_path, oid)) |
121 | 677 | self.assertEqual(message.decode('utf-8', 'replace'), | 674 | self.assertEqual(message.decode('utf-8', 'replace'), |
122 | @@ -809,15 +806,15 @@ class ApiTestCase(TestCase): | |||
123 | 809 | factory.add_commit('b\n', 'dir/file', parents=[c1]) | 806 | factory.add_commit('b\n', 'dir/file', parents=[c1]) |
124 | 810 | resp = self.app.get('/repo/{}/blob/dir/file'.format(self.repo_path)) | 807 | resp = self.app.get('/repo/{}/blob/dir/file'.format(self.repo_path)) |
125 | 811 | self.assertEqual(2, resp.json['size']) | 808 | self.assertEqual(2, resp.json['size']) |
127 | 812 | self.assertEqual('b\n', base64.b64decode(resp.json['data'])) | 809 | self.assertEqual(b'b\n', base64.b64decode(resp.json['data'])) |
128 | 813 | resp = self.app.get('/repo/{}/blob/dir/file?rev=master'.format( | 810 | resp = self.app.get('/repo/{}/blob/dir/file?rev=master'.format( |
129 | 814 | self.repo_path)) | 811 | self.repo_path)) |
130 | 815 | self.assertEqual(2, resp.json['size']) | 812 | self.assertEqual(2, resp.json['size']) |
132 | 816 | self.assertEqual('b\n', base64.b64decode(resp.json['data'])) | 813 | self.assertEqual(b'b\n', base64.b64decode(resp.json['data'])) |
133 | 817 | resp = self.app.get('/repo/{}/blob/dir/file?rev={}'.format( | 814 | resp = self.app.get('/repo/{}/blob/dir/file?rev={}'.format( |
134 | 818 | self.repo_path, c1.hex)) | 815 | self.repo_path, c1.hex)) |
135 | 819 | self.assertEqual(2, resp.json['size']) | 816 | self.assertEqual(2, resp.json['size']) |
137 | 820 | self.assertEqual('a\n', base64.b64decode(resp.json['data'])) | 817 | self.assertEqual(b'a\n', base64.b64decode(resp.json['data'])) |
138 | 821 | 818 | ||
139 | 822 | def test_repo_blob_missing_commit(self): | 819 | def test_repo_blob_missing_commit(self): |
140 | 823 | """Trying to get a blob from a non-existent commit returns HTTP 404.""" | 820 | """Trying to get a blob from a non-existent commit returns HTTP 404.""" |
141 | @@ -861,7 +858,7 @@ class ApiTestCase(TestCase): | |||
142 | 861 | resp = self.app.get('/repo/{}/blob/dir/file?rev=tag-name'.format( | 858 | resp = self.app.get('/repo/{}/blob/dir/file?rev=tag-name'.format( |
143 | 862 | self.repo_path)) | 859 | self.repo_path)) |
144 | 863 | self.assertEqual(2, resp.json['size']) | 860 | self.assertEqual(2, resp.json['size']) |
146 | 864 | self.assertEqual('a\n', base64.b64decode(resp.json['data'])) | 861 | self.assertEqual(b'a\n', base64.b64decode(resp.json['data'])) |
147 | 865 | 862 | ||
148 | 866 | def test_repo_blob_from_non_commit(self): | 863 | def test_repo_blob_from_non_commit(self): |
149 | 867 | """Trying to get a blob from a non-commit returns HTTP 404.""" | 864 | """Trying to get a blob from a non-commit returns HTTP 404.""" |
150 | diff --git a/turnip/api/tests/test_helpers.py b/turnip/api/tests/test_helpers.py | |||
151 | index dac6950..a6035b4 100644 | |||
152 | --- a/turnip/api/tests/test_helpers.py | |||
153 | +++ b/turnip/api/tests/test_helpers.py | |||
154 | @@ -4,20 +4,23 @@ | |||
155 | 4 | import contextlib | 4 | import contextlib |
156 | 5 | import fnmatch | 5 | import fnmatch |
157 | 6 | import itertools | 6 | import itertools |
158 | 7 | import logging | ||
159 | 7 | import os | 8 | import os |
160 | 9 | from subprocess import PIPE, Popen, CalledProcessError | ||
161 | 8 | import uuid | 10 | import uuid |
162 | 9 | 11 | ||
163 | 10 | from six.moves import urllib | ||
164 | 11 | |||
165 | 12 | from pygit2 import ( | 12 | from pygit2 import ( |
166 | 13 | clone_repository, | 13 | clone_repository, |
167 | 14 | init_repository, | ||
168 | 15 | GIT_FILEMODE_BLOB, | 14 | GIT_FILEMODE_BLOB, |
169 | 16 | GIT_OBJ_COMMIT, | ||
170 | 17 | IndexEntry, | 15 | IndexEntry, |
171 | 16 | init_repository, | ||
172 | 18 | Repository, | 17 | Repository, |
173 | 19 | Signature, | 18 | Signature, |
174 | 20 | ) | 19 | ) |
175 | 20 | import six | ||
176 | 21 | from six.moves import urllib | ||
177 | 22 | |||
178 | 23 | log = logging.getLogger() | ||
179 | 21 | 24 | ||
180 | 22 | 25 | ||
181 | 23 | def get_revlist(repo): | 26 | def get_revlist(repo): |
182 | @@ -94,14 +97,34 @@ class RepoFactory(object): | |||
183 | 94 | self.branches.append(branch) | 97 | self.branches.append(branch) |
184 | 95 | return branch | 98 | return branch |
185 | 96 | 99 | ||
186 | 100 | def _get_cmd_line_auth_params(self): | ||
187 | 101 | return [ | ||
188 | 102 | '-c', 'user.name={}'.format(self.author.name), | ||
189 | 103 | '-c', 'user.email={}'.format(self.author.email), | ||
190 | 104 | '-c', 'author.name={}'.format(self.author.name), | ||
191 | 105 | '-c', 'author.email={}'.format(self.author.email), | ||
192 | 106 | '-c', 'committer.name={}'.format(self.committer.name), | ||
193 | 107 | '-c', 'committer.email={}'.format(self.committer.email), | ||
194 | 108 | ] | ||
195 | 109 | |||
196 | 97 | def add_tag(self, tag_name, tag_message, oid): | 110 | def add_tag(self, tag_name, tag_message, oid): |
197 | 98 | """Create a tag from tag_name and oid.""" | 111 | """Create a tag from tag_name and oid.""" |
201 | 99 | repo = self.repo | 112 | cmd_line = ['git', '-C', self.repo_path] |
202 | 100 | repo.create_tag(tag_name, oid, GIT_OBJ_COMMIT, | 113 | cmd_line += self._get_cmd_line_auth_params() |
203 | 101 | self.committer, tag_message) | 114 | cmd_line += ['tag', '-m', tag_message, tag_name, oid.hex] |
204 | 115 | subproc = Popen(cmd_line, stderr=PIPE, stdout=PIPE) | ||
205 | 116 | retcode = subproc.wait() | ||
206 | 117 | if retcode: | ||
207 | 118 | log.error( | ||
208 | 119 | "Command %s finished with error code %s. stdout/stderr:\n%s", | ||
209 | 120 | cmd_line, retcode, subproc.stderr.read()) | ||
210 | 121 | raise CalledProcessError(retcode, cmd_line) | ||
211 | 102 | 122 | ||
212 | 103 | def makeSignature(self, name, email, encoding='utf-8'): | 123 | def makeSignature(self, name, email, encoding='utf-8'): |
213 | 104 | """Return an author or committer signature.""" | 124 | """Return an author or committer signature.""" |
214 | 125 | # email should always be str on python3, but pygit2 | ||
215 | 126 | # doesn't enforce the same for name. | ||
216 | 127 | email = six.ensure_str(email) | ||
217 | 105 | return Signature(name, email, encoding=encoding) | 128 | return Signature(name, email, encoding=encoding) |
218 | 106 | 129 | ||
219 | 107 | def stage(self, path, content): | 130 | def stage(self, path, content): |
220 | diff --git a/turnip/tests/__init__.py b/turnip/tests/__init__.py | |||
221 | index e69de29..494f3fd 100644 | |||
222 | --- a/turnip/tests/__init__.py | |||
223 | +++ b/turnip/tests/__init__.py | |||
224 | @@ -0,0 +1,13 @@ | |||
225 | 1 | # Copyright 2020 Canonical Ltd. This software is licensed under the | ||
226 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | ||
227 | 3 | |||
228 | 4 | from __future__ import ( | ||
229 | 5 | absolute_import, | ||
230 | 6 | print_function, | ||
231 | 7 | unicode_literals, | ||
232 | 8 | ) | ||
233 | 9 | |||
234 | 10 | from turnip.tests.logging import setupLogger | ||
235 | 11 | |||
236 | 12 | |||
237 | 13 | setupLogger() | ||
238 | diff --git a/turnip/tests/logging.py b/turnip/tests/logging.py | |||
239 | 0 | new file mode 100644 | 14 | new file mode 100644 |
240 | index 0000000..28b6ef3 | |||
241 | --- /dev/null | |||
242 | +++ b/turnip/tests/logging.py | |||
243 | @@ -0,0 +1,16 @@ | |||
244 | 1 | # Copyright 2020 Canonical Ltd. This software is licensed under the | ||
245 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | ||
246 | 3 | |||
247 | 4 | from __future__ import ( | ||
248 | 5 | absolute_import, | ||
249 | 6 | print_function, | ||
250 | 7 | unicode_literals, | ||
251 | 8 | ) | ||
252 | 9 | |||
253 | 10 | import sys | ||
254 | 11 | import logging | ||
255 | 12 | |||
256 | 13 | |||
257 | 14 | def setupLogger(): | ||
258 | 15 | """Setup our basic logging for tests.""" | ||
259 | 16 | logging.basicConfig(stream=sys.stdout, level=logging.INFO) |
I'd particularly like to see my comments about get_refs disentangled, but should be fine after that.