Merge lp:~xnox/ubuntu-dev-tools/py3k into lp:~ubuntu-dev/ubuntu-dev-tools/trunk
- py3k
- Merge into trunk
Proposed by
Dimitri John Ledkov
Status: | Merged | ||||
---|---|---|---|---|---|
Merged at revision: | 1422 | ||||
Proposed branch: | lp:~xnox/ubuntu-dev-tools/py3k | ||||
Merge into: | lp:~ubuntu-dev/ubuntu-dev-tools/trunk | ||||
Diff against target: |
1965 lines (+467/-335) 25 files modified
debian/changelog (+3/-0) debian/control (+32/-2) debian/rules (+9/-8) setup.py (+13/-7) ubuntutools/archive.py (+40/-27) ubuntutools/config.py (+1/-1) ubuntutools/harvest.py (+10/-7) ubuntutools/lp/libsupport.py (+9/-6) ubuntutools/lp/lpapicache.py (+37/-14) ubuntutools/misc.py (+10/-8) ubuntutools/question.py (+24/-19) ubuntutools/requestsync/lp.py (+16/-14) ubuntutools/requestsync/mail.py (+15/-9) ubuntutools/sponsor_patch/bugtask.py (+7/-3) ubuntutools/sponsor_patch/patch.py (+1/-0) ubuntutools/sponsor_patch/question.py (+3/-1) ubuntutools/sponsor_patch/source_package.py (+11/-9) ubuntutools/sponsor_patch/sponsor_patch.py (+14/-9) ubuntutools/test/test_archive.py (+109/-134) ubuntutools/test/test_config.py (+34/-13) ubuntutools/test/test_help.py (+5/-1) ubuntutools/test/test_logger.py (+6/-3) ubuntutools/test/test_pylint.py (+0/-3) ubuntutools/test/test_update_maintainer.py (+47/-28) ubuntutools/update_maintainer.py (+11/-9) |
||||
To merge this branch: | bzr merge lp:~xnox/ubuntu-dev-tools/py3k | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Barry Warsaw | Pending | ||
Ubuntu Development Team | Pending | ||
Review via email: mp+245250@code.launchpad.net |
Commit message
Description of the change
Port ubuntutools module & test suite to python3.
To post a comment you must log in.
lp:~xnox/ubuntu-dev-tools/py3k
updated
- 1423. By Dimitri John Ledkov
-
There is no python3-soappy yet.
- 1424. By Dimitri John Ledkov
-
Mock mock more.
Revision history for this message
Dimitri John Ledkov (xnox) wrote : | # |
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'debian/changelog' |
2 | --- debian/changelog 2014-07-25 07:50:59 +0000 |
3 | +++ debian/changelog 2014-12-19 22:54:27 +0000 |
4 | @@ -7,6 +7,9 @@ |
5 | * mk-sbuild: better message for cross build so that new start have |
6 | correct sbuild command from the last message of mk-sbuild. |
7 | |
8 | + [ Dimitri John Ledkov ] |
9 | + * Port ubuntutools module to python3. |
10 | + |
11 | -- Logan Rosen <logan@ubuntu.com> Wed, 23 Apr 2014 17:24:12 -0400 |
12 | |
13 | ubuntu-dev-tools (0.153) unstable; urgency=medium |
14 | |
15 | === modified file 'debian/control' |
16 | --- debian/control 2014-01-06 21:48:08 +0000 |
17 | +++ debian/control 2014-12-19 22:54:27 +0000 |
18 | @@ -8,6 +8,7 @@ |
19 | Vcs-Browser: https://code.launchpad.net/~ubuntu-dev/ubuntu-dev-tools/trunk |
20 | Build-Depends: dctrl-tools, |
21 | debhelper (>= 9), |
22 | + dh-python, |
23 | devscripts (>= 2.11.0~), |
24 | distro-info (>= 0.2~), |
25 | libwww-perl, |
26 | @@ -19,11 +20,20 @@ |
27 | python-distro-info (>= 0.4~), |
28 | python-httplib2, |
29 | python-launchpadlib (>= 1.5.7), |
30 | - python-mox, |
31 | python-setuptools, |
32 | python-soappy, |
33 | - python-unittest2 |
34 | + python-unittest2, |
35 | + python-mock, |
36 | + python3-all, |
37 | + python3-apt, |
38 | + python3-debian, |
39 | + python3-distro-info, |
40 | + python3-httplib2, |
41 | + python3-launchpadlib, |
42 | + python3-setuptools, |
43 | + python3-mock, |
44 | X-Python-Version: >= 2.6 |
45 | +X-Python3-Version: >= 3.2 |
46 | Homepage: https://launchpad.net/ubuntu-dev-tools |
47 | Standards-Version: 3.9.5 |
48 | |
49 | @@ -114,3 +124,23 @@ |
50 | - ubuntu-upload-permission - query / list the upload permissions for a |
51 | package. |
52 | - update-maintainer - script to update maintainer field in ubuntu packages. |
53 | + |
54 | +Package: python-ubuntutools |
55 | +Architecture: all |
56 | +Depends: ${python:Depends} |
57 | +Breaks: ubuntu-dev-tools (<< 0.154) |
58 | +Replaces: ubuntu-dev-tools (<< 0.154) |
59 | +Description: useful library of APIs for Ubuntu developer tools (Python 2) |
60 | + This package ships a collection of APIs, helpers and wrappers used to |
61 | + develop useful utiliteis for Ubuntu developers. |
62 | + . |
63 | + Python 2 variant. |
64 | + |
65 | +Package: python3-ubuntutools |
66 | +Architecture: all |
67 | +Depends: ${python3:Depends} |
68 | +Description: useful library of APIs for Ubuntu developer tools |
69 | + This package ships a collection of APIs, helpers and wrappers used to |
70 | + develop useful utiliteis for Ubuntu developers. |
71 | + . |
72 | + Python 3 variant. |
73 | |
74 | === modified file 'debian/rules' |
75 | --- debian/rules 2011-06-25 15:53:44 +0000 |
76 | +++ debian/rules 2014-12-19 22:54:27 +0000 |
77 | @@ -1,12 +1,13 @@ |
78 | #!/usr/bin/make -f |
79 | |
80 | +export PYBUILD_NAME=ubuntutools |
81 | + |
82 | %: |
83 | - dh $@ --with python2 |
84 | + dh $@ --with python2,python3 --buildsystem=pybuild |
85 | |
86 | -ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS))) |
87 | -override_dh_auto_test: |
88 | - set -e; \ |
89 | - for python in $(shell pyversions -r); do \ |
90 | - $$python setup.py test; \ |
91 | - done |
92 | -endif |
93 | +override_dh_install: |
94 | + dh_install |
95 | + mkdir -p debian/ubuntu-dev-tools/usr |
96 | + mv debian/python-ubuntutools/etc debian/ubuntu-dev-tools |
97 | + mv debian/python-ubuntutools/usr/bin debian/ubuntu-dev-tools/usr/ |
98 | + mv debian/python-ubuntutools/usr/share debian/ubuntu-dev-tools/usr/ |
99 | |
100 | === modified file 'setup.py' |
101 | --- setup.py 2012-11-09 11:02:01 +0000 |
102 | +++ setup.py 2014-12-19 22:54:27 +0000 |
103 | @@ -4,6 +4,7 @@ |
104 | import glob |
105 | import os |
106 | import re |
107 | +import sys |
108 | |
109 | # look/set what version we have |
110 | changelog = "debian/changelog" |
111 | @@ -13,7 +14,11 @@ |
112 | if match: |
113 | version = match.group(1) |
114 | |
115 | -scripts = ['404main', |
116 | +if sys.version_info[0] >= 3: |
117 | + scripts = [] |
118 | + data_files = [] |
119 | +else: |
120 | + scripts = ['404main', |
121 | 'backportpackage', |
122 | 'bitesize', |
123 | 'check-mir', |
124 | @@ -46,6 +51,12 @@ |
125 | 'ubuntu-upload-permission', |
126 | 'update-maintainer', |
127 | ] |
128 | + data_files = [ |
129 | + ('/etc/bash_completion.d', glob.glob("bash_completion/*")), |
130 | + ('share/man/man1', glob.glob("doc/*.1")), |
131 | + ('share/man/man5', glob.glob("doc/*.5")), |
132 | + ('share/ubuntu-dev-tools', ['enforced-editing-wrapper']), |
133 | + ] |
134 | |
135 | if __name__ == '__main__': |
136 | setup(name='ubuntu-dev-tools', |
137 | @@ -57,11 +68,6 @@ |
138 | 'ubuntutools/sponsor_patch', |
139 | 'ubuntutools/test', |
140 | ], |
141 | - data_files=[('/etc/bash_completion.d', |
142 | - glob.glob("bash_completion/*")), |
143 | - ('share/man/man1', glob.glob("doc/*.1")), |
144 | - ('share/man/man5', glob.glob("doc/*.5")), |
145 | - ('share/ubuntu-dev-tools', ['enforced-editing-wrapper']), |
146 | - ], |
147 | + data_files=data_files, |
148 | test_suite='ubuntutools.test.discover', |
149 | ) |
150 | |
151 | === modified file 'ubuntutools/archive.py' |
152 | --- ubuntutools/archive.py 2013-03-18 23:18:02 +0000 |
153 | +++ ubuntutools/archive.py 2014-12-19 22:54:27 +0000 |
154 | @@ -27,18 +27,28 @@ |
155 | 3. Verify checksums. |
156 | """ |
157 | |
158 | -from __future__ import with_statement |
159 | +from __future__ import with_statement, print_function |
160 | |
161 | import hashlib |
162 | import os.path |
163 | -import urllib2 |
164 | -import urlparse |
165 | +try: |
166 | + from urllib.request import ProxyHandler, build_opener, urlopen |
167 | + from urllib.parse import urlparse |
168 | + from urllib.error import URLError, HTTPError |
169 | +except ImportError: |
170 | + from urllib2 import ProxyHandler, build_opener, urlopen |
171 | + from urlparse import urlparse |
172 | + from urllib2 import URLError, HTTPError |
173 | import re |
174 | import sys |
175 | +if sys.version_info[0] >= 3: |
176 | + basestring = str |
177 | + unicode = str |
178 | |
179 | from debian.changelog import Changelog, Version |
180 | import debian.deb822 |
181 | import debian.debian_support |
182 | +import codecs |
183 | import httplib2 |
184 | |
185 | from ubuntutools.config import UDTConfig |
186 | @@ -81,7 +91,7 @@ |
187 | f = open(pathname, 'rb') |
188 | while True: |
189 | buf = f.read(hash_func.block_size) |
190 | - if buf == '': |
191 | + if buf == b'': |
192 | break |
193 | hash_func.update(buf) |
194 | f.close() |
195 | @@ -102,7 +112,7 @@ |
196 | their_checksums = \ |
197 | dict((entry['name'], (int(entry['size']), entry[key])) |
198 | for entry in other[field]) |
199 | - for name, (size, checksum) in our_checksums.iteritems(): |
200 | + for name, (size, checksum) in our_checksums.items(): |
201 | if name not in their_checksums: |
202 | # file only in one dsc |
203 | continue |
204 | @@ -154,8 +164,8 @@ |
205 | self.version = debian.debian_support.Version(version) |
206 | |
207 | # uses default proxies from the environment |
208 | - proxy = urllib2.ProxyHandler() |
209 | - self.url_opener = urllib2.build_opener(proxy) |
210 | + proxy = ProxyHandler() |
211 | + self.url_opener = build_opener(proxy) |
212 | |
213 | @property |
214 | def lp_spph(self): |
215 | @@ -231,10 +241,10 @@ |
216 | def pull_dsc(self): |
217 | "Retrieve dscfile and parse" |
218 | if self._dsc_source: |
219 | - parsed = urlparse.urlparse(self._dsc_source) |
220 | + parsed = urlparse(self._dsc_source) |
221 | if parsed.scheme == '': |
222 | self._dsc_source = 'file://' + os.path.abspath(self._dsc_source) |
223 | - parsed = urlparse.urlparse(self._dsc_source) |
224 | + parsed = urlparse(self._dsc_source) |
225 | url = self._dsc_source |
226 | else: |
227 | url = self._lp_url(self.dsc_name) |
228 | @@ -244,14 +254,14 @@ |
229 | |
230 | def _download_dsc(self, url): |
231 | "Download specified dscfile and parse" |
232 | - parsed = urlparse.urlparse(url) |
233 | + parsed = urlparse(url) |
234 | if parsed.scheme == 'file': |
235 | with open(parsed.path, 'r') as f: |
236 | body = f.read() |
237 | else: |
238 | try: |
239 | response, body = httplib2.Http().request(url) |
240 | - except httplib2.HttpLib2Error, e: |
241 | + except httplib2.HttpLib2Error as e: |
242 | raise DownloadError(e) |
243 | if response.status != 200: |
244 | raise DownloadError("%s: %s %s" % (url, response.status, |
245 | @@ -299,7 +309,7 @@ |
246 | "Write dsc file to workdir" |
247 | if self._dsc is None: |
248 | self.pull_dsc() |
249 | - with open(self.dsc_pathname, 'w') as f: |
250 | + with open(self.dsc_pathname, 'wb') as f: |
251 | f.write(self.dsc.raw_text) |
252 | |
253 | def _download_file(self, url, filename): |
254 | @@ -312,17 +322,17 @@ |
255 | if entry['name'] == filename] |
256 | assert len(size) == 1 |
257 | size = int(size[0]) |
258 | - parsed = urlparse.urlparse(url) |
259 | + parsed = urlparse(url) |
260 | if not self.quiet: |
261 | Logger.normal('Downloading %s from %s (%0.3f MiB)', |
262 | filename, parsed.hostname, size / 1024.0 / 1024) |
263 | |
264 | if parsed.scheme == 'file': |
265 | - in_ = open(parsed.path, 'r') |
266 | + in_ = open(parsed.path, 'rb') |
267 | else: |
268 | try: |
269 | in_ = self.url_opener.open(url) |
270 | - except urllib2.URLError: |
271 | + except URLError: |
272 | return False |
273 | |
274 | downloaded = 0 |
275 | @@ -331,10 +341,10 @@ |
276 | with open(pathname, 'wb') as out: |
277 | while True: |
278 | block = in_.read(10240) |
279 | - if block == '': |
280 | + if block == b'': |
281 | break |
282 | downloaded += len(block) |
283 | - out.write(block) |
284 | + out.write(block) |
285 | if not self.quiet: |
286 | percent = downloaded * 100 // size |
287 | bar = '=' * int(round(downloaded * bar_width / size)) |
288 | @@ -360,9 +370,9 @@ |
289 | try: |
290 | if self._download_file(url, name): |
291 | break |
292 | - except urllib2.HTTPError, e: |
293 | + except HTTPError as e: |
294 | Logger.normal('HTTP Error %i: %s', e.code, str(e)) |
295 | - except urllib2.URLError, e: |
296 | + except URLError as e: |
297 | Logger.normal('URL Error: %s', e.reason) |
298 | else: |
299 | raise DownloadError('File %s could not be found' % name) |
300 | @@ -457,7 +467,7 @@ |
301 | wrapped_iterator = super(DebianSourcePackage, self)._source_urls(name) |
302 | while True: |
303 | try: |
304 | - yield wrapped_iterator.next() |
305 | + yield next(wrapped_iterator) |
306 | except StopIteration: |
307 | break |
308 | if self.snapshot_list: |
309 | @@ -499,11 +509,14 @@ |
310 | "python-simplejson") |
311 | |
312 | try: |
313 | - srcfiles = json.load(self.url_opener.open( |
314 | + data = self.url_opener.open( |
315 | 'http://snapshot.debian.org' |
316 | '/mr/package/%s/%s/srcfiles?fileinfo=1' |
317 | - % (self.source, self.version.full_version))) |
318 | - except urllib2.HTTPError: |
319 | + % (self.source, self.version.full_version)) |
320 | + reader = codecs.getreader('utf-8') |
321 | + srcfiles = json.load(reader(data)) |
322 | + |
323 | + except HTTPError: |
324 | Logger.error('Version %s of %s not found on ' |
325 | 'snapshot.debian.org', |
326 | self.version.full_version, self.source) |
327 | @@ -511,7 +524,7 @@ |
328 | return False |
329 | self._snapshot_list = dict((info[0]['name'], hash_) |
330 | for hash_, info |
331 | - in srcfiles['fileinfo'].iteritems()) |
332 | + in srcfiles['fileinfo'].items()) |
333 | return self._snapshot_list |
334 | |
335 | def _snapshot_url(self, name): |
336 | @@ -569,9 +582,9 @@ |
337 | self.name + '_' + pkgversion, |
338 | 'changelog' + extension) |
339 | try: |
340 | - self._changelog = urllib2.urlopen(url).read() |
341 | - except urllib2.HTTPError, error: |
342 | - print >> sys.stderr, ('%s: %s' % (url, error)) |
343 | + self._changelog = urlopen(url).read() |
344 | + except HTTPError as error: |
345 | + print(('%s: %s' % (url, error)), file=sys.stderr) |
346 | return None |
347 | |
348 | if since_version is None: |
349 | |
350 | === modified file 'ubuntutools/config.py' |
351 | --- ubuntutools/config.py 2013-08-13 21:01:32 +0000 |
352 | +++ ubuntutools/config.py 2014-12-19 22:54:27 +0000 |
353 | @@ -179,6 +179,6 @@ |
354 | encoding = locale.getdefaultlocale()[1] |
355 | if not encoding: |
356 | encoding = 'utf-8' |
357 | - if name: |
358 | + if name and isinstance(name, bytes): |
359 | name = name.decode(encoding) |
360 | return name, email |
361 | |
362 | === modified file 'ubuntutools/harvest.py' |
363 | --- ubuntutools/harvest.py 2013-03-18 23:18:02 +0000 |
364 | +++ ubuntutools/harvest.py 2014-12-19 22:54:27 +0000 |
365 | @@ -14,7 +14,12 @@ |
366 | import json |
367 | import os.path |
368 | import sys |
369 | -import urllib2 |
370 | +try: |
371 | + from urllib.request import urlopen |
372 | + from urllib.error import URLError |
373 | +except ImportError: |
374 | + from urllib2 import urlopen |
375 | + from urllib2 import URLError |
376 | |
377 | from ubuntutools.logger import Logger |
378 | |
379 | @@ -32,11 +37,11 @@ |
380 | |
381 | def _get_data(self): |
382 | try: |
383 | - sock = urllib2.urlopen(self.data_url) |
384 | + sock = urlopen(self.data_url) |
385 | except IOError: |
386 | try: |
387 | - urllib2.urlopen(BASE_URL) |
388 | - except urllib2.URLError: |
389 | + urlopen(BASE_URL) |
390 | + except URLError: |
391 | Logger.error("Harvest is down.") |
392 | sys.exit(1) |
393 | return None |
394 | @@ -45,9 +50,7 @@ |
395 | return json.loads(response) |
396 | |
397 | def opportunity_summary(self): |
398 | - l = [] |
399 | - for key in filter(lambda a: a != "total", self.data.keys()): |
400 | - l += ["%s (%s)" % (key, self.data[key])] |
401 | + l = ["%s (%s)" % (k,v) for (k,v) in self.data.items() if k != "total"] |
402 | return ", ".join(l) |
403 | |
404 | def report(self): |
405 | |
406 | === modified file 'ubuntutools/lp/libsupport.py' |
407 | --- ubuntutools/lp/libsupport.py 2011-02-28 22:32:36 +0000 |
408 | +++ ubuntutools/lp/libsupport.py 2014-12-19 22:54:27 +0000 |
409 | @@ -19,8 +19,11 @@ |
410 | # |
411 | |
412 | # Modules. |
413 | -import urllib |
414 | -import urlparse |
415 | +try: |
416 | + from urllib.parse import urlsplit, urlencode, urlunsplit |
417 | +except ImportError: |
418 | + from urllib import urlencode |
419 | + from urlparse import urlsplit, urlunsplit |
420 | |
421 | def query_to_dict(query_string): |
422 | result = dict() |
423 | @@ -31,7 +34,7 @@ |
424 | return result |
425 | |
426 | def translate_web_api(url, launchpad): |
427 | - scheme, netloc, path, query, fragment = urlparse.urlsplit(url) |
428 | + scheme, netloc, path, query, fragment = urlsplit(url) |
429 | query = query_to_dict(query) |
430 | |
431 | differences = set(netloc.split('.')).symmetric_difference( |
432 | @@ -44,8 +47,8 @@ |
433 | if "ws.op" in query: |
434 | raise ValueError("Invalid web url, url: %s" %url) |
435 | query["ws.op"] = "searchTasks" |
436 | - scheme, netloc, api_path, _, _ = urlparse.urlsplit(str(launchpad._root_uri)) |
437 | - query = urllib.urlencode(query) |
438 | - url = urlparse.urlunsplit((scheme, netloc, api_path + path.lstrip("/"), |
439 | + scheme, netloc, api_path, _, _ = urlsplit(str(launchpad._root_uri)) |
440 | + query = urlencode(query) |
441 | + url = urlunsplit((scheme, netloc, api_path + path.lstrip("/"), |
442 | query, fragment)) |
443 | return url |
444 | |
445 | === modified file 'ubuntutools/lp/lpapicache.py' |
446 | --- ubuntutools/lp/lpapicache.py 2012-07-26 19:40:49 +0000 |
447 | +++ ubuntutools/lp/lpapicache.py 2014-12-19 22:54:27 +0000 |
448 | @@ -21,12 +21,34 @@ |
449 | # |
450 | # Based on code written by Jonathan Davies <jpds@ubuntu.com> |
451 | |
452 | +from __future__ import print_function |
453 | + |
454 | # Uncomment for tracing LP API calls |
455 | #import httplib2 |
456 | #httplib2.debuglevel = 1 |
457 | |
458 | import sys |
459 | |
460 | +if sys.version_info[0] >= 3: |
461 | + basestring = str |
462 | + unicode = str |
463 | + |
464 | +#Shameless steal from python-six |
465 | +def add_metaclass(metaclass): |
466 | + """Class decorator for creating a class with a metaclass.""" |
467 | + def wrapper(cls): |
468 | + orig_vars = cls.__dict__.copy() |
469 | + slots = orig_vars.get('__slots__') |
470 | + if slots is not None: |
471 | + if isinstance(slots, str): |
472 | + slots = [slots] |
473 | + for slots_var in slots: |
474 | + orig_vars.pop(slots_var) |
475 | + orig_vars.pop('__dict__', None) |
476 | + orig_vars.pop('__weakref__', None) |
477 | + return metaclass(cls.__name__, cls.__bases__, orig_vars) |
478 | + return wrapper |
479 | + |
480 | from debian.changelog import Changelog, Version |
481 | from httplib2 import Http, HttpLib2Error |
482 | from launchpadlib.launchpad import Launchpad as LP |
483 | @@ -39,6 +61,7 @@ |
484 | PackageNotFoundException, |
485 | PocketDoesNotExistError, |
486 | SeriesNotFoundException) |
487 | +import collections |
488 | |
489 | __all__ = [ |
490 | 'Archive', |
491 | @@ -64,8 +87,8 @@ |
492 | try: |
493 | self.__lp = LP.login_with('ubuntu-dev-tools', service, |
494 | version=api_version) |
495 | - except IOError, error: |
496 | - print >> sys.stderr, 'E: %s' % error |
497 | + except IOError as error: |
498 | + print('E: %s' % error, file=sys.stderr) |
499 | raise |
500 | else: |
501 | raise AlreadyLoggedInError('Already logged in to Launchpad.') |
502 | @@ -112,11 +135,11 @@ |
503 | cls._cache = dict() |
504 | |
505 | |
506 | +@add_metaclass(MetaWrapper) |
507 | class BaseWrapper(object): |
508 | ''' |
509 | A base class from which other wrapper classes are derived. |
510 | ''' |
511 | - __metaclass__ = MetaWrapper |
512 | resource_type = None # it's a base class after all |
513 | |
514 | def __new__(cls, data): |
515 | @@ -149,7 +172,7 @@ |
516 | cls._cache[data.self_link] = cached |
517 | # add additional class specific caching (if available) |
518 | cache = getattr(cls, 'cache', None) |
519 | - if callable(cache): |
520 | + if isinstance(cache, collections.Callable): |
521 | cache(cached) |
522 | return cached |
523 | else: |
524 | @@ -158,7 +181,7 @@ |
525 | else: |
526 | # not a LP API representation, let the specific class handle it |
527 | fetch = getattr(cls, 'fetch', None) |
528 | - if callable(fetch): |
529 | + if isinstance(fetch, collections.Callable): |
530 | return fetch(data) |
531 | else: |
532 | raise NotImplementedError("Don't know how to fetch '%s' from LP" |
533 | @@ -502,19 +525,19 @@ |
534 | if self._changelog is None: |
535 | url = self._lpobject.changelogUrl() |
536 | if url is None: |
537 | - print >> sys.stderr, ('E: No changelog available for %s %s', |
538 | + print(('E: No changelog available for %s %s', |
539 | (self.getPackageName(), |
540 | - self.getVersion())) |
541 | + self.getVersion())), file=sys.stderr) |
542 | return None |
543 | |
544 | try: |
545 | response, changelog = Http().request(url) |
546 | - except HttpLib2Error, e: |
547 | - print >> sys.stderr, str(e) |
548 | + except HttpLib2Error as e: |
549 | + print(str(e), file=sys.stderr) |
550 | return None |
551 | if response.status != 200: |
552 | - print >> sys.stderr, ('%s: %s %s' % (url, response.status, |
553 | - response.reason)) |
554 | + print(('%s: %s %s' % (url, response.status, |
555 | + response.reason)), file=sys.stderr) |
556 | return None |
557 | self._changelog = changelog |
558 | |
559 | @@ -627,7 +650,7 @@ |
560 | if '_me' not in cls.__dict__: |
561 | try: |
562 | cls._me = PersonTeam(Launchpad.me) |
563 | - except HTTPError, error: |
564 | + except HTTPError as error: |
565 | if error.response.status == 401: |
566 | # Anonymous login |
567 | cls._me = None |
568 | @@ -636,11 +659,11 @@ |
569 | return cls._me |
570 | |
571 | |
572 | +@add_metaclass(MetaPersonTeam) |
573 | class PersonTeam(BaseWrapper): |
574 | ''' |
575 | Wrapper class around a LP person or team object. |
576 | ''' |
577 | - __metaclass__ = MetaPersonTeam |
578 | |
579 | resource_type = ( |
580 | 'person', |
581 | @@ -716,7 +739,7 @@ |
582 | sourcepackagename=package, |
583 | ) |
584 | canUpload = True |
585 | - except HTTPError, e: |
586 | + except HTTPError as e: |
587 | if e.response.status == 403: |
588 | canUpload = False |
589 | else: |
590 | |
591 | === modified file 'ubuntutools/misc.py' |
592 | --- ubuntutools/misc.py 2011-11-22 23:45:49 +0000 |
593 | +++ ubuntutools/misc.py 2014-12-19 22:54:27 +0000 |
594 | @@ -22,6 +22,8 @@ |
595 | # |
596 | # ################################################################## |
597 | |
598 | +from __future__ import print_function |
599 | + |
600 | # Modules. |
601 | import locale |
602 | import os |
603 | @@ -66,8 +68,8 @@ |
604 | break |
605 | _system_distribution_chain.append(parent) |
606 | except Exception: |
607 | - print ('Error: Could not determine the parent of the ' |
608 | - 'distribution %s' % _system_distribution_chain[-1]) |
609 | + print(('Error: Could not determine the parent of the ' |
610 | + 'distribution %s' % _system_distribution_chain[-1])) |
611 | return [] |
612 | |
613 | return _system_distribution_chain |
614 | @@ -92,8 +94,8 @@ |
615 | stderr=PIPE).communicate()[0].split() |
616 | |
617 | if not arch or 'not found' in arch[0]: |
618 | - print 'Error: Not running on a Debian based system; could not ' \ |
619 | - 'detect its architecture.' |
620 | + print('Error: Not running on a Debian based system; could not ' \ |
621 | + 'detect its architecture.') |
622 | return None |
623 | |
624 | return arch[0] |
625 | @@ -106,13 +108,13 @@ |
626 | """ |
627 | |
628 | if not os.path.isfile(filename): |
629 | - print 'File "%s" does not exist.' % filename |
630 | + print('File "%s" does not exist.' % filename) |
631 | return False |
632 | |
633 | content = open(filename).read().replace('\n', ' ').replace(',', ' ') |
634 | |
635 | if not content.strip(): |
636 | - print 'File "%s" is empty.' % filename |
637 | + print('File "%s" is empty.' % filename) |
638 | return False |
639 | |
640 | items = [item for item in content.split() if item] |
641 | @@ -149,8 +151,8 @@ |
642 | def require_utf8(): |
643 | '''Can be called by programs that only function in UTF-8 locales''' |
644 | if locale.getpreferredencoding() != 'UTF-8': |
645 | - print >> sys.stderr, ("This program only functions in a UTF-8 locale. " |
646 | - "Aborting.") |
647 | + print(("This program only functions in a UTF-8 locale. " |
648 | + "Aborting."), file=sys.stderr) |
649 | sys.exit(1) |
650 | |
651 | |
652 | |
653 | === modified file 'ubuntutools/question.py' |
654 | --- ubuntutools/question.py 2012-11-08 08:10:26 +0000 |
655 | +++ ubuntutools/question.py 2014-12-19 22:54:27 +0000 |
656 | @@ -16,10 +16,15 @@ |
657 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
658 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
659 | |
660 | +from __future__ import print_function |
661 | + |
662 | import tempfile |
663 | import os |
664 | import re |
665 | import sys |
666 | +if sys.version_info[0] < 3: |
667 | + input = raw_input |
668 | + |
669 | |
670 | import ubuntutools.subprocess |
671 | |
672 | @@ -56,9 +61,9 @@ |
673 | selected = None |
674 | while selected not in self.options: |
675 | try: |
676 | - selected = raw_input(question).strip().lower() |
677 | + selected = input(question).strip().lower() |
678 | except (EOFError, KeyboardInterrupt): |
679 | - print '\nAborting as requested.' |
680 | + print('\nAborting as requested.') |
681 | sys.exit(1) |
682 | if selected == "": |
683 | selected = default |
684 | @@ -68,8 +73,8 @@ |
685 | if selected == option[0]: |
686 | selected = option |
687 | if selected not in self.options: |
688 | - print "Please answer the question with " + \ |
689 | - self.get_options() + "." |
690 | + print("Please answer the question with " + \ |
691 | + self.get_options() + ".") |
692 | return selected |
693 | |
694 | |
695 | @@ -86,9 +91,9 @@ |
696 | selected = None |
697 | while selected < min_number or selected > max_number: |
698 | try: |
699 | - selected = raw_input(question).strip() |
700 | + selected = input(question).strip() |
701 | except (EOFError, KeyboardInterrupt): |
702 | - print '\nAborting as requested.' |
703 | + print('\nAborting as requested.') |
704 | sys.exit(1) |
705 | if default and selected == "": |
706 | selected = default |
707 | @@ -96,10 +101,10 @@ |
708 | try: |
709 | selected = int(selected) |
710 | if selected < min_number or selected > max_number: |
711 | - print "Please input a number between %i and %i." % \ |
712 | - (min_number, max_number) |
713 | + print("Please input a number between %i and %i." % \ |
714 | + (min_number, max_number)) |
715 | except ValueError: |
716 | - print "Please input a number." |
717 | + print("Please input a number.") |
718 | assert type(selected) == int |
719 | return selected |
720 | |
721 | @@ -113,9 +118,9 @@ |
722 | action = 'continue' |
723 | message = 'Press [Enter] to %s. Press [Ctrl-C] to abort now.' % action |
724 | try: |
725 | - raw_input(message) |
726 | + input(message) |
727 | except (EOFError, KeyboardInterrupt): |
728 | - print '\nAborting as requested.' |
729 | + print('\nAborting as requested.') |
730 | sys.exit(1) |
731 | |
732 | |
733 | @@ -129,9 +134,9 @@ |
734 | |
735 | def edit(self, optional=False): |
736 | if optional: |
737 | - print "\n\nCurrently the %s looks like:" % self.description |
738 | + print("\n\nCurrently the %s looks like:" % self.description) |
739 | with open(self.filename, 'r') as f: |
740 | - print f.read() |
741 | + print(f.read()) |
742 | if YesNoQuestion().ask("Edit", "no") == "no": |
743 | return |
744 | |
745 | @@ -150,12 +155,12 @@ |
746 | placeholders_present = True |
747 | |
748 | if placeholders_present: |
749 | - print ("Placeholders still present in the %s. " |
750 | - "Please replace them with useful information." |
751 | - % self.description) |
752 | + print("Placeholders still present in the %s. " |
753 | + "Please replace them with useful information." |
754 | + % self.description) |
755 | confirmation_prompt(action='edit again') |
756 | elif not modified: |
757 | - print "The %s was not modified" % self.description |
758 | + print("The %s was not modified" % self.description) |
759 | if YesNoQuestion().ask("Edit again", "yes") == "no": |
760 | done = True |
761 | elif self.check_edit(): |
762 | @@ -189,8 +194,8 @@ |
763 | report = f.read().decode('utf-8') |
764 | |
765 | if self.split_re.match(report) is None: |
766 | - print ("The %s doesn't start with 'Summary:' and 'Description:' " |
767 | - "blocks" % self.description) |
768 | + print("The %s doesn't start with 'Summary:' and 'Description:' " |
769 | + "blocks" % self.description) |
770 | confirmation_prompt('edit again') |
771 | return False |
772 | return True |
773 | |
774 | === modified file 'ubuntutools/requestsync/lp.py' |
775 | --- ubuntutools/requestsync/lp.py 2013-03-18 23:18:02 +0000 |
776 | +++ ubuntutools/requestsync/lp.py 2014-12-19 22:54:27 +0000 |
777 | @@ -20,6 +20,8 @@ |
778 | # Please see the /usr/share/common-licenses/GPL-2 file for the full text |
779 | # of the GNU General Public License license. |
780 | |
781 | +from __future__ import print_function |
782 | + |
783 | import re |
784 | |
785 | from debian.deb822 import Changes |
786 | @@ -39,7 +41,7 @@ |
787 | |
788 | try: |
789 | release = DebianDistroInfo().codename(release, None, release) |
790 | - except DistroDataOutdated, e: |
791 | + except DistroDataOutdated as e: |
792 | Logger.warn(e) |
793 | |
794 | return debian_archive.getSourcePackage(name, release) |
795 | @@ -71,11 +73,11 @@ |
796 | need_sponsor = not PersonTeam.me.canUploadPackage(archive, distroseries, |
797 | name, component) |
798 | if need_sponsor: |
799 | - print '''You are not able to upload this package directly to Ubuntu. |
800 | + print('''You are not able to upload this package directly to Ubuntu. |
801 | Your sync request shall require an approval by a member of the appropriate |
802 | sponsorship team, who shall be subscribed to this bug report. |
803 | This must be done before it can be processed by a member of the Ubuntu Archive |
804 | -team.''' |
805 | +team.''') |
806 | confirmation_prompt() |
807 | |
808 | return need_sponsor |
809 | @@ -98,12 +100,12 @@ |
810 | for bug in pkg_bug_list: |
811 | # check for Sync or sync and the package name |
812 | if not bug.is_complete and 'ync %s' % srcpkg in bug.title: |
813 | - print ('The following bug could be a possible duplicate sync bug ' |
814 | - 'on Launchpad:\n' |
815 | - ' * %s (%s)\n' |
816 | - 'Please check the above URL to verify this before ' |
817 | - 'continuing.' |
818 | - % (bug.title, bug.web_link)) |
819 | + print('The following bug could be a possible duplicate sync bug ' |
820 | + 'on Launchpad:\n' |
821 | + ' * %s (%s)\n' |
822 | + 'Please check the above URL to verify this before ' |
823 | + 'continuing.' |
824 | + % (bug.title, bug.web_link)) |
825 | confirmation_prompt() |
826 | |
827 | def get_ubuntu_delta_changelog(srcpkg): |
828 | @@ -127,7 +129,7 @@ |
829 | break |
830 | try: |
831 | response, body = Http().request(changes_url) |
832 | - except HttpLib2Error, e: |
833 | + except HttpLib2Error as e: |
834 | Logger.error(str(e)) |
835 | break |
836 | if response.status != 200: |
837 | @@ -156,8 +158,8 @@ |
838 | Use the LP API to file the sync request. |
839 | ''' |
840 | |
841 | - print ('The final report is:\nSummary: %s\nDescription:\n%s\n' |
842 | - % (bugtitle, bugtext)) |
843 | + print('The final report is:\nSummary: %s\nDescription:\n%s\n' |
844 | + % (bugtitle, bugtext)) |
845 | confirmation_prompt() |
846 | |
847 | if srcpkg: |
848 | @@ -181,5 +183,5 @@ |
849 | |
850 | bug.subscribe(person = PersonTeam(subscribe)()) |
851 | |
852 | - print ('Sync request filed as bug #%i: %s' |
853 | - % (bug.id, bug.web_link)) |
854 | + print('Sync request filed as bug #%i: %s' |
855 | + % (bug.id, bug.web_link)) |
856 | |
857 | === modified file 'ubuntutools/requestsync/mail.py' |
858 | --- ubuntutools/requestsync/mail.py 2013-03-18 23:18:02 +0000 |
859 | +++ ubuntutools/requestsync/mail.py 2014-12-19 22:54:27 +0000 |
860 | @@ -20,6 +20,8 @@ |
861 | # Please see the /usr/share/common-licenses/GPL-2 file for the full text |
862 | # of the GNU General Public License license. |
863 | |
864 | +from __future__ import print_function |
865 | + |
866 | import os |
867 | import re |
868 | import sys |
869 | @@ -27,6 +29,10 @@ |
870 | import socket |
871 | import tempfile |
872 | |
873 | +if sys.version_info[0] >= 3: |
874 | + basestring = str |
875 | + unicode = str |
876 | + |
877 | from debian.changelog import Changelog, Version |
878 | from distro_info import DebianDistroInfo, DistroDataOutdated |
879 | |
880 | @@ -51,7 +57,7 @@ |
881 | debian_info = DebianDistroInfo() |
882 | try: |
883 | release = debian_info.codename(release, default=release) |
884 | - except DistroDataOutdated, e: |
885 | + except DistroDataOutdated as e: |
886 | Logger.warn(e) |
887 | |
888 | lines = list(rmadison(distro, name, suite=release, arch='source')) |
889 | @@ -86,9 +92,9 @@ |
890 | ''' |
891 | Point the user to the URL to manually check for duplicate bug reports. |
892 | ''' |
893 | - print ('Please check on ' |
894 | - 'https://bugs.launchpad.net/ubuntu/+source/%s/+bugs\n' |
895 | - 'for duplicate sync requests before continuing.' % srcpkg) |
896 | + print('Please check on ' |
897 | + 'https://bugs.launchpad.net/ubuntu/+source/%s/+bugs\n' |
898 | + 'for duplicate sync requests before continuing.' % srcpkg) |
899 | confirmation_prompt() |
900 | |
901 | def get_ubuntu_delta_changelog(srcpkg): |
902 | @@ -164,7 +170,7 @@ |
903 | |
904 | %s''' % (myemailaddr, to, bugtitle, signed_report) |
905 | |
906 | - print 'The final report is:\n%s' % mail |
907 | + print('The final report is:\n%s' % mail) |
908 | confirmation_prompt() |
909 | |
910 | # save mail in temporary file |
911 | @@ -184,11 +190,11 @@ |
912 | mailserver_port) |
913 | s = smtplib.SMTP(mailserver_host, mailserver_port) |
914 | break |
915 | - except socket.error, s: |
916 | + except socket.error as s: |
917 | Logger.error('Could not connect to %s:%s: %s (%i)', |
918 | mailserver_host, mailserver_port, s[1], s[0]) |
919 | return |
920 | - except smtplib.SMTPConnectError, s: |
921 | + except smtplib.SMTPConnectError as s: |
922 | Logger.error('Could not connect to %s:%s: %s (%i)', |
923 | mailserver_host, mailserver_port, s[1], s[0]) |
924 | if s.smtp_code == 421: |
925 | @@ -215,7 +221,7 @@ |
926 | os.remove(backup.name) |
927 | Logger.normal('Sync request mailed.') |
928 | break |
929 | - except smtplib.SMTPRecipientsRefused, smtperror: |
930 | + except smtplib.SMTPRecipientsRefused as smtperror: |
931 | smtp_code, smtp_message = smtperror.recipients[to] |
932 | Logger.error('Error while sending: %i, %s', smtp_code, smtp_message) |
933 | if smtp_code == 450: |
934 | @@ -223,7 +229,7 @@ |
935 | '[Enter] to retry. Press [Ctrl-C] to abort now.') |
936 | else: |
937 | return |
938 | - except smtplib.SMTPResponseException, e: |
939 | + except smtplib.SMTPResponseException as e: |
940 | Logger.error('Error while sending: %i, %s', |
941 | e.smtp_code, e.smtp_error) |
942 | return |
943 | |
944 | === modified file 'ubuntutools/sponsor_patch/bugtask.py' |
945 | --- ubuntutools/sponsor_patch/bugtask.py 2013-03-18 23:18:02 +0000 |
946 | +++ ubuntutools/sponsor_patch/bugtask.py 2014-12-19 22:54:27 +0000 |
947 | @@ -17,7 +17,11 @@ |
948 | |
949 | import os |
950 | import re |
951 | -import urllib |
952 | +try: |
953 | + from urllib.parse import unquote |
954 | + from urllib.request import urlretrieve |
955 | +except ImportError: |
956 | + from urllib import unquote, urlretrieve |
957 | |
958 | import debian.debian_support |
959 | import distro_info |
960 | @@ -63,7 +67,7 @@ |
961 | source_files = self.get_source().sourceFileUrls() |
962 | dsc_file = "" |
963 | for url in source_files: |
964 | - filename = urllib.unquote(os.path.basename(url)) |
965 | + filename = unquote(os.path.basename(url)) |
966 | Logger.info("Downloading %s..." % (filename)) |
967 | # HttpLib2 isn't suitable for large files (it reads into memory), |
968 | # but we want its https certificate validation on the .dsc |
969 | @@ -75,7 +79,7 @@ |
970 | |
971 | dsc_file = os.path.join(os.getcwd(), filename) |
972 | else: |
973 | - urllib.urlretrieve(url, filename) |
974 | + urlretrieve(url, filename) |
975 | assert os.path.isfile(dsc_file), "%s does not exist." % (dsc_file) |
976 | return dsc_file |
977 | |
978 | |
979 | === modified file 'ubuntutools/sponsor_patch/patch.py' |
980 | --- ubuntutools/sponsor_patch/patch.py 2013-03-18 23:18:02 +0000 |
981 | +++ ubuntutools/sponsor_patch/patch.py 2014-12-19 22:54:27 +0000 |
982 | @@ -21,6 +21,7 @@ |
983 | from ubuntutools import subprocess |
984 | from ubuntutools.logger import Logger |
985 | from ubuntutools.sponsor_patch.question import ask_for_manual_fixing |
986 | +from functools import reduce |
987 | |
988 | class Patch(object): |
989 | """This object represents a patch that can be downloaded from Launchpad.""" |
990 | |
991 | === modified file 'ubuntutools/sponsor_patch/question.py' |
992 | --- ubuntutools/sponsor_patch/question.py 2011-12-21 21:09:53 +0000 |
993 | +++ ubuntutools/sponsor_patch/question.py 2014-12-19 22:54:27 +0000 |
994 | @@ -15,6 +15,8 @@ |
995 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
996 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
997 | |
998 | +from __future__ import print_function |
999 | + |
1000 | import sys |
1001 | |
1002 | from ubuntutools.question import Question, YesNoQuestion |
1003 | @@ -43,5 +45,5 @@ |
1004 | def user_abort(): |
1005 | """Print abort and quit the program.""" |
1006 | |
1007 | - print "User abort." |
1008 | + print("User abort.") |
1009 | sys.exit(2) |
1010 | |
1011 | === modified file 'ubuntutools/sponsor_patch/source_package.py' |
1012 | --- ubuntutools/sponsor_patch/source_package.py 2013-03-18 23:18:02 +0000 |
1013 | +++ ubuntutools/sponsor_patch/source_package.py 2014-12-19 22:54:27 +0000 |
1014 | @@ -15,6 +15,8 @@ |
1015 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
1016 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
1017 | |
1018 | +from __future__ import print_function |
1019 | + |
1020 | import os |
1021 | import re |
1022 | import sys |
1023 | @@ -301,7 +303,7 @@ |
1024 | bug title.""" |
1025 | |
1026 | if not task.title_contains(self._version): |
1027 | - print "Bug #%i title: %s" % (bug_number, task.get_bug_title()) |
1028 | + print("Bug #%i title: %s" % (bug_number, task.get_bug_title())) |
1029 | msg = "Is %s %s the version that should be synced" % (self._package, |
1030 | self._version) |
1031 | answer = YesNoQuestion().ask(msg, "no") |
1032 | @@ -349,7 +351,7 @@ |
1033 | |
1034 | assert os.path.isfile(self._changes_file), "%s does not exist." % \ |
1035 | (self._changes_file) |
1036 | - changes = debian.deb822.Changes(file(self._changes_file)) |
1037 | + changes = debian.deb822.Changes(open(self._changes_file)) |
1038 | fixed_bugs = [] |
1039 | if "Launchpad-Bugs-Fixed" in changes: |
1040 | fixed_bugs = changes["Launchpad-Bugs-Fixed"].split(" ") |
1041 | @@ -370,16 +372,16 @@ |
1042 | """Print things that should be checked before uploading a package.""" |
1043 | |
1044 | lintian_filename = self._run_lintian() |
1045 | - print "\nPlease check %s %s carefully:" % (self._package, self._version) |
1046 | + print("\nPlease check %s %s carefully:" % (self._package, self._version)) |
1047 | if os.path.isfile(self._debdiff_filename): |
1048 | - print "file://" + self._debdiff_filename |
1049 | - print "file://" + lintian_filename |
1050 | + print("file://" + self._debdiff_filename) |
1051 | + print("file://" + lintian_filename) |
1052 | if self._build_log: |
1053 | - print "file://" + self._build_log |
1054 | + print("file://" + self._build_log) |
1055 | |
1056 | harvest = Harvest(self._package) |
1057 | if harvest.data: |
1058 | - print harvest.report() |
1059 | + print(harvest.report()) |
1060 | |
1061 | def reload_changelog(self): |
1062 | """Reloads debian/changelog and updates the version. |
1063 | @@ -391,9 +393,9 @@ |
1064 | # Check the changelog |
1065 | self._changelog = debian.changelog.Changelog() |
1066 | try: |
1067 | - self._changelog.parse_changelog(file("debian/changelog"), |
1068 | + self._changelog.parse_changelog(open("debian/changelog"), |
1069 | max_blocks=1, strict=True) |
1070 | - except debian.changelog.ChangelogParseError, error: |
1071 | + except debian.changelog.ChangelogParseError as error: |
1072 | Logger.error("The changelog entry doesn't validate: %s", str(error)) |
1073 | ask_for_manual_fixing() |
1074 | return False |
1075 | |
1076 | === modified file 'ubuntutools/sponsor_patch/sponsor_patch.py' |
1077 | --- ubuntutools/sponsor_patch/sponsor_patch.py 2013-08-22 15:22:55 +0000 |
1078 | +++ ubuntutools/sponsor_patch/sponsor_patch.py 2014-12-19 22:54:27 +0000 |
1079 | @@ -15,11 +15,16 @@ |
1080 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
1081 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
1082 | |
1083 | +from __future__ import print_function |
1084 | + |
1085 | import os |
1086 | import pwd |
1087 | import shutil |
1088 | import sys |
1089 | |
1090 | +if sys.version_info[0] < 3: |
1091 | + range = xrange |
1092 | + |
1093 | from distro_info import UbuntuDistroInfo |
1094 | |
1095 | from launchpadlib.launchpad import Launchpad |
1096 | @@ -81,11 +86,11 @@ |
1097 | # Spawn shell to allow modifications |
1098 | cmd = [get_user_shell()] |
1099 | Logger.command(cmd) |
1100 | - print """An interactive shell was launched in |
1101 | + print("""An interactive shell was launched in |
1102 | file://%s |
1103 | Edit your files. When you are done, exit the shell. If you wish to abort the |
1104 | process, exit the shell such that it returns an exit code other than zero. |
1105 | -""" % (os.getcwd()), |
1106 | +""" % (os.getcwd()), end=' ') |
1107 | returncode = subprocess.call(cmd) |
1108 | if returncode != 0: |
1109 | Logger.error("Shell exited with exit value %i." % (returncode)) |
1110 | @@ -113,10 +118,10 @@ |
1111 | i = 0 |
1112 | for linked_branch in linked_branches: |
1113 | i += 1 |
1114 | - print "%i) %s" % (i, linked_branch.display_name) |
1115 | + print("%i) %s" % (i, linked_branch.display_name)) |
1116 | for attached_patch in attached_patches: |
1117 | i += 1 |
1118 | - print "%i) %s" % (i, attached_patch.title) |
1119 | + print("%i) %s" % (i, attached_patch.title)) |
1120 | selected = input_number("Which branch or patch do you want to download", |
1121 | 1, i, i) |
1122 | if selected <= len(linked_branches): |
1123 | @@ -220,9 +225,9 @@ |
1124 | else: |
1125 | Logger.normal("https://launchpad.net/bugs/%i has %i Ubuntu tasks:" \ |
1126 | % (bug_id, len(ubuntu_tasks))) |
1127 | - for i in xrange(len(ubuntu_tasks)): |
1128 | - print "%i) %s" % (i + 1, |
1129 | - ubuntu_tasks[i].get_package_and_series()) |
1130 | + for i in range(len(ubuntu_tasks)): |
1131 | + print("%i) %s" % (i + 1, |
1132 | + ubuntu_tasks[i].get_package_and_series())) |
1133 | selected = input_number("To which Ubuntu task does the patch belong", |
1134 | 1, len(ubuntu_tasks)) |
1135 | task = ubuntu_tasks[selected - 1] |
1136 | @@ -235,7 +240,7 @@ |
1137 | if not os.path.isdir(workdir): |
1138 | try: |
1139 | os.makedirs(workdir) |
1140 | - except os.error, error: |
1141 | + except os.error as error: |
1142 | Logger.error("Failed to create the working directory %s [Errno " \ |
1143 | "%i]: %s." % (workdir, error.errno, error.strerror)) |
1144 | sys.exit(1) |
1145 | @@ -248,7 +253,7 @@ |
1146 | Logger.command(["update-maintainer"]) |
1147 | try: |
1148 | update_maintainer("debian", Logger.verbose) |
1149 | - except MaintainerUpdateException, e: |
1150 | + except MaintainerUpdateException as e: |
1151 | Logger.error("update-maintainer failed: %s", str(e)) |
1152 | sys.exit(1) |
1153 | |
1154 | |
1155 | === modified file 'ubuntutools/test/test_archive.py' |
1156 | --- ubuntutools/test/test_archive.py 2014-02-25 20:46:10 +0000 |
1157 | +++ ubuntutools/test/test_archive.py 2014-12-19 22:54:27 +0000 |
1158 | @@ -14,19 +14,30 @@ |
1159 | # OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
1160 | # PERFORMANCE OF THIS SOFTWARE. |
1161 | |
1162 | -from __future__ import with_statement |
1163 | |
1164 | -import __builtin__ |
1165 | +try: |
1166 | + import builtins |
1167 | +except ImportError: |
1168 | + import __builtin__ |
1169 | import os.path |
1170 | import shutil |
1171 | -import StringIO |
1172 | +try: |
1173 | + from StringIO import StringIO |
1174 | +except: |
1175 | + from io import StringIO |
1176 | +from io import BytesIO |
1177 | import tempfile |
1178 | import types |
1179 | -import urllib2 |
1180 | - |
1181 | +try: |
1182 | + from urllib.request import OpenerDirector, urlopen |
1183 | + from urllib.error import HTTPError, URLError |
1184 | +except ImportError: |
1185 | + from urllib2 import OpenerDirector, urlopen |
1186 | + from urllib2 import HTTPError, URLError |
1187 | import debian.deb822 |
1188 | import httplib2 |
1189 | -import mox |
1190 | +import sys |
1191 | +import mock |
1192 | |
1193 | import ubuntutools.archive |
1194 | from ubuntutools.config import UDTConfig |
1195 | @@ -44,15 +55,11 @@ |
1196 | ex_pkg.cleanup() |
1197 | |
1198 | |
1199 | -class DscVerificationTestCase(mox.MoxTestBase, unittest.TestCase): |
1200 | +class DscVerificationTestCase(unittest.TestCase): |
1201 | def setUp(self): |
1202 | - super(DscVerificationTestCase, self).setUp() |
1203 | with open('test-data/example_1.0-1.dsc', 'rb') as f: |
1204 | self.dsc = ubuntutools.archive.Dsc(f.read()) |
1205 | |
1206 | - def tearDown(self): |
1207 | - super(DscVerificationTestCase, self).tearDown() |
1208 | - |
1209 | def test_good(self): |
1210 | self.assertTrue(self.dsc.verify_file( |
1211 | 'test-data/example_1.0.orig.tar.gz')) |
1212 | @@ -67,11 +74,19 @@ |
1213 | fn = 'test-data/example_1.0.orig.tar.gz' |
1214 | with open(fn, 'rb') as f: |
1215 | data = f.read() |
1216 | - data = data[:-1] + chr(ord(data[-1]) ^ 8) |
1217 | - self.mox.StubOutWithMock(__builtin__, 'open') |
1218 | - open(fn, 'rb').AndReturn(StringIO.StringIO(data)) |
1219 | - self.mox.ReplayAll() |
1220 | - self.assertFalse(self.dsc.verify_file(fn)) |
1221 | + if sys.version_info[0] >= 3: |
1222 | + last_byte = chr(data[-1] ^ 8).encode() |
1223 | + else: |
1224 | + last_byte = chr(ord(data[-1]) ^ 8) |
1225 | + data = data[:-1] + last_byte |
1226 | + m = mock.MagicMock(name='open', spec=open) |
1227 | + m.return_value = BytesIO(data) |
1228 | + if sys.version_info[0] >= 3: |
1229 | + target = 'builtins.open' |
1230 | + else: |
1231 | + target = '__builtin__.open' |
1232 | + with mock.patch(target, m): |
1233 | + self.assertFalse(self.dsc.verify_file(fn)) |
1234 | |
1235 | def test_sha1(self): |
1236 | del self.dsc['Checksums-Sha256'] |
1237 | @@ -85,26 +100,31 @@ |
1238 | self.test_bad() |
1239 | |
1240 | |
1241 | -class LocalSourcePackageTestCase(mox.MoxTestBase, unittest.TestCase): |
1242 | +class LocalSourcePackageTestCase(unittest.TestCase): |
1243 | SourcePackage = ubuntutools.archive.UbuntuSourcePackage |
1244 | |
1245 | def setUp(self): |
1246 | - super(LocalSourcePackageTestCase, self).setUp() |
1247 | self.workdir = tempfile.mkdtemp(prefix='udt-test') |
1248 | |
1249 | - self.mox.StubOutWithMock(ubuntutools.archive, 'Distribution') |
1250 | - self.mox.StubOutWithMock(ubuntutools.archive, 'rmadison') |
1251 | - |
1252 | - self.real_http = httplib2.Http() |
1253 | - self.mox.StubOutWithMock(httplib2, 'Http') |
1254 | - self.mock_http = self.mox.CreateMock(httplib2.Http) |
1255 | + self._stubout('ubuntutools.archive.Distribution') |
1256 | + self._stubout('ubuntutools.archive.rmadison') |
1257 | + |
1258 | + self.mock_http = self._stubout('httplib2.Http.request') |
1259 | + self.mock_http.side_effect = self.request_proxy |
1260 | + |
1261 | + self.url_opener = mock.MagicMock(spec=OpenerDirector) |
1262 | + self.url_opener.open.side_effect = self.urlopen_proxy |
1263 | |
1264 | # Silence the tests a little: |
1265 | - self.mox.stubs.Set(Logger, 'stdout', StringIO.StringIO()) |
1266 | - self.mox.stubs.Set(Logger, 'stderr', StringIO.StringIO()) |
1267 | + self._stubout('ubuntutools.logger.Logger.stdout') |
1268 | + self._stubout('ubuntutools.logger.Logger.stderr') |
1269 | + |
1270 | + def _stubout(self, stub): |
1271 | + patcher = mock.patch(stub) |
1272 | + self.addCleanup(patcher.stop) |
1273 | + return patcher.start() |
1274 | |
1275 | def tearDown(self): |
1276 | - super(LocalSourcePackageTestCase, self).tearDown() |
1277 | shutil.rmtree(self.workdir) |
1278 | |
1279 | def urlopen_proxy(self, url, destname=None): |
1280 | @@ -112,7 +132,7 @@ |
1281 | if destname is None: |
1282 | destname = os.path.basename(url) |
1283 | destpath = os.path.join(os.path.abspath('test-data'), destname) |
1284 | - return urllib2.urlopen('file://' + destpath) |
1285 | + return urlopen('file://' + destpath) |
1286 | |
1287 | def urlopen_file(self, filename): |
1288 | "Wrapper for urlopen_proxy for named files" |
1289 | @@ -120,11 +140,11 @@ |
1290 | |
1291 | def urlopen_null(self, url): |
1292 | "urlopen for zero length files" |
1293 | - return StringIO.StringIO('') |
1294 | + return BytesIO(b'') |
1295 | |
1296 | def urlopen_404(self, url): |
1297 | "urlopen for errors" |
1298 | - raise urllib2.HTTPError(url, 404, "Not Found", {}, None) |
1299 | + raise HTTPError(url, 404, "Not Found", {}, None) |
1300 | |
1301 | def request_proxy(self, url, destname=None): |
1302 | "httplib2 proxy for grabbing the file from test-data" |
1303 | @@ -132,7 +152,7 @@ |
1304 | destname = os.path.basename(url) |
1305 | destpath = os.path.join(os.path.abspath('test-data'), destname) |
1306 | response = httplib2.Response({}) |
1307 | - with open(destpath, 'r') as f: |
1308 | + with open(destpath, 'rb') as f: |
1309 | body = f.read() |
1310 | return response, body |
1311 | |
1312 | @@ -141,10 +161,17 @@ |
1313 | response = httplib2.Response({'status': 404}) |
1314 | return response, "I'm a 404 Error" |
1315 | |
1316 | + def request_404_then_proxy(self, url, destname=None): |
1317 | + "mock side_effect callable to chain request 404 & proxy" |
1318 | + if self.mock_http.called: |
1319 | + return self.request_proxy(url, destname) |
1320 | + return self.request_404(url) |
1321 | + |
1322 | def test_local_copy(self): |
1323 | pkg = self.SourcePackage('example', '1.0-1', 'main', |
1324 | dscfile='test-data/example_1.0-1.dsc', |
1325 | workdir=self.workdir) |
1326 | + pkg.quiet = True |
1327 | pkg.pull() |
1328 | pkg.unpack() |
1329 | |
1330 | @@ -156,6 +183,7 @@ |
1331 | pkg = self.SourcePackage(dscfile=os.path.join(self.workdir, |
1332 | 'example_1.0-1.dsc'), |
1333 | workdir=self.workdir) |
1334 | + pkg.quiet = True |
1335 | pkg.pull() |
1336 | pkg.unpack() |
1337 | |
1338 | @@ -168,6 +196,7 @@ |
1339 | dscfile=os.path.join(self.workdir, |
1340 | 'example_1.0-1.dsc'), |
1341 | workdir=self.workdir) |
1342 | + pkg.quiet = True |
1343 | pkg.pull() |
1344 | pkg.unpack() |
1345 | |
1346 | @@ -177,31 +206,24 @@ |
1347 | shutil.copy2('test-data/example_1.0-1.debian.tar.xz', self.workdir) |
1348 | with open(os.path.join(self.workdir, 'example_1.0-1.debian.tar.xz'), |
1349 | 'r+b') as f: |
1350 | - f.write('CORRUPTION') |
1351 | + f.write(b'CORRUPTION') |
1352 | |
1353 | pkg = self.SourcePackage('example', '1.0-1', 'main', |
1354 | dscfile='test-data/example_1.0-1.dsc', |
1355 | workdir=self.workdir) |
1356 | + pkg.quiet = True |
1357 | pkg.pull() |
1358 | |
1359 | def test_pull(self): |
1360 | dist = self.SourcePackage.distribution |
1361 | mirror = UDTConfig.defaults['%s_MIRROR' % dist.upper()] |
1362 | urlbase = '/pool/main/e/example/' |
1363 | - httplib2.Http().AndReturn(self.mock_http) |
1364 | - self.mock_http.request('https://launchpad.net/%s/+archive/primary/' |
1365 | - '+files/example_1.0-1.dsc' % dist |
1366 | - ).WithSideEffects(self.request_proxy) |
1367 | - url_opener = self.mox.CreateMock(urllib2.OpenerDirector) |
1368 | - url_opener.open(mirror + urlbase + 'example_1.0.orig.tar.gz' |
1369 | - ).WithSideEffects(self.urlopen_proxy) |
1370 | - url_opener.open(mirror + urlbase + 'example_1.0-1.debian.tar.xz' |
1371 | - ).WithSideEffects(self.urlopen_proxy) |
1372 | - self.mox.ReplayAll() |
1373 | |
1374 | pkg = self.SourcePackage('example', '1.0-1', 'main', |
1375 | workdir=self.workdir) |
1376 | - pkg.url_opener = url_opener |
1377 | + |
1378 | + pkg.url_opener = self.url_opener |
1379 | + pkg.quiet = True |
1380 | pkg.pull() |
1381 | |
1382 | def test_mirrors(self): |
1383 | @@ -209,34 +231,24 @@ |
1384 | mirror = 'http://mirror' |
1385 | lpbase = 'https://launchpad.net/ubuntu/+archive/primary/+files/' |
1386 | urlbase = '/pool/main/e/example/' |
1387 | - httplib2.Http().AndReturn(self.mock_http) |
1388 | - self.mock_http.request(lpbase + 'example_1.0-1.dsc' |
1389 | - ).WithSideEffects(self.request_proxy) |
1390 | - url_opener = self.mox.CreateMock(urllib2.OpenerDirector) |
1391 | - url_opener.open(mirror + urlbase + 'example_1.0.orig.tar.gz' |
1392 | - ).WithSideEffects(self.urlopen_null) |
1393 | - url_opener.open(master + urlbase + 'example_1.0.orig.tar.gz' |
1394 | - ).WithSideEffects(self.urlopen_404) |
1395 | - url_opener.open(lpbase + 'example_1.0.orig.tar.gz' |
1396 | - ).WithSideEffects(self.urlopen_proxy) |
1397 | - url_opener.open(mirror + urlbase + 'example_1.0-1.debian.tar.xz' |
1398 | - ).WithSideEffects(self.urlopen_proxy) |
1399 | - self.mox.ReplayAll() |
1400 | + sequence = [self.urlopen_null, self.urlopen_404, self.urlopen_proxy, |
1401 | + self.urlopen_proxy] |
1402 | + def _callable_iter(*args, **kwargs): |
1403 | + return sequence.pop(0)(*args, **kwargs) |
1404 | + url_opener = mock.MagicMock(spec=OpenerDirector) |
1405 | + url_opener.open.side_effect = _callable_iter |
1406 | |
1407 | pkg = self.SourcePackage('example', '1.0-1', 'main', |
1408 | workdir=self.workdir, mirrors=[mirror]) |
1409 | pkg.url_opener = url_opener |
1410 | + pkg.quiet = True |
1411 | pkg.pull() |
1412 | |
1413 | def test_dsc_missing(self): |
1414 | - lpbase = 'https://launchpad.net/ubuntu/+archive/primary/+files/' |
1415 | - httplib2.Http().AndReturn(self.mock_http) |
1416 | - self.mock_http.request(lpbase + 'example_1.0-1.dsc' |
1417 | - ).WithSideEffects(self.request_404) |
1418 | - self.mox.ReplayAll() |
1419 | - |
1420 | + self.mock_http.side_effect = self.request_404 |
1421 | pkg = self.SourcePackage('example', '1.0-1', 'main', |
1422 | workdir=self.workdir) |
1423 | + pkg.quiet = True |
1424 | self.assertRaises(ubuntutools.archive.DownloadError, pkg.pull) |
1425 | |
1426 | |
1427 | @@ -251,35 +263,24 @@ |
1428 | lpbase = 'https://launchpad.net/debian/+archive/primary/+files/' |
1429 | base = '/pool/main/e/example/' |
1430 | |
1431 | - httplib2.Http().AndReturn(self.mock_http) |
1432 | - self.mock_http.request(lpbase + 'example_1.0-1.dsc' |
1433 | - ).WithSideEffects(self.request_proxy) |
1434 | - url_opener = self.mox.CreateMock(urllib2.OpenerDirector) |
1435 | - url_opener.open(debian_mirror + base + 'example_1.0.orig.tar.gz' |
1436 | - ).WithSideEffects(self.urlopen_null) |
1437 | - url_opener.open(debsec_mirror + base + 'example_1.0.orig.tar.gz' |
1438 | - ).WithSideEffects(self.urlopen_404) |
1439 | - url_opener.open(debian_master + base + 'example_1.0.orig.tar.gz' |
1440 | - ).WithSideEffects(self.urlopen_404) |
1441 | - url_opener.open(debsec_master + base + 'example_1.0.orig.tar.gz' |
1442 | - ).WithSideEffects(self.urlopen_404) |
1443 | - url_opener.open(lpbase + 'example_1.0.orig.tar.gz' |
1444 | - ).WithSideEffects(self.urlopen_404) |
1445 | - url_opener.open('http://snapshot.debian.org/mr/package/example/1.0-1/' |
1446 | - 'srcfiles?fileinfo=1' |
1447 | - ).WithSideEffects(lambda x: StringIO.StringIO( |
1448 | - '{"fileinfo": {"hashabc": [{"name": "example_1.0.orig.tar.gz"}]}}' |
1449 | - )) |
1450 | - url_opener.open('http://snapshot.debian.org/file/hashabc' |
1451 | - ).WithSideEffects(self.urlopen_file( |
1452 | - 'example_1.0.orig.tar.gz')) |
1453 | - url_opener.open(debian_mirror + base + 'example_1.0-1.debian.tar.xz' |
1454 | - ).WithSideEffects(self.urlopen_proxy) |
1455 | - self.mox.ReplayAll() |
1456 | + sequence = [self.urlopen_null, |
1457 | + self.urlopen_404, |
1458 | + self.urlopen_404, |
1459 | + self.urlopen_404, |
1460 | + self.urlopen_404, |
1461 | + lambda x: BytesIO( |
1462 | + b'{"fileinfo": {"hashabc": [{"name": "example_1.0.orig.tar.gz"}]}}'), |
1463 | + self.urlopen_file('example_1.0.orig.tar.gz'), |
1464 | + self.urlopen_proxy] |
1465 | + def _callable_iter(*args, **kwargs): |
1466 | + return sequence.pop(0)(*args, **kwargs) |
1467 | + url_opener = mock.MagicMock(spec=OpenerDirector) |
1468 | + url_opener.open.side_effect = _callable_iter |
1469 | |
1470 | pkg = self.SourcePackage('example', '1.0-1', 'main', |
1471 | workdir=self.workdir, mirrors=[debian_mirror, |
1472 | debsec_mirror]) |
1473 | + pkg.quiet = True |
1474 | pkg.url_opener = url_opener |
1475 | pkg.pull() |
1476 | pkg.unpack() |
1477 | @@ -288,61 +289,35 @@ |
1478 | mirror = 'http://mirror' |
1479 | lpbase = 'https://launchpad.net/debian/+archive/primary/+files/' |
1480 | base = '/pool/main/e/example/' |
1481 | - httplib2.Http().AndReturn(self.mock_http) |
1482 | - self.mock_http.request(lpbase + 'example_1.0-1.dsc' |
1483 | - ).WithSideEffects(self.request_404) |
1484 | - httplib2.Http().AndReturn(self.mock_http) |
1485 | - self.mock_http.request(mirror + base + 'example_1.0-1.dsc' |
1486 | - ).WithSideEffects(self.request_proxy) |
1487 | - url_opener = self.mox.CreateMock(urllib2.OpenerDirector) |
1488 | - url_opener.open(mirror + base + 'example_1.0.orig.tar.gz' |
1489 | - ).WithSideEffects(self.urlopen_proxy) |
1490 | - url_opener.open(mirror + base + 'example_1.0-1.debian.tar.xz' |
1491 | - ).WithSideEffects(self.urlopen_proxy) |
1492 | - |
1493 | - def fake_gpg_info(self, message, keyrings=None): |
1494 | - return debian.deb822.GpgInfo.from_output( |
1495 | - '[GNUPG:] GOODSIG DEADBEEF Joe Developer ' |
1496 | - '<joe@example.net>') |
1497 | - # We have to stub this out without mox because there some versions of |
1498 | - # python-debian will pass keyrings=None, others won't. |
1499 | - # http://code.google.com/p/pymox/issues/detail?id=37 |
1500 | - self.mox.stubs.Set(debian.deb822.GpgInfo, 'from_sequence', |
1501 | - types.MethodType(fake_gpg_info, |
1502 | - debian.deb822.GpgInfo, |
1503 | - debian.deb822.GpgInfo)) |
1504 | - |
1505 | - self.mox.ReplayAll() |
1506 | + self.mock_http.side_effect = self.request_404_then_proxy |
1507 | + |
1508 | + patcher = mock.patch.object(debian.deb822.GpgInfo, 'from_sequence') |
1509 | + self.addCleanup(patcher.stop) |
1510 | + mock_gpg_info = patcher.start() |
1511 | + mock_gpg_info.return_value = debian.deb822.GpgInfo.from_output( |
1512 | + '[GNUPG:] GOODSIG DEADBEEF Joe Developer ' |
1513 | + '<joe@example.net>') |
1514 | |
1515 | pkg = self.SourcePackage('example', '1.0-1', 'main', |
1516 | workdir=self.workdir, mirrors=[mirror]) |
1517 | - pkg.url_opener = url_opener |
1518 | + pkg.url_opener = self.url_opener |
1519 | pkg.pull() |
1520 | |
1521 | def test_dsc_badsig(self): |
1522 | mirror = 'http://mirror' |
1523 | lpbase = 'https://launchpad.net/debian/+archive/primary/+files/' |
1524 | base = '/pool/main/e/example/' |
1525 | - httplib2.Http().AndReturn(self.mock_http) |
1526 | - self.mock_http.request(lpbase + 'example_1.0-1.dsc' |
1527 | - ).WithSideEffects(self.request_404) |
1528 | - httplib2.Http().AndReturn(self.mock_http) |
1529 | - self.mock_http.request(mirror + base + 'example_1.0-1.dsc' |
1530 | - ).WithSideEffects(self.request_proxy) |
1531 | - |
1532 | - def fake_gpg_info(self, message, keyrings=None): |
1533 | - return debian.deb822.GpgInfo.from_output( |
1534 | - '[GNUPG:] ERRSIG DEADBEEF') |
1535 | - # We have to stub this out without mox because there some versions of |
1536 | - # python-debian will pass keyrings=None, others won't. |
1537 | - # http://code.google.com/p/pymox/issues/detail?id=37 |
1538 | - self.mox.stubs.Set(debian.deb822.GpgInfo, 'from_sequence', |
1539 | - types.MethodType(fake_gpg_info, |
1540 | - debian.deb822.GpgInfo, |
1541 | - debian.deb822.GpgInfo)) |
1542 | - |
1543 | - self.mox.ReplayAll() |
1544 | - |
1545 | + self.mock_http.side_effect = self.request_404_then_proxy |
1546 | + |
1547 | + patcher = mock.patch.object(debian.deb822.GpgInfo, 'from_sequence') |
1548 | + self.addCleanup(patcher.stop) |
1549 | + mock_gpg_info = patcher.start() |
1550 | + mock_gpg_info.return_value = debian.deb822.GpgInfo.from_output( |
1551 | + '[GNUPG:] ERRSIG DEADBEEF') |
1552 | + |
1553 | pkg = self.SourcePackage('example', '1.0-1', 'main', |
1554 | workdir=self.workdir, mirrors=[mirror]) |
1555 | - self.assertRaises(ubuntutools.archive.DownloadError, pkg.pull) |
1556 | + try: |
1557 | + self.assertRaises(ubuntutools.archive.DownloadError, pkg.pull) |
1558 | + except URLError: |
1559 | + raise unittest.SkipTest('Test needs addr resolution to work') |
1560 | |
1561 | === modified file 'ubuntutools/test/test_config.py' |
1562 | --- ubuntutools/test/test_config.py 2013-05-15 00:18:50 +0000 |
1563 | +++ ubuntutools/test/test_config.py 2014-12-19 22:54:27 +0000 |
1564 | @@ -15,19 +15,25 @@ |
1565 | # OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
1566 | # PERFORMANCE OF THIS SOFTWARE. |
1567 | |
1568 | -import __builtin__ |
1569 | +try: |
1570 | + import builtins |
1571 | +except ImportError: |
1572 | + import __builtin__ |
1573 | import os |
1574 | import sys |
1575 | import locale |
1576 | -from StringIO import StringIO |
1577 | +try: |
1578 | + from StringIO import StringIO |
1579 | +except: |
1580 | + from io import StringIO |
1581 | |
1582 | -import mox |
1583 | +import mock |
1584 | |
1585 | from ubuntutools.config import UDTConfig, ubu_email |
1586 | from ubuntutools.logger import Logger |
1587 | from ubuntutools.test import unittest |
1588 | |
1589 | -class ConfigTestCase(mox.MoxTestBase, unittest.TestCase): |
1590 | +class ConfigTestCase(unittest.TestCase): |
1591 | _config_files = { |
1592 | 'system': '', |
1593 | 'user': '', |
1594 | @@ -46,7 +52,18 @@ |
1595 | |
1596 | def setUp(self): |
1597 | super(ConfigTestCase, self).setUp() |
1598 | - self.mox.stubs.Set(__builtin__, 'open', self._fake_open) |
1599 | + if sys.version_info[0] < 3: |
1600 | + self.assertRegex = self.assertRegexpMatches |
1601 | + m = mock.mock_open() |
1602 | + m.side_effect = self._fake_open |
1603 | + if sys.version_info[0] >= 3: |
1604 | + target = 'builtins.open' |
1605 | + else: |
1606 | + target = '__builtin__.open' |
1607 | + patcher = mock.patch(target, m) |
1608 | + self.addCleanup(patcher.stop) |
1609 | + patcher.start() |
1610 | + |
1611 | Logger.stdout = StringIO() |
1612 | Logger.stderr = StringIO() |
1613 | |
1614 | @@ -63,7 +80,7 @@ |
1615 | def clean_environment(self): |
1616 | self._config_files['system'] = '' |
1617 | self._config_files['user'] = '' |
1618 | - for k in os.environ.keys(): |
1619 | + for k in list(os.environ.keys()): |
1620 | if k.startswith(('UBUNTUTOOLS_', 'TEST_')): |
1621 | del os.environ[k] |
1622 | |
1623 | @@ -97,8 +114,8 @@ |
1624 | errs = Logger.stderr.getvalue().strip() |
1625 | Logger.stderr = StringIO() |
1626 | self.assertEqual(len(errs.splitlines()), 1) |
1627 | - self.assertRegexpMatches(errs, |
1628 | - r'Warning: Cannot parse.*\bCOMMAND_EXECUTION=a') |
1629 | + self.assertRegex(errs, |
1630 | + r'Warning: Cannot parse.*\bCOMMAND_EXECUTION=a') |
1631 | |
1632 | def get_value(self, *args, **kwargs): |
1633 | config = UDTConfig(prefix='TEST') |
1634 | @@ -137,8 +154,8 @@ |
1635 | errs = Logger.stderr.getvalue().strip() |
1636 | Logger.stderr = StringIO() |
1637 | self.assertEqual(len(errs.splitlines()), 1) |
1638 | - self.assertRegexpMatches(errs, |
1639 | - r'deprecated.*\bCOMPATFOOBAR\b.*\bTEST_QUX\b') |
1640 | + self.assertRegex(errs, |
1641 | + r'deprecated.*\bCOMPATFOOBAR\b.*\bTEST_QUX\b') |
1642 | |
1643 | def test_boolean(self): |
1644 | self._config_files['user'] = "TEST_BOOLEAN=yes" |
1645 | @@ -150,7 +167,7 @@ |
1646 | |
1647 | def test_nonpackagewide(self): |
1648 | self._config_files['user'] = 'UBUNTUTOOLS_FOOBAR=a' |
1649 | - self.assertEquals(self.get_value('FOOBAR'), None) |
1650 | + self.assertEqual(self.get_value('FOOBAR'), None) |
1651 | |
1652 | |
1653 | class UbuEmailTestCase(unittest.TestCase): |
1654 | @@ -217,7 +234,11 @@ |
1655 | encoding = locale.getdefaultlocale()[1] |
1656 | if not encoding: |
1657 | encoding = 'utf-8' |
1658 | - name = 'Jöe Déveloper'.decode('utf-8') |
1659 | - os.environ['DEBFULLNAME'] = name.encode(encoding) |
1660 | + name = 'Jöe Déveloper' |
1661 | + env_name = name |
1662 | + if isinstance(name, bytes): |
1663 | + name = 'Jöe Déveloper'.decode('utf-8') |
1664 | + env_name = name.encode(encoding) |
1665 | + os.environ['DEBFULLNAME'] = env_name |
1666 | os.environ['DEBEMAIL'] = email = 'joe@example.net' |
1667 | self.assertEqual(ubu_email(), (name, email)) |
1668 | |
1669 | === modified file 'ubuntutools/test/test_help.py' |
1670 | --- ubuntutools/test/test_help.py 2012-05-06 04:06:41 +0000 |
1671 | +++ ubuntutools/test/test_help.py 2014-12-19 22:54:27 +0000 |
1672 | @@ -45,6 +45,7 @@ |
1673 | null = open('/dev/null', 'r') |
1674 | process = subprocess.Popen(['./' + script, '--help'], |
1675 | close_fds=True, stdin=null, |
1676 | + universal_newlines=True, |
1677 | stdout=subprocess.PIPE, |
1678 | stderr=subprocess.PIPE) |
1679 | started = time.time() |
1680 | @@ -57,7 +58,10 @@ |
1681 | |
1682 | while time.time() - started < TIMEOUT: |
1683 | for fd in select.select(fds, [], fds, TIMEOUT)[0]: |
1684 | - out.append(os.read(fd, 1024)) |
1685 | + output = os.read(fd, 1024) |
1686 | + if not isinstance(output, str): |
1687 | + output = output.decode('utf-8') |
1688 | + out.append(output) |
1689 | if process.poll() is not None: |
1690 | break |
1691 | |
1692 | |
1693 | === modified file 'ubuntutools/test/test_logger.py' |
1694 | --- ubuntutools/test/test_logger.py 2013-03-18 23:18:02 +0000 |
1695 | +++ ubuntutools/test/test_logger.py 2014-12-19 22:54:27 +0000 |
1696 | @@ -14,7 +14,10 @@ |
1697 | # OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
1698 | # PERFORMANCE OF THIS SOFTWARE. |
1699 | |
1700 | -import StringIO |
1701 | +try: |
1702 | + from StringIO import StringIO |
1703 | +except: |
1704 | + from io import StringIO |
1705 | import sys |
1706 | |
1707 | from ubuntutools.logger import Logger |
1708 | @@ -23,8 +26,8 @@ |
1709 | |
1710 | class LoggerTestCase(unittest.TestCase): |
1711 | def setUp(self): |
1712 | - Logger.stdout = StringIO.StringIO() |
1713 | - Logger.stderr = StringIO.StringIO() |
1714 | + Logger.stdout = StringIO() |
1715 | + Logger.stderr = StringIO() |
1716 | self._script_name = Logger.script_name |
1717 | Logger.script_name = 'test' |
1718 | self._verbose = Logger.verbose |
1719 | |
1720 | === modified file 'ubuntutools/test/test_pylint.py' |
1721 | --- ubuntutools/test/test_pylint.py 2011-06-24 14:32:07 +0000 |
1722 | +++ ubuntutools/test/test_pylint.py 2014-12-19 22:54:27 +0000 |
1723 | @@ -25,9 +25,6 @@ |
1724 | r"No name '\w+Error' in module 'launchpadlib\.errors'", |
1725 | # http://www.logilab.org/ticket/51250: |
1726 | r"Module 'hashlib' has no '(md5|sha(1|224|256|384|512))' member", |
1727 | - # mox: |
1728 | - r"Instance of '.+' has no '(WithSideEffects|MultipleTimes|AndReturn)' " |
1729 | - r"member", |
1730 | # pylint doesn't like *args/**kwargs |
1731 | r"Instance of 'Popen' has no '.*' member", |
1732 | )] |
1733 | |
1734 | === modified file 'ubuntutools/test/test_update_maintainer.py' |
1735 | --- ubuntutools/test/test_update_maintainer.py 2013-03-18 23:18:02 +0000 |
1736 | +++ ubuntutools/test/test_update_maintainer.py 2014-12-19 22:54:27 +0000 |
1737 | @@ -16,12 +16,19 @@ |
1738 | |
1739 | """Test suite for ubuntutools.update_maintainer""" |
1740 | |
1741 | -import __builtin__ |
1742 | +try: |
1743 | + import builtins |
1744 | +except ImportError: |
1745 | + import __builtin__ |
1746 | +try: |
1747 | + from StringIO import StringIO |
1748 | +except: |
1749 | + from io import StringIO |
1750 | + |
1751 | import os |
1752 | -import StringIO |
1753 | import sys |
1754 | |
1755 | -import mox |
1756 | +import mock |
1757 | |
1758 | from ubuntutools.logger import Logger |
1759 | from ubuntutools.test import unittest |
1760 | @@ -186,7 +193,7 @@ |
1761 | """ |
1762 | |
1763 | #pylint: disable=R0904 |
1764 | -class UpdateMaintainerTestCase(mox.MoxTestBase, unittest.TestCase): |
1765 | +class UpdateMaintainerTestCase(unittest.TestCase): |
1766 | """TestCase object for ubuntutools.update_maintainer""" |
1767 | |
1768 | _directory = "/" |
1769 | @@ -210,18 +217,30 @@ |
1770 | (mode == "r" and self._files[base] is None)): |
1771 | raise IOError("No such file or directory: '%s'" % filename) |
1772 | if mode == "w": |
1773 | - self._files[base] = StringIO.StringIO() |
1774 | + self._files[base] = StringIO() |
1775 | self._files[base].close = lambda: None |
1776 | return self._files[base] |
1777 | |
1778 | #pylint: disable=C0103 |
1779 | def setUp(self): |
1780 | - super(UpdateMaintainerTestCase, self).setUp() |
1781 | - self.mox.stubs.Set(__builtin__, 'open', self._fake_open) |
1782 | - self.mox.stubs.Set(os.path, 'isfile', self._fake_isfile) |
1783 | - self._files["rules"] = StringIO.StringIO(_SIMPLE_RULES) |
1784 | - Logger.stdout = StringIO.StringIO() |
1785 | - Logger.stderr = StringIO.StringIO() |
1786 | + if sys.version_info[0] < 3: |
1787 | + self.assertRegex = self.assertRegexpMatches |
1788 | + m = mock.mock_open() |
1789 | + m.side_effect = self._fake_open |
1790 | + if sys.version_info[0] >= 3: |
1791 | + target = 'builtins.open' |
1792 | + else: |
1793 | + target = '__builtin__.open' |
1794 | + patcher = mock.patch(target, m) |
1795 | + self.addCleanup(patcher.stop) |
1796 | + patcher.start() |
1797 | + m = mock.MagicMock(side_effect=self._fake_isfile) |
1798 | + patcher = mock.patch('os.path.isfile', m) |
1799 | + self.addCleanup(patcher.stop) |
1800 | + patcher.start() |
1801 | + self._files["rules"] = StringIO(_SIMPLE_RULES) |
1802 | + Logger.stdout = StringIO() |
1803 | + Logger.stderr = StringIO() |
1804 | |
1805 | def tearDown(self): |
1806 | self.assertEqual(Logger.stdout.getvalue(), '') |
1807 | @@ -236,8 +255,8 @@ |
1808 | #pylint: enable=C0103 |
1809 | def test_debian_package(self): |
1810 | """Test: Don't update Maintainer field if target is Debian.""" |
1811 | - self._files["changelog"] = StringIO.StringIO(_UNSTABLE_CHANGELOG) |
1812 | - self._files["control"] = StringIO.StringIO(_ABP_CONTROL) |
1813 | + self._files["changelog"] = StringIO(_UNSTABLE_CHANGELOG) |
1814 | + self._files["control"] = StringIO(_ABP_CONTROL) |
1815 | update_maintainer(self._directory) |
1816 | self.assertEqual(self._files["control"].getvalue(), _ABP_CONTROL) |
1817 | |
1818 | @@ -246,52 +265,52 @@ |
1819 | |
1820 | The Maintainer field needs to be update even if |
1821 | XSBC-Original-Maintainer has an @ubuntu.com address.""" |
1822 | - self._files["changelog"] = StringIO.StringIO(_LUCID_CHANGELOG) |
1823 | - self._files["control"] = StringIO.StringIO(_AXIS2C_CONTROL) |
1824 | + self._files["changelog"] = StringIO(_LUCID_CHANGELOG) |
1825 | + self._files["control"] = StringIO(_AXIS2C_CONTROL) |
1826 | update_maintainer(self._directory) |
1827 | self.assertEqual(self._files["control"].getvalue(), _AXIS2C_UPDATED) |
1828 | warnings = Logger.stderr.getvalue().strip() |
1829 | - Logger.stderr = StringIO.StringIO() |
1830 | + Logger.stderr = StringIO() |
1831 | self.assertEqual(len(warnings.splitlines()), 1) |
1832 | - self.assertRegexpMatches(warnings, "Warning: Overwriting original " |
1833 | + self.assertRegex(warnings, "Warning: Overwriting original " |
1834 | "maintainer: Soren Hansen " |
1835 | "<soren@ubuntu.com>") |
1836 | |
1837 | def test_update_maintainer(self): |
1838 | """Test: Update Maintainer field.""" |
1839 | - self._files["changelog"] = StringIO.StringIO(_LUCID_CHANGELOG) |
1840 | - self._files["control"] = StringIO.StringIO(_ABP_CONTROL) |
1841 | + self._files["changelog"] = StringIO(_LUCID_CHANGELOG) |
1842 | + self._files["control"] = StringIO(_ABP_CONTROL) |
1843 | update_maintainer(self._directory) |
1844 | self.assertEqual(self._files["control"].getvalue(), _ABP_UPDATED) |
1845 | |
1846 | def test_update_old_maintainer(self): |
1847 | """Test: Update old MOTU address.""" |
1848 | - self._files["changelog"] = StringIO.StringIO(_UNSTABLE_CHANGELOG) |
1849 | - self._files["control.in"] = StringIO.StringIO(_ABP_OLD_MAINTAINER) |
1850 | + self._files["changelog"] = StringIO(_UNSTABLE_CHANGELOG) |
1851 | + self._files["control.in"] = StringIO(_ABP_OLD_MAINTAINER) |
1852 | update_maintainer(self._directory, True) |
1853 | self.assertEqual(self._files["control.in"].getvalue(), _ABP_UPDATED) |
1854 | |
1855 | def test_comments_in_control(self): |
1856 | """Test: Update Maintainer field in a control file containing |
1857 | comments.""" |
1858 | - self._files["changelog"] = StringIO.StringIO(_LUCID_CHANGELOG) |
1859 | - self._files["control"] = StringIO.StringIO(_SEAHORSE_PLUGINS_CONTROL) |
1860 | + self._files["changelog"] = StringIO(_LUCID_CHANGELOG) |
1861 | + self._files["control"] = StringIO(_SEAHORSE_PLUGINS_CONTROL) |
1862 | update_maintainer(self._directory) |
1863 | self.assertEqual(self._files["control"].getvalue(), |
1864 | _SEAHORSE_PLUGINS_UPDATED) |
1865 | |
1866 | def test_skip_smart_rules(self): |
1867 | """Test: Skip update when XSBC-Original in debian/rules.""" |
1868 | - self._files["changelog"] = StringIO.StringIO(_LUCID_CHANGELOG) |
1869 | - self._files["control"] = StringIO.StringIO(_ABP_CONTROL) |
1870 | - self._files["rules"] = StringIO.StringIO(_COMPLEX_RULES) |
1871 | + self._files["changelog"] = StringIO(_LUCID_CHANGELOG) |
1872 | + self._files["control"] = StringIO(_ABP_CONTROL) |
1873 | + self._files["rules"] = StringIO(_COMPLEX_RULES) |
1874 | update_maintainer(self._directory) |
1875 | self.assertEqual(self._files["control"].getvalue(), _ABP_CONTROL) |
1876 | |
1877 | def test_missing_rules(self): |
1878 | """Test: Skip XSBC-Original test when debian/rules is missing.""" |
1879 | - self._files["changelog"] = StringIO.StringIO(_LUCID_CHANGELOG) |
1880 | - self._files["control"] = StringIO.StringIO(_ABP_CONTROL) |
1881 | + self._files["changelog"] = StringIO(_LUCID_CHANGELOG) |
1882 | + self._files["control"] = StringIO(_ABP_CONTROL) |
1883 | self._files["rules"] = None |
1884 | update_maintainer(self._directory) |
1885 | self.assertEqual(self._files["control"].getvalue(), _ABP_UPDATED) |
1886 | |
1887 | === modified file 'ubuntutools/update_maintainer.py' |
1888 | --- ubuntutools/update_maintainer.py 2013-03-18 23:18:02 +0000 |
1889 | +++ ubuntutools/update_maintainer.py 2014-12-19 22:54:27 +0000 |
1890 | @@ -14,6 +14,8 @@ |
1891 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
1892 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
1893 | |
1894 | +from __future__ import print_function |
1895 | + |
1896 | """This module is for updating the Maintainer field of an Ubuntu package.""" |
1897 | |
1898 | import os |
1899 | @@ -125,7 +127,7 @@ |
1900 | if os.path.isfile(rules_file) and \ |
1901 | 'XSBC-Original-' in open(rules_file).read(): |
1902 | if verbose: |
1903 | - print "XSBC-Original is managed by 'rules' file. Doing nothing." |
1904 | + print("XSBC-Original is managed by 'rules' file. Doing nothing.") |
1905 | control_files = [] |
1906 | |
1907 | return (changelog_file, control_files) |
1908 | @@ -144,7 +146,7 @@ |
1909 | """ |
1910 | try: |
1911 | changelog_file, control_files = _find_files(debian_directory, verbose) |
1912 | - except MaintainerUpdateException, e: |
1913 | + except MaintainerUpdateException as e: |
1914 | Logger.error(str(e)) |
1915 | raise |
1916 | |
1917 | @@ -159,8 +161,8 @@ |
1918 | |
1919 | if original_maintainer.strip().lower() in _PREVIOUS_UBUNTU_MAINTAINER: |
1920 | if verbose: |
1921 | - print "The old maintainer was: %s" % original_maintainer |
1922 | - print "Resetting as: %s" % _UBUNTU_MAINTAINER |
1923 | + print("The old maintainer was: %s" % original_maintainer) |
1924 | + print("Resetting as: %s" % _UBUNTU_MAINTAINER) |
1925 | control.set_maintainer(_UBUNTU_MAINTAINER) |
1926 | control.save() |
1927 | continue |
1928 | @@ -173,7 +175,7 @@ |
1929 | |
1930 | if distribution in ("stable", "testing", "unstable", "experimental"): |
1931 | if verbose: |
1932 | - print "The package targets Debian. Doing nothing." |
1933 | + print("The package targets Debian. Doing nothing.") |
1934 | return |
1935 | |
1936 | if control.get_original_maintainer() is not None: |
1937 | @@ -181,8 +183,8 @@ |
1938 | control.get_original_maintainer()) |
1939 | |
1940 | if verbose: |
1941 | - print "The original maintainer is: %s" % original_maintainer |
1942 | - print "Resetting as: %s" % _UBUNTU_MAINTAINER |
1943 | + print("The original maintainer is: %s" % original_maintainer) |
1944 | + print("Resetting as: %s" % _UBUNTU_MAINTAINER) |
1945 | control.set_original_maintainer(original_maintainer) |
1946 | control.set_maintainer(_UBUNTU_MAINTAINER) |
1947 | control.save() |
1948 | @@ -194,7 +196,7 @@ |
1949 | """Restore the original maintainer""" |
1950 | try: |
1951 | changelog_file, control_files = _find_files(debian_directory, verbose) |
1952 | - except MaintainerUpdateException, e: |
1953 | + except MaintainerUpdateException as e: |
1954 | Logger.error(str(e)) |
1955 | raise |
1956 | |
1957 | @@ -204,7 +206,7 @@ |
1958 | if not orig_maintainer: |
1959 | continue |
1960 | if verbose: |
1961 | - print "Restoring original maintainer: %s" % orig_maintainer |
1962 | + print("Restoring original maintainer: %s" % orig_maintainer) |
1963 | control.set_maintainer(orig_maintainer) |
1964 | control.remove_original_maintainer() |
1965 | control.save() |
I am pondering to land this in vivid (it will take time to go through new) and then make the library available and then continue to port the scripts.