Merge ubuntu-dev-tools:python3 into ubuntu-dev-tools:master

Proposed by Stefano Rivera
Status: Merged
Merged at revision: 434ca8952e4e1ccec6a3891be292d13770cb690f
Proposed branch: ubuntu-dev-tools:python3
Merge into: ubuntu-dev-tools:master
Diff against target: 3322 lines (+410/-855)
51 files modified
backportpackage (+2/-2)
bitesize (+3/-3)
check-mir (+3/-5)
debian/changelog (+8/-0)
debian/control (+8/-45)
debian/copyright (+1/-3)
debian/rules (+1/-1)
dev/null (+0/-116)
enforced-editing-wrapper (+1/-1)
grep-merges (+8/-12)
hugdaylist (+16/-15)
import-bug-from-debian (+7/-15)
merge-changelog (+8/-174)
pbuilder-dist (+6/-6)
pull-debian-debdiff (+4/-4)
pull-lp-source (+11/-10)
pull-uca-source (+4/-4)
requestbackport (+13/-8)
requestsync (+39/-37)
reverse-depends (+12/-12)
seeded-in-ubuntu (+17/-17)
setup.py (+40/-48)
sponsor-patch (+2/-2)
submittodebian (+15/-20)
syncpackage (+21/-22)
ubuntu-build (+39/-38)
ubuntu-iso (+6/-6)
ubuntu-upload-permission (+25/-23)
ubuntutools/archive.py (+11/-29)
ubuntutools/builder.py (+5/-4)
ubuntutools/lp/libsupport.py (+1/-6)
ubuntutools/lp/lpapicache.py (+11/-36)
ubuntutools/misc.py (+3/-5)
ubuntutools/question.py (+8/-15)
ubuntutools/requestsync/lp.py (+0/-2)
ubuntutools/requestsync/mail.py (+9/-14)
ubuntutools/sponsor_patch/bugtask.py (+2/-5)
ubuntutools/sponsor_patch/patch.py (+2/-3)
ubuntutools/sponsor_patch/question.py (+0/-2)
ubuntutools/sponsor_patch/source_package.py (+3/-7)
ubuntutools/sponsor_patch/sponsor_patch.py (+1/-6)
ubuntutools/test/__init__.py (+2/-6)
ubuntutools/test/test_archive.py (+6/-18)
ubuntutools/test/test_config.py (+4/-14)
ubuntutools/test/test_flake8.py (+5/-4)
ubuntutools/test/test_help.py (+4/-2)
ubuntutools/test/test_logger.py (+1/-4)
ubuntutools/test/test_pylint.py (+6/-5)
ubuntutools/test/test_update_maintainer.py (+3/-14)
ubuntutools/update_maintainer.py (+0/-2)
update-maintainer (+3/-3)
Reviewer Review Type Date Requested Status
Mattia Rizzolo Approve
Review via email: mp+372305@code.launchpad.net

Commit message

Port everything to Python 3

Description of the change

This is reviewable by commit.

In general, the pattern is:
1. Add support for Python 3 to core infra.
2. Port individual scripts to Python 3.
3. Cleanup any Python 2 hacks.

The scripts that are easy to test have been tested. But some of the more complex ones haven't been, notably pbuilder-dist and sponsor-patch.

To post a comment you must log in.
Revision history for this message
Mattia Rizzolo (mapreri) wrote :

Notes to self, things to do while/after merging:

* remove "pylint bug: http://www.logilab.org/ticket/46273"
* scottk's commit touches changelog, check gbp dch
* needs a X-Python3-Version >= 3.6

Revision history for this message
Mattia Rizzolo (mapreri) wrote :

This looks like a very thorough porting, thank you!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/404main b/404main
2deleted file mode 100755
3index abfaf62..0000000
4--- a/404main
5+++ /dev/null
6@@ -1,182 +0,0 @@
7-#!/usr/bin/python
8-# -*- coding: utf-8 -*-
9-#
10-# Copyright 2006-2007 (C) Pete Savage <petesavage@ubuntu.com>
11-# Copyright 2007 (C) Siegfried-A. Gevatter <rainct@ubuntu.com>
12-# Copyright 2009 (C) Canonical Ltd. (by Colin Watson <cjwatson@ubuntu.com>)
13-#
14-# ##################################################################
15-#
16-# This program is free software; you can redistribute it and/or
17-# modify it under the terms of the GNU General Public License
18-# as published by the Free Software Foundation; either version 2
19-# of the License, or (at your option) any later version.
20-#
21-# This program is distributed in the hope that it will be useful,
22-# but WITHOUT ANY WARRANTY; without even the implied warranty of
23-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24-# GNU General Public License for more details.
25-#
26-# See file /usr/share/common-licenses/GPL for more details.
27-#
28-# ##################################################################
29-#
30-# This script is used to check if a package and all its build
31-# dependencies are in main or not.
32-
33-import sys
34-
35-import apt_pkg
36-import apt
37-
38-from ubuntutools import subprocess
39-
40-
41-def process_deps(cache, deps):
42- """Takes a list of (build) dependencies and processes it."""
43-
44- for basedep in [d.or_dependencies[0] for d in deps]:
45- if basedep.name not in packages and basedep.name != '':
46- # Check the (build) dependencies recursively
47- find_main(cache, basedep.name)
48-
49-
50-def get_package_version(cache, distro, pack):
51- if pack not in cache:
52- return None
53- for version in (cache[pack].candidate, cache[pack].installed):
54- if not version:
55- continue
56- for origin in version.origins:
57- if origin.archive == distro:
58- return version
59- return None
60-
61-
62-# Cache::CompTypeDeb isn't exposed via python-apt
63-def comp_type_deb(op):
64- ops = ("", "<=", ">=", "<<", ">>", "=", "!=")
65- if (op & 15) < 7:
66- return ops[op & 15]
67- return ""
68-
69-
70-def find_main(cache, pack):
71- """Searches the dependencies and build dependencies of a package recursively
72- to determine if they are all in the 'main' component or not."""
73-
74- global packages
75-
76- if pack in packages:
77- return
78-
79- # Retrieve information about the package
80- version = get_package_version(cache, distro, pack)
81-
82- if not version:
83- packages[pack] = False
84- return
85- elif [origin for origin in version.origins if origin.component == 'main']:
86- packages[pack] = True
87- return
88- else:
89- if pack not in packages:
90- packages[pack] = False
91-
92- # Retrieve package dependencies
93- process_deps(cache, version.dependencies)
94-
95- # Retrieve package build dependencies. There's no handy
96- # attribute on version for this, so unfortunately we have to
97- # do a lot of messing about with apt.
98- deps = []
99- src_records = apt_pkg.SourceRecords()
100- got_src = False
101- while src_records.lookup(version.source_name):
102- if pack in src_records.binaries:
103- got_src = True
104- break
105- if got_src:
106- # pylint: disable=E1101
107- for _, all_deps in src_records.build_depends.iteritems():
108- # pylint: enable=E1101
109- for or_deps in all_deps:
110- base_deps = []
111- for (name, ver, op) in or_deps:
112- # pylint: disable=too-many-function-args
113- base_deps.append(apt.package.BaseDependency(name, op,
114- ver, False))
115- # pylint: enable=too-many-function-args
116- # pylint: disable=no-value-for-parameter
117- deps.append(apt.package.Dependency(base_deps))
118- # pylint: enable=no-value-for-parameter
119-
120- process_deps(cache, deps)
121-
122-
123-def usage(exit_code):
124- print 'Usage: %s <package name> [<distribution>]' % sys.argv[0]
125- sys.exit(exit_code)
126-
127-
128-def main():
129-
130- global packages, distro
131-
132- # Check if the amount of arguments is correct
133- if len(sys.argv) > 1 and sys.argv[1] in ('help', '-h', '--help'):
134- usage(0)
135-
136- if len(sys.argv) < 2 or len(sys.argv) > 3:
137- usage(1)
138-
139- cache = apt.cache.Cache()
140-
141- if len(sys.argv) == 3 and sys.argv[2]:
142- distro = sys.argv[2]
143- if not get_package_version(cache, distro, 'bash'):
144- print u'«%s» is not a valid distribution.' % distro
145- print('Remember that for 404main to work with a certain distribution '
146- 'it must be in your /etc/apt/sources.list file.')
147- sys.exit(1)
148- else:
149- cmd = ['lsb_release', '-cs']
150- process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
151- distro = process.stdout.read().strip('\n')
152-
153- if not get_package_version(cache, distro, sys.argv[1]):
154- print(u"Can't find package «%s» in distribution «%s»." % (sys.argv[1], distro))
155- sys.exit(1)
156-
157- print(u'Checking package «%s» in distribution «%s»...' % (sys.argv[1], distro))
158-
159- find_main(cache, sys.argv[1])
160-
161- # True if everything checked until the point is in main
162- all_in_main = True
163-
164- for package in packages:
165- if not packages[package]:
166- if all_in_main:
167- print 'The following packages aren\'t in main:'
168- all_in_main = False
169- print ' ', package
170-
171- if all_in_main:
172- print((u'Package «%s» and all its dependencies and build dependencies are in main.') %
173- sys.argv[1])
174-
175-
176-if __name__ == '__main__':
177-
178- # Global variable to hold the status of all packages
179- packages = {}
180-
181- # Global variable to hold the target distribution
182- distro = ''
183-
184- try:
185- main()
186- except KeyboardInterrupt:
187- print 'Aborted.'
188- sys.exit(1)
189diff --git a/backportpackage b/backportpackage
190index 1c77350..c8f1ef0 100755
191--- a/backportpackage
192+++ b/backportpackage
193@@ -1,4 +1,4 @@
194-#!/usr/bin/python
195+#!/usr/bin/python3
196 # -*- coding: utf-8 -*-
197 # ##################################################################
198 #
199@@ -22,6 +22,7 @@ import glob
200 import optparse
201 import os
202 import shutil
203+import subprocess
204 import sys
205 import tempfile
206
207@@ -39,7 +40,6 @@ from ubuntutools.logger import Logger
208 from ubuntutools.misc import (system_distribution, vendor_to_distroinfo,
209 codename_to_distribution)
210 from ubuntutools.question import YesNoQuestion
211-from ubuntutools import subprocess
212
213
214 def error(msg):
215diff --git a/bitesize b/bitesize
216index e59bd73..6fd1b47 100755
217--- a/bitesize
218+++ b/bitesize
219@@ -1,4 +1,4 @@
220-#!/usr/bin/python
221+#!/usr/bin/python3
222 """Add 'bitesize' tag to bugs and add a comment."""
223
224 # Copyright (c) 2011 Canonical Ltd.
225@@ -39,7 +39,7 @@ def error_out(msg):
226 def save_entry(entry):
227 try:
228 entry.lp_save()
229- except HTTPError, error:
230+ except HTTPError as error:
231 error_out(error.content)
232
233
234@@ -73,7 +73,7 @@ def main():
235 # check that the new main bug isn't a duplicate
236 try:
237 bug = launchpad.bugs[args[0]]
238- except HTTPError, error:
239+ except HTTPError as error:
240 if error.response.status == 401:
241 error_out("Don't have enough permissions to access bug %s. %s" %
242 (args[0], error.content))
243diff --git a/check-mir b/check-mir
244index 56ef56e..b7ebe83 100755
245--- a/check-mir
246+++ b/check-mir
247@@ -1,4 +1,4 @@
248-#!/usr/bin/python
249+#!/usr/bin/python3
250 #
251 # Check components of build dependencies and warn about universe/multiverse
252 # ones, for a package destined for main/restricted
253@@ -21,8 +21,6 @@
254 # this program; if not, write to the Free Software Foundation, Inc.,
255 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
256
257-from __future__ import print_function
258-
259 import sys
260 import optparse
261 import os.path
262@@ -103,7 +101,7 @@ def check_binary_dependencies(apt_cache, control):
263 print('\nChecking support status of binary dependencies...')
264 while True:
265 try:
266- control.next()
267+ next(control)
268 except StopIteration:
269 break
270
271@@ -141,7 +139,7 @@ def main():
272
273 # get build dependencies from debian/control
274 control = apt.apt_pkg.TagFile(open('debian/control'))
275- control.next()
276+ next(control)
277
278 unsupported_build_deps = check_build_dependencies(apt_cache, control)
279 unsupported_binary_deps = check_binary_dependencies(apt_cache, control)
280diff --git a/debian/changelog b/debian/changelog
281index ea9fb27..719d13a 100644
282--- a/debian/changelog
283+++ b/debian/changelog
284@@ -1,7 +1,15 @@
285 ubuntu-dev-tools (0.173) UNRELEASED; urgency=medium
286
287+ [ Stefano Rivera ]
288 * pull-debian-debdiff: Don't unpack the older source package, it will often
289 use the same directory as the newer one, and break.
290+ * Drop 404main, it's been totally broken for years.
291+ * Use python3-debian's Version class in merge-changelog, to support Python 3.
292+ * Port Python scripts to Python 3, remove python 2 modules.
293+ (Closes: #938740, LP: #1099537)
294+
295+ [ Scott Kitterman ]
296+ * Update requestsync to python3 (Closes: #927147)
297
298 -- Stefano Rivera <stefanor@debian.org> Wed, 04 Sep 2019 16:31:28 -0300
299
300diff --git a/debian/control b/debian/control
301index 0dcfcd8..bf1ebef 100644
302--- a/debian/control
303+++ b/debian/control
304@@ -15,20 +15,10 @@ Build-Depends:
305 libwww-perl,
306 lsb-release,
307 pylint (>= 2),
308- python-all (>= 2.6.5-13~),
309- python-apt (>= 0.7.93~),
310- python-debian (>= 0.1.20~),
311- python-distro-info (>= 0.4~),
312- python-flake8,
313- python-httplib2,
314- python-launchpadlib (>= 1.5.7),
315- python-mock,
316- python-setuptools,
317- python-soappy,
318- python-unittest2,
319 python3-all,
320 python3-apt,
321 python3-debian,
322+ python3-debianbts,
323 python3-distro-info,
324 python3-flake8,
325 python3-httplib2,
326@@ -54,16 +44,13 @@ Depends:
327 distro-info (>= 0.2~),
328 dpkg-dev,
329 lsb-release,
330- python,
331- python-apt (>= 0.7.93~),
332- python-debian (>= 0.1.20~),
333- python-distro-info (>= 0.4~),
334- python-httplib2,
335- python-launchpadlib (>= 1.5.7),
336- python-lazr.restfulclient,
337- python-ubuntutools,
338 python3,
339+ python3-apt,
340+ python3-debian,
341 python3-distro-info,
342+ python3-httplib2,
343+ python3-launchpadlib,
344+ python3-lazr.restfulclient,
345 python3-ubuntutools,
346 sensible-utils,
347 sudo,
348@@ -82,13 +69,12 @@ Recommends:
349 lintian,
350 patch,
351 pbuilder | cowbuilder | sbuild,
352- python-dns,
353- python-soappy,
354+ python3-debianbts,
355+ python3-dns,
356 quilt,
357 reportbug (>= 3.39ubuntu1),
358 ubuntu-keyring | ubuntu-archive-keyring,
359 Suggests:
360- python-simplejson | python (>= 2.7),
361 qemu-user-static,
362 Description: useful tools for Ubuntu developers
363 This is a collection of useful tools that Ubuntu developers use to make their
364@@ -96,8 +82,6 @@ Description: useful tools for Ubuntu developers
365 .
366 Such tools include:
367 .
368- - 404main - used to check what components a package's deps are in, for
369- doing a main inclusion report for example.
370 - backportpackage - helper to test package backports
371 - bitesize - add the 'bitesize' tag to a bug and comment that you are
372 willing to help fix it.
373@@ -139,27 +123,6 @@ Description: useful tools for Ubuntu developers
374 package.
375 - update-maintainer - script to update maintainer field in ubuntu packages.
376
377-Package: python-ubuntutools
378-Architecture: all
379-Section: python
380-Depends:
381- python-debian,
382- python-distro-info,
383- python-httplib2,
384- python-launchpadlib,
385- sensible-utils,
386- ${misc:Depends},
387- ${python:Depends},
388-Breaks:
389- ubuntu-dev-tools (<< 0.154),
390-Replaces:
391- ubuntu-dev-tools (<< 0.154),
392-Description: useful APIs for Ubuntu developer tools — Python 2 library
393- This package ships a collection of APIs, helpers and wrappers used to
394- develop useful utilities for Ubuntu developers.
395- .
396- This package installs the library for Python 2.
397-
398 Package: python3-ubuntutools
399 Architecture: all
400 Section: python
401diff --git a/debian/copyright b/debian/copyright
402index 57105f4..0a5d3df 100644
403--- a/debian/copyright
404+++ b/debian/copyright
405@@ -39,9 +39,7 @@ License: GPL-2
406 On Debian systems, the complete text of the GNU General Public License
407 version 2 can be found in the /usr/share/common-licenses/GPL-2 file.
408
409-Files: 404main
410- doc/404main.1
411- doc/import-bug-from-debian.1
412+Files: doc/import-bug-from-debian.1
413 doc/pbuilder-dist-simple.1
414 doc/pbuilder-dist.1
415 doc/submittodebian.1
416diff --git a/debian/python-ubuntutools.install b/debian/python-ubuntutools.install
417deleted file mode 100644
418index 5ad7ef7..0000000
419--- a/debian/python-ubuntutools.install
420+++ /dev/null
421@@ -1 +0,0 @@
422-/usr/lib/python2.7
423diff --git a/debian/rules b/debian/rules
424index 04fac7a..641186e 100755
425--- a/debian/rules
426+++ b/debian/rules
427@@ -1,4 +1,4 @@
428 #!/usr/bin/make -f
429
430 %:
431- dh $@ --with python2,python3 --buildsystem=pybuild
432+ dh $@ --with python3 --buildsystem=pybuild
433diff --git a/doc/404main.1 b/doc/404main.1
434deleted file mode 100644
435index a1b353a..0000000
436--- a/doc/404main.1
437+++ /dev/null
438@@ -1,29 +0,0 @@
439-.TH 404main 1 "February 17, 2008" "ubuntu-dev-tools"
440-
441-.SH NAME
442-404main \- check if all build dependencies of a package are in main
443-
444-.SH SYNOPSIS
445-\fB404main\fP <\fIpackage name\fP> [<\fIdistribution\fP>]
446-
447-.SH DESCRIPTION
448-\fB404main\fP is a script that can be used to check if a package and
449-all its build dependencies are in Ubuntu's main component or not.
450-
451-.SH CAVEATS
452-\fB404main\fP will take the dependencies and build dependencies of the
453-packages from the distribution you have first in your
454-/etc/apt/sources.list file.
455-.PP
456-Also, because of this the <\fIdistribution\fP> option is NOT trustworthy; if
457-the dependencies changed YOU WILL GET INCORRECT RESULTS.
458-
459-.SH SEE ALSO
460-.BR apt-cache (8)
461-
462-.SH AUTHORS
463-\fB404main\fP was written by Pete Savage <petesavage@ubuntu.com> and
464-this manpage by Siegfried-Angel Gevatter Pujals <rainct@ubuntu.com>.
465-.PP
466-Both are released under the GNU General Public License, version 2 or
467-later.
468diff --git a/enforced-editing-wrapper b/enforced-editing-wrapper
469index 27917f8..36a1b55 100755
470--- a/enforced-editing-wrapper
471+++ b/enforced-editing-wrapper
472@@ -1,4 +1,4 @@
473-#!/usr/bin/python
474+#!/usr/bin/python3
475 #
476 # Copyright (C) 2011, Stefano Rivera <stefanor@ubuntu.com>
477 #
478diff --git a/grep-merges b/grep-merges
479index 3206920..3658a1b 100755
480--- a/grep-merges
481+++ b/grep-merges
482@@ -1,4 +1,4 @@
483-#! /usr/bin/python
484+#! /usr/bin/python3
485 #
486 # grep-merges - search for pending merges from Debian
487 #
488@@ -51,12 +51,12 @@ def main():
489 url = 'https://merges.ubuntu.com/%s.json' % component
490 try:
491 headers, page = Http().request(url)
492- except HttpLib2Error, e:
493- print >> sys.stderr, str(e)
494+ except HttpLib2Error as e:
495+ print(str(e), file=sys.stderr)
496 sys.exit(1)
497 if headers.status != 200:
498- print >> sys.stderr, "%s: %s %s" % (url, headers.status,
499- headers.reason)
500+ print("%s: %s %s" % (url, headers.status, headers.reason),
501+ file=sys.stderr)
502 sys.exit(1)
503
504 for merge in json.loads(page):
505@@ -66,16 +66,12 @@ def main():
506 author = merge['user']
507 if merge.get('uploader'):
508 uploader = '(%s)' % merge['uploader']
509- try:
510- teams = merge['teams']
511- except e:
512- teams = []
513+ teams = merge.get('teams', [])
514
515- pretty_uploader = u'{} {}'.format(author, uploader)
516+ pretty_uploader = '{} {}'.format(author, uploader)
517 if (match is None or match in package or match in author
518 or match in uploader or match in teams):
519- print '%s\t%s' % (package.encode("utf-8"),
520- pretty_uploader.encode("utf-8"))
521+ print('%s\t%s' % (package, pretty_uploader))
522
523
524 if __name__ == '__main__':
525diff --git a/hugdaylist b/hugdaylist
526index 859c8a3..37f531f 100755
527--- a/hugdaylist
528+++ b/hugdaylist
529@@ -1,4 +1,4 @@
530-#!/usr/bin/python
531+#!/usr/bin/python3
532 # -*- coding: utf-8 -*-
533 #
534 # Copyright (C) 2007 Canonical Ltd., Daniel Holbach
535@@ -57,8 +57,8 @@ def check_args():
536
537 # Check that we have an URL.
538 if not args:
539- print >> sys.stderr, "An URL pointing to a Launchpad bug list is " \
540- "required."
541+ print("An URL pointing to a Launchpad bug list is required.",
542+ file=sys.stderr)
543 opt_parser.print_help()
544 sys.exit(1)
545 else:
546@@ -87,24 +87,25 @@ def main():
547 if len(url.split("?", 1)) == 2:
548 # search options not supported, because there is no mapping web ui
549 # options <-> API options
550- print >> sys.stderr, "Options in url are not supported, url: %s" % url
551+ print("Options in url are not supported, url: %s" % url,
552+ file=sys.stderr)
553 sys.exit(1)
554
555 launchpad = None
556 try:
557 launchpad = Launchpad.login_with("ubuntu-dev-tools", 'production')
558- except IOError, error:
559- print error
560+ except IOError as error:
561+ print(error)
562 sys.exit(1)
563
564 api_url = translate_web_api(url, launchpad)
565 try:
566 product = launchpad.load(api_url)
567- except Exception, error:
568+ except Exception as error:
569 response = getattr(error, "response", {})
570 if response.get("status", None) == "404":
571- print >> sys.stderr, ("The URL at '%s' does not appear to be a "
572- "valid url to a product") % url
573+ print(("The URL at '%s' does not appear to be a valid url to a "
574+ "product") % url, file=sys.stderr)
575 sys.exit(1)
576 else:
577 raise
578@@ -112,28 +113,28 @@ def main():
579 bug_list = [b for b in product.searchTasks() if filter_unsolved(b)]
580
581 if not bug_list:
582- print "Bug list of %s is empty." % url
583+ print("Bug list of %s is empty." % url)
584 sys.exit(0)
585 if howmany == -1:
586 howmany = len(bug_list)
587
588- print """
589+ print("""
590 ## ||<rowbgcolor="#CCFFCC"> This task is done || somebody || ||
591 ## ||<rowbgcolor="#FFFFCC"> This task is assigned || somebody || <status> ||
592 ## ||<rowbgcolor="#FFEBBB"> This task isn't || ... || ||
593 ## ||<rowbgcolor="#FFCCCC"> This task is blocked on something || somebody || <explanation> ||
594
595-|| Bug || Subject || Triager ||"""
596+|| Bug || Subject || Triager ||""")
597
598 for i in list(bug_list)[:howmany]:
599 bug = i.bug
600- print '||<rowbgcolor="#FFEBBB"> [%s %s] || %s || ||' % \
601- (bug.web_link, bug.id, bug.title)
602+ print('||<rowbgcolor="#FFEBBB"> [%s %s] || %s || ||'
603+ % (bug.web_link, bug.id, bug.title))
604
605
606 if __name__ == '__main__':
607 try:
608 main()
609 except KeyboardInterrupt:
610- print >> sys.stderr, "Aborted."
611+ print("Aborted.", file=sys.stderr)
612 sys.exit(1)
613diff --git a/import-bug-from-debian b/import-bug-from-debian
614index 8a78e18..e498c11 100755
615--- a/import-bug-from-debian
616+++ b/import-bug-from-debian
617@@ -1,4 +1,4 @@
618-#!/usr/bin/python
619+#!/usr/bin/python3
620 # -*- coding: UTF-8 -*-
621
622 # Copyright © 2009 James Westby <james.westby@ubuntu.com>,
623@@ -33,23 +33,15 @@ from ubuntutools.config import UDTConfig
624 from ubuntutools.logger import Logger
625
626 try:
627- import SOAPpy
628+ import debianbts
629 except ImportError:
630- Logger.error("Please install 'python-soappy' in order to use this utility.")
631+ Logger.error("Please install 'python3-debianbts' in order to use this utility.")
632 sys.exit(1)
633
634
635 def main():
636 bug_re = re.compile(r"bug=(\d+)")
637
638- url = 'http://bugs.debian.org/cgi-bin/soap.cgi'
639- namespace = 'Debbugs/SOAP'
640- debbugs = SOAPpy.SOAPProxy(url, namespace)
641-
642- # debug
643- # debbugs.config.dumpSOAPOut = 1
644- # debbugs.config.dumpSOAPIn = 1
645-
646 parser = OptionParser(usage="%prog [option] bug ...")
647 parser.add_option("-b", "--browserless",
648 help="Don't open the bug in the browser at the end",
649@@ -94,7 +86,7 @@ def main():
650 bug_num = int(bug_num)
651 bug_nums.append(bug_num)
652
653- bugs = debbugs.get_status(*bug_nums)
654+ bugs = debianbts.get_status(*bug_nums)
655
656 if len(bug_nums) > 1:
657 bugs = bugs[0]
658@@ -104,14 +96,14 @@ def main():
659 sys.exit(1)
660
661 for bug in bugs:
662- bug = bug.value
663 ubupackage = package = bug.source
664 if options.package:
665 ubupackage = options.package
666 bug_num = bug.bug_num
667 subject = bug.subject
668- log = debbugs.get_bug_log(bug_num)
669- summary = log[0][0]
670+ summary = bug.summary
671+ log = debianbts.get_bug_log(bug_num)
672+ summary = log[0]['body']
673 target = ubuntu.getSourcePackage(name=ubupackage)
674 if target is None:
675 Logger.error("Source package '%s' is not in Ubuntu. Please specify "
676diff --git a/merge-changelog b/merge-changelog
677index 8ad8983..b2ad12a 100755
678--- a/merge-changelog
679+++ b/merge-changelog
680@@ -1,4 +1,4 @@
681-#!/usr/bin/python
682+#!/usr/bin/python3
683 # -*- coding: utf-8 -*-
684 # Copyright © 2008 Canonical Ltd.
685 # Author: Scott James Remnant <scott at ubuntu.com>.
686@@ -21,15 +21,17 @@
687 import re
688 import sys
689
690+from debian.debian_support import Version
691+
692
693 def usage(exit_code=1):
694- print '''Usage: merge-changelog <left changelog> <right changelog>
695+ print('''Usage: merge-changelog <left changelog> <right changelog>
696
697 merge-changelog takes two changelogs that once shared a common source,
698 merges them back together, and prints the merged result to stdout. This
699 is useful if you need to manually merge a ubuntu package with a new
700 Debian release of the package.
701-'''
702+''')
703 sys.exit(exit_code)
704
705 ########################################################################
706@@ -51,15 +53,15 @@ def merge_changelog(left_changelog, right_changelog):
707 for right_ver, right_text in right_cl:
708 while len(left_cl) and left_cl[0][0] > right_ver:
709 (left_ver, left_text) = left_cl.pop(0)
710- print left_text
711+ print(left_text)
712
713 while len(left_cl) and left_cl[0][0] == right_ver:
714 (left_ver, left_text) = left_cl.pop(0)
715
716- print right_text
717+ print(right_text)
718
719 for _, left_text in left_cl:
720- print left_text
721+ print(left_text)
722
723 return False
724
725@@ -98,174 +100,6 @@ def read_changelog(filename):
726 return entries
727
728
729-########################################################################
730-# Version parsing code
731-########################################################################
732-# Regular expressions make validating things easy
733-VALID_EPOCH = re.compile(r'^[0-9]+$')
734-VALID_UPSTREAM = re.compile(r'^[A-Za-z0-9+:.~-]*$')
735-VALID_REVISION = re.compile(r'^[A-Za-z0-9+.~]+$')
736-
737-# Character comparison table for upstream and revision components
738-CMP_TABLE = "~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+-.:"
739-
740-
741-class Version(object):
742- """Debian version number.
743-
744- This class is designed to be reasonably transparent and allow you
745- to write code like:
746-
747- | s.version >= '1.100-1'
748-
749- The comparison will be done according to Debian rules, so '1.2' will
750- compare lower.
751-
752- Properties:
753- epoch Epoch
754- upstream Upstream version
755- revision Debian/local revision
756- """
757-
758- def __init__(self, ver):
759- """Parse a string or number into the three components."""
760- self.epoch = 0
761- self.upstream = None
762- self.revision = None
763-
764- ver = str(ver)
765- if not len(ver):
766- raise ValueError
767-
768- # Epoch is component before first colon
769- idx = ver.find(":")
770- if idx != -1:
771- self.epoch = ver[:idx]
772- if not len(self.epoch):
773- raise ValueError
774- if not VALID_EPOCH.search(self.epoch):
775- raise ValueError
776- ver = ver[idx+1:]
777-
778- # Revision is component after last hyphen
779- idx = ver.rfind("-")
780- if idx != -1:
781- self.revision = ver[idx+1:]
782- if not len(self.revision):
783- raise ValueError
784- if not VALID_REVISION.search(self.revision):
785- raise ValueError
786- ver = ver[:idx]
787-
788- # Remaining component is upstream
789- self.upstream = ver
790- if not len(self.upstream):
791- raise ValueError
792- if not VALID_UPSTREAM.search(self.upstream):
793- raise ValueError
794-
795- self.epoch = int(self.epoch)
796-
797- def get_without_epoch(self):
798- """Return the version without the epoch."""
799- string = self.upstream
800- if self.revision is not None:
801- string += "-%s" % (self.revision,)
802- return string
803-
804- without_epoch = property(get_without_epoch)
805-
806- def __str__(self):
807- """Return the class as a string for printing."""
808- string = ""
809- if self.epoch > 0:
810- string += "%d:" % (self.epoch,)
811- string += self.upstream
812- if self.revision is not None:
813- string += "-%s" % (self.revision,)
814- return string
815-
816- def __repr__(self):
817- """Return a debugging representation of the object."""
818- return "<%s epoch: %d, upstream: %r, revision: %r>" \
819- % (self.__class__.__name__, self.epoch,
820- self.upstream, self.revision)
821-
822- def __cmp__(self, other):
823- """Compare two Version classes."""
824- other = Version(other)
825-
826- result = cmp(self.epoch, other.epoch)
827- if result != 0:
828- return result
829-
830- result = deb_cmp(self.upstream, other.upstream)
831- if result != 0:
832- return result
833-
834- result = deb_cmp(self.revision or "", other.revision or "")
835- if result != 0:
836- return result
837-
838- return 0
839-
840-
841-def strcut(string, idx, accept):
842- """Cut characters from string that are entirely in accept."""
843- ret = ""
844- while idx < len(string) and string[idx] in accept:
845- ret += string[idx]
846- idx += 1
847-
848- return (ret, idx)
849-
850-
851-def deb_order(string, idx):
852- """Return the comparison order of two characters."""
853- if idx >= len(string):
854- return 0
855- elif string[idx] == "~":
856- return -1
857- else:
858- return CMP_TABLE.index(string[idx])
859-
860-
861-def deb_cmp_str(x, y):
862- """Compare two strings in a deb version."""
863- idx = 0
864- while (idx < len(x)) or (idx < len(y)):
865- result = deb_order(x, idx) - deb_order(y, idx)
866- if result < 0:
867- return -1
868- elif result > 0:
869- return 1
870-
871- idx += 1
872-
873- return 0
874-
875-
876-def deb_cmp(x, y):
877- """Implement the string comparison outlined by Debian policy."""
878- x_idx = y_idx = 0
879- while x_idx < len(x) or y_idx < len(y):
880- # Compare strings
881- (x_str, x_idx) = strcut(x, x_idx, CMP_TABLE)
882- (y_str, y_idx) = strcut(y, y_idx, CMP_TABLE)
883- result = deb_cmp_str(x_str, y_str)
884- if result != 0:
885- return result
886-
887- # Compare numbers
888- (x_str, x_idx) = strcut(x, x_idx, "0123456789")
889- (y_str, y_idx) = strcut(y, y_idx, "0123456789")
890- result = cmp(int(x_str or "0"), int(y_str or "0"))
891- if result != 0:
892- return result
893-
894- return 0
895-
896-
897 def main():
898 if len(sys.argv) > 1 and sys.argv[1] in ('-h', '--help'):
899 usage(0)
900diff --git a/pbuilder-dist b/pbuilder-dist
901index 914f7a1..4fff772 100755
902--- a/pbuilder-dist
903+++ b/pbuilder-dist
904@@ -1,4 +1,4 @@
905-#! /usr/bin/env python
906+#! /usr/bin/python3
907 # -*- coding: utf-8 -*-
908 #
909 # Copyright (C) 2007-2010, Siegfried-A. Gevatter <rainct@ubuntu.com>,
910@@ -30,6 +30,7 @@
911 # that the target distribution is always meant to be Ubuntu Hardy.
912
913 import os
914+import subprocess
915 import sys
916
917 import debian.deb822
918@@ -40,7 +41,6 @@ import ubuntutools.version
919 from ubuntutools.config import UDTConfig
920 from ubuntutools.logger import Logger
921 from ubuntutools.question import YesNoQuestion
922-from ubuntutools import subprocess
923
924
925 class PbuilderDist(object):
926@@ -279,7 +279,7 @@ class PbuilderDist(object):
927 try:
928 codename = debian_info.codename(self.target_distro,
929 default=self.target_distro)
930- except DistroDataOutdated, error:
931+ except DistroDataOutdated as error:
932 Logger.warn(error)
933 if codename in (debian_info.devel(), 'experimental'):
934 self.enable_security = False
935@@ -306,7 +306,7 @@ class PbuilderDist(object):
936 else:
937 try:
938 dev_release = self.target_distro == UbuntuDistroInfo().devel()
939- except DistroDataOutdated, error:
940+ except DistroDataOutdated as error:
941 Logger.warn(error)
942 dev_release = True
943
944@@ -396,7 +396,7 @@ def show_help(exit_code=0):
945
946 Print a help message for pbuilder-dist, and exit with the given code.
947 """
948- print 'See man pbuilder-dist for more information.'
949+ print('See man pbuilder-dist for more information.')
950
951 sys.exit(exit_code)
952
953@@ -498,7 +498,7 @@ def main():
954 if '--debug-echo' not in args:
955 sys.exit(subprocess.call(app.get_command(args)))
956 else:
957- print app.get_command([arg for arg in args if arg != '--debug-echo'])
958+ print(app.get_command([arg for arg in args if arg != '--debug-echo']))
959
960
961 if __name__ == '__main__':
962diff --git a/pull-debian-debdiff b/pull-debian-debdiff
963index 3858dd5..3997cea 100755
964--- a/pull-debian-debdiff
965+++ b/pull-debian-debdiff
966@@ -1,4 +1,4 @@
967-#!/usr/bin/python
968+#!/usr/bin/python3
969 # pull-debian-debdiff - find and download a specific version of a Debian
970 # package and its immediate parent to generate a debdiff.
971 #
972@@ -84,7 +84,7 @@ def main():
973 newpkg = DebianSourcePackage(package, version, mirrors=mirrors)
974 try:
975 newpkg.pull()
976- except DownloadError, e:
977+ except DownloadError as e:
978 Logger.error('Failed to download: %s', str(e))
979 sys.exit(1)
980 newpkg.unpack()
981@@ -101,10 +101,10 @@ def main():
982 oldpkg = DebianSourcePackage(package, oldversion, mirrors=mirrors)
983 try:
984 oldpkg.pull()
985- except DownloadError, e:
986+ except DownloadError as e:
987 Logger.error('Failed to download: %s', str(e))
988 sys.exit(1)
989- print 'file://' + oldpkg.debdiff(newpkg, diffstat=True)
990+ print('file://' + oldpkg.debdiff(newpkg, diffstat=True))
991
992
993 if __name__ == '__main__':
994diff --git a/pull-lp-source b/pull-lp-source
995index 9cb865a..1de837e 100755
996--- a/pull-lp-source
997+++ b/pull-lp-source
998@@ -1,4 +1,4 @@
999-#!/usr/bin/python
1000+#!/usr/bin/python3
1001 #
1002 # pull-lp-source -- pull a source package from Launchpad
1003 # Basic usage: pull-lp-source <source package> [<release>]
1004@@ -26,7 +26,8 @@
1005 import json
1006 import os
1007 import sys
1008-import urllib2
1009+import urllib.error
1010+import urllib.request
1011 from optparse import OptionParser
1012
1013 from distro_info import UbuntuDistroInfo, DistroDataOutdated
1014@@ -49,11 +50,11 @@ def source_package_for(binary, release):
1015 % (release, binary))
1016 data = None
1017 try:
1018- data = json.load(urllib2.urlopen(url))['r']
1019- except urllib2.URLError, e:
1020+ data = json.load(urllib.request.urlopen(url))['r']
1021+ except urllib.error.URLError as e:
1022 Logger.error('Unable to retrieve package information from DDE: '
1023 '%s (%s)', url, str(e))
1024- except ValueError, e:
1025+ except ValueError as e:
1026 Logger.error('Unable to parse JSON response from DDE: '
1027 '%s (%s)', url, str(e))
1028 if not data:
1029@@ -94,7 +95,7 @@ def main():
1030 else:
1031 try:
1032 version = os.getenv('DIST') or ubuntu_info.devel()
1033- except DistroDataOutdated, e:
1034+ except DistroDataOutdated as e:
1035 Logger.warn("%s\nOr specify a distribution.", e)
1036 sys.exit(1)
1037 component = None
1038@@ -104,16 +105,16 @@ def main():
1039 pocket = None
1040 try:
1041 (release, pocket) = split_release_pocket(version, default=None)
1042- except PocketDoesNotExistError, e:
1043+ except PocketDoesNotExistError:
1044 pass
1045 if release in ubuntu_info.all:
1046 archive = Distribution('ubuntu').getArchive()
1047 try:
1048 spph = archive.getSourcePackage(package, release, pocket)
1049- except SeriesNotFoundException, e:
1050+ except SeriesNotFoundException as e:
1051 Logger.error(str(e))
1052 sys.exit(1)
1053- except PackageNotFoundException, e:
1054+ except PackageNotFoundException as e:
1055 source_package = source_package_for(package, release)
1056 if source_package is not None and source_package != package:
1057 try:
1058@@ -135,7 +136,7 @@ def main():
1059 mirrors=[options.ubuntu_mirror])
1060 try:
1061 srcpkg.pull()
1062- except DownloadError, e:
1063+ except DownloadError as e:
1064 Logger.error('Failed to download: %s', str(e))
1065 sys.exit(1)
1066 if not options.download_only:
1067diff --git a/pull-uca-source b/pull-uca-source
1068index 79a60f5..0bd97d2 100755
1069--- a/pull-uca-source
1070+++ b/pull-uca-source
1071@@ -1,4 +1,4 @@
1072-#!/usr/bin/python
1073+#!/usr/bin/python3
1074 #
1075 # pull-uca-source -- pull a source package from Ubuntu Cloud Archive
1076 # Basic usage: pull-uca-source <source package> <openstack release> [version]
1077@@ -118,12 +118,12 @@ def main():
1078 pocket = None
1079 try:
1080 (release, pocket) = split_release_pocket(release, default=None)
1081- except PocketDoesNotExistError, e:
1082+ except PocketDoesNotExistError:
1083 pass
1084
1085 try:
1086 archive = uca.getPPAByName(name="%s-staging" % release)
1087- except NotFound, e:
1088+ except NotFound:
1089 Logger.error('Archive does not exist for Openstack release: %s',
1090 release)
1091 showOpenstackReleases(uca)
1092@@ -143,7 +143,7 @@ def main():
1093
1094 try:
1095 srcpkg.pull()
1096- except DownloadError, e:
1097+ except DownloadError as e:
1098 Logger.error('Failed to download: %s', str(e))
1099 sys.exit(1)
1100 if not options.download_only:
1101diff --git a/requestbackport b/requestbackport
1102index 903bce6..555610d 100755
1103--- a/requestbackport
1104+++ b/requestbackport
1105@@ -1,4 +1,4 @@
1106-#!/usr/bin/python
1107+#!/usr/bin/python3
1108 #
1109 # Copyright (C) 2011, Stefano Rivera <stefanor@ubuntu.com>
1110 #
1111@@ -102,7 +102,12 @@ def check_existing(package, destinations):
1112 Logger.normal("There are existing bug reports that look similar to your "
1113 "request. Please check before continuing:")
1114
1115- for bug in sorted(set(bug_task.bug for bug_task in bugs)):
1116+ by_id = {}
1117+ for bug_task in bugs:
1118+ bug = bug_task.bug
1119+ by_id[bug.id] = bug
1120+
1121+ for id_, bug in sorted(by_id.items()):
1122 Logger.normal(" * LP: #%-7i: %s %s", bug.id, bug.title, bug.web_link)
1123
1124 confirmation_prompt()
1125@@ -123,7 +128,7 @@ def find_rdepends(releases, published_binaries):
1126 except RDependsException:
1127 # Not published? TODO: Check
1128 continue
1129- for relationship, rdeps in raw_rdeps.iteritems():
1130+ for relationship, rdeps in raw_rdeps.items():
1131 for rdep in rdeps:
1132 # Ignore circular deps:
1133 if rdep['Package'] in published_binaries:
1134@@ -134,14 +139,14 @@ def find_rdepends(releases, published_binaries):
1135 intermediate[binpkg][rdep['Package']].append((release, relationship))
1136
1137 output = []
1138- for binpkg, rdeps in intermediate.iteritems():
1139+ for binpkg, rdeps in intermediate.items():
1140 output += ['', binpkg, '-' * len(binpkg)]
1141- for pkg, appearences in rdeps.iteritems():
1142+ for pkg, appearences in rdeps.items():
1143 output += ['* %s' % pkg]
1144 for release, relationship in appearences:
1145 output += [' [ ] %s (%s)' % (release, relationship)]
1146
1147- found_any = sum(len(rdeps) for rdeps in intermediate.itervalues())
1148+ found_any = sum(len(rdeps) for rdeps in intermediate.values())
1149 if found_any:
1150 output = [
1151 "Reverse dependencies:",
1152@@ -168,7 +173,7 @@ def locate_package(package, distribution):
1153 try:
1154 package_spph = archive.getSourcePackage(package, distribution)
1155 return package_spph
1156- except PackageNotFoundException, e:
1157+ except PackageNotFoundException as e:
1158 if pass_ == 'binary':
1159 Logger.error(str(e))
1160 sys.exit(1)
1161@@ -292,7 +297,7 @@ def main():
1162 try:
1163 destinations = determine_destinations(options.source,
1164 options.destination)
1165- except DestinationException, e:
1166+ except DestinationException as e:
1167 Logger.error(str(e))
1168 sys.exit(1)
1169
1170diff --git a/requestsync b/requestsync
1171index 28ff87a..30b5149 100755
1172--- a/requestsync
1173+++ b/requestsync
1174@@ -1,4 +1,4 @@
1175-#!/usr/bin/python
1176+#!/usr/bin/python3
1177 # -*- coding: utf-8 -*-
1178 #
1179 # (C) 2007 Canonical Ltd., Steve Kowalik
1180@@ -97,7 +97,7 @@ def main():
1181 config = UDTConfig(options.no_conf)
1182
1183 if options.deprecated_lp_flag:
1184- print "The --lp flag is now default, ignored."
1185+ print("The --lp flag is now default, ignored.")
1186 if options.email:
1187 options.lpapi = False
1188 else:
1189@@ -115,8 +115,8 @@ def main():
1190 elif options.lpinstance == 'staging':
1191 bug_mail_domain = 'bugs.staging.launchpad.net'
1192 else:
1193- print >> sys.stderr, ('Error: Unknown launchpad instance: %s'
1194- % options.lpinstance)
1195+ print('Error: Unknown launchpad instance: %s' % options.lpinstance,
1196+ file=sys.stderr)
1197 sys.exit(1)
1198
1199 mailserver_host = config.get_value('SMTP_SERVER',
1200@@ -130,8 +130,8 @@ def main():
1201 firstmx = mxlist[0]
1202 mailserver_host = firstmx[1]
1203 except ImportError:
1204- print >> sys.stderr, ('Please install python-dns to support '
1205- 'Launchpad mail server lookup.')
1206+ print('Please install python3-dns to support Launchpad mail '
1207+ 'server lookup.', file=sys.stderr)
1208 sys.exit(1)
1209
1210 mailserver_port = config.get_value('SMTP_PORT', default=25,
1211@@ -167,9 +167,9 @@ def main():
1212 get_ubuntu_delta_changelog,
1213 mail_bug, need_sponsorship)
1214 if not any(x in os.environ for x in ('UBUMAIL', 'DEBEMAIL', 'EMAIL')):
1215- print >> sys.stderr, (
1216- 'E: The environment variable UBUMAIL, DEBEMAIL or EMAIL needs '
1217- 'to be set to let this script mail the sync request.')
1218+ print('E: The environment variable UBUMAIL, DEBEMAIL or EMAIL '
1219+ 'needs to be set to let this script mail the sync request.',
1220+ file=sys.stderr)
1221 sys.exit(1)
1222
1223 newsource = options.newpkg
1224@@ -187,14 +187,15 @@ def main():
1225 else:
1226 ubu_info = UbuntuDistroInfo()
1227 release = ubu_info.devel()
1228- print >> sys.stderr, 'W: Target release missing - assuming %s' % release
1229+ print('W: Target release missing - assuming %s' % release,
1230+ file=sys.stderr)
1231 elif len(args) == 2:
1232 release = args[1]
1233 elif len(args) == 3:
1234 release = args[1]
1235 force_base_version = Version(args[2])
1236 else:
1237- print >> sys.stderr, 'E: Too many arguments.'
1238+ print('E: Too many arguments.', file=sys.stderr)
1239 parser.print_help()
1240 sys.exit(1)
1241
1242@@ -209,12 +210,13 @@ def main():
1243 ubuntu_version = Version('~')
1244 ubuntu_component = None # Set after getting the Debian info
1245 if not newsource:
1246- print("'%s' doesn't exist in 'Ubuntu %s'.\nDo you want to sync a new package?" %
1247- (srcpkg, release))
1248+ print(("'%s' doesn't exist in 'Ubuntu %s'.\n"
1249+ "Do you want to sync a new package?")
1250+ % (srcpkg, release))
1251 confirmation_prompt()
1252 newsource = True
1253- except udtexceptions.SeriesNotFoundException, error:
1254- print >> sys.stderr, "E: %s" % error
1255+ except udtexceptions.SeriesNotFoundException as error:
1256+ print("E: %s" % error, file=sys.stderr)
1257 sys.exit(1)
1258
1259 # Get the requested Debian source package
1260@@ -222,11 +224,11 @@ def main():
1261 debian_srcpkg = get_debian_srcpkg(srcpkg, distro)
1262 debian_version = Version(debian_srcpkg.getVersion())
1263 debian_component = debian_srcpkg.getComponent()
1264- except udtexceptions.PackageNotFoundException, error:
1265- print >> sys.stderr, "E: %s" % error
1266+ except udtexceptions.PackageNotFoundException as error:
1267+ print("E: %s" % error, file=sys.stderr)
1268 sys.exit(1)
1269- except udtexceptions.SeriesNotFoundException, error:
1270- print >> sys.stderr, "E: %s" % error
1271+ except udtexceptions.SeriesNotFoundException as error:
1272+ print("E: %s" % error, file=sys.stderr)
1273 sys.exit(1)
1274
1275 if ubuntu_component is None:
1276@@ -243,18 +245,18 @@ def main():
1277 debian_srcpkg = ubuntutools.requestsync.mail.get_debian_srcpkg(srcpkg, distro)
1278 debian_version = Version(debian_srcpkg.getVersion())
1279 debian_component = debian_srcpkg.getComponent()
1280- except udtexceptions.PackageNotFoundException, error:
1281- print >> sys.stderr, "E: %s" % error
1282+ except udtexceptions.PackageNotFoundException as error:
1283+ print("E: %s" % error, file=sys.stderr)
1284 sys.exit(1)
1285
1286 if ubuntu_version == debian_version:
1287- print >> sys.stderr, ('E: The versions in Debian and Ubuntu are the '
1288- 'same already (%s). Aborting.' % ubuntu_version)
1289+ print('E: The versions in Debian and Ubuntu are the same already '
1290+ '(%s). Aborting.' % ubuntu_version, file=sys.stderr)
1291 sys.exit(1)
1292 if ubuntu_version > debian_version:
1293- print >> sys.stderr, ('E: The version in Ubuntu (%s) is newer than '
1294- 'the version in Debian (%s). Aborting.'
1295- % (ubuntu_version, debian_version))
1296+ print(('E: The version in Ubuntu (%s) is newer than the version in '
1297+ 'Debian (%s). Aborting.')
1298+ % (ubuntu_version, debian_version), file=sys.stderr)
1299 sys.exit(1)
1300
1301 # -s flag not specified - check if we do need sponsorship
1302@@ -262,8 +264,8 @@ def main():
1303 sponsorship = need_sponsorship(srcpkg, ubuntu_component, release)
1304
1305 if not sponsorship and not ffe:
1306- print >> sys.stderr, ('Consider using syncpackage(1) for syncs that '
1307- 'do not require feature freeze exceptions.')
1308+ print('Consider using syncpackage(1) for syncs that do not require '
1309+ 'feature freeze exceptions.', file=sys.stderr)
1310
1311 # Check for existing package reports
1312 if not newsource:
1313@@ -284,8 +286,8 @@ def main():
1314 print('Changes have been made to the package in Ubuntu.\n'
1315 'Please edit the report and give an explanation.\n'
1316 'Not saving the report file will abort the request.')
1317- report += (u'Explanation of the Ubuntu delta and why it can be '
1318- u'dropped:\n%s\n>>> ENTER_EXPLANATION_HERE <<<\n\n'
1319+ report += ('Explanation of the Ubuntu delta and why it can be '
1320+ 'dropped:\n%s\n>>> ENTER_EXPLANATION_HERE <<<\n\n'
1321 % get_ubuntu_delta_changelog(ubuntu_srcpkg))
1322
1323 if ffe:
1324@@ -310,10 +312,10 @@ def main():
1325 changelog = debian_srcpkg.getChangelog(since_version=base_version)
1326 if not changelog:
1327 if not options.missing_changelog_ok:
1328- print >> sys.stderr, ("E: Did not retrieve any changelog entries. "
1329- "Do you need to specify '-C'? "
1330- "Was the package recently uploaded? (check "
1331- "http://packages.debian.org/changelogs/)")
1332+ print("E: Did not retrieve any changelog entries. "
1333+ "Do you need to specify '-C'? "
1334+ "Was the package recently uploaded? (check "
1335+ "http://packages.debian.org/changelogs/)", file=sys.stderr)
1336 sys.exit(1)
1337 else:
1338 need_interaction = True
1339@@ -325,8 +327,8 @@ def main():
1340 title, report = editor.get_report()
1341
1342 if 'XXX FIXME' in report:
1343- print >> sys.stderr, ("E: changelog boilerplate found in report, "
1344- "please manually add changelog when using '-C'")
1345+ print("E: changelog boilerplate found in report, please manually add "
1346+ "changelog when using '-C'", file=sys.stderr)
1347 sys.exit(1)
1348
1349 # bug status and bug subscriber
1350@@ -357,5 +359,5 @@ if __name__ == '__main__':
1351 try:
1352 main()
1353 except KeyboardInterrupt:
1354- print "\nUser abort."
1355+ print("\nUser abort.")
1356 sys.exit(2)
1357diff --git a/reverse-depends b/reverse-depends
1358index 3426539..6b9aeba 100755
1359--- a/reverse-depends
1360+++ b/reverse-depends
1361@@ -1,4 +1,4 @@
1362-#!/usr/bin/python
1363+#!/usr/bin/python3
1364 #
1365 # Copyright (C) 2011, Stefano Rivera <stefanor@ubuntu.com>
1366 #
1367@@ -106,12 +106,12 @@ def main():
1368 sys.exit(1)
1369
1370 def filter_out_fiels(data, fields):
1371- for field in data.keys():
1372+ for field in list(data.keys()):
1373 if field not in fields:
1374 del data[field]
1375
1376 def filter_out_component(data, component):
1377- for field, rdeps in data.items():
1378+ for field, rdeps in list(data.items()):
1379 filtered = [rdep for rdep in rdeps
1380 if rdep['Component'] in component]
1381 if not filtered:
1382@@ -141,7 +141,7 @@ def main():
1383 filter_out_component(result[package], component)
1384
1385 if recursive > 0:
1386- for rdeps in result[package].itervalues():
1387+ for rdeps in result[package].values():
1388 for rdep in rdeps:
1389 build_results(
1390 rdep['Package'], result, fields, component, recursive - 1)
1391@@ -178,7 +178,7 @@ def display_verbose(package, values):
1392 data = values.get(package)
1393 if data:
1394 offset = offset + 1
1395- for rdeps in data.itervalues():
1396+ for rdeps in data.values():
1397 for rdep in rdeps:
1398 print_package(values,
1399 rdep['Package'],
1400@@ -188,13 +188,13 @@ def display_verbose(package, values):
1401
1402 all_archs = set()
1403 # This isn't accurate, but we make up for it by displaying what we found
1404- for data in values.itervalues():
1405- for rdeps in data.itervalues():
1406+ for data in values.values():
1407+ for rdeps in data.values():
1408 for rdep in rdeps:
1409 if 'Architectures' in rdep:
1410 all_archs.update(rdep['Architectures'])
1411
1412- for field, rdeps in values[package].iteritems():
1413+ for field, rdeps in values[package].items():
1414 print_field(field)
1415 rdeps.sort(key=lambda x: x['Package'])
1416 for rdep in rdeps:
1417@@ -202,7 +202,7 @@ def display_verbose(package, values):
1418 rdep['Package'],
1419 rdep.get('Architectures', all_archs),
1420 rdep.get('Dependency'))
1421- print
1422+ print()
1423
1424 if all_archs:
1425 print("Packages without architectures listed are "
1426@@ -212,12 +212,12 @@ def display_verbose(package, values):
1427
1428 def display_consise(values):
1429 result = set()
1430- for data in values.itervalues():
1431- for rdeps in data.itervalues():
1432+ for data in values.values():
1433+ for rdeps in data.values():
1434 for rdep in rdeps:
1435 result.add(rdep['Package'])
1436
1437- print(u'\n'.join(sorted(list(result))))
1438+ print('\n'.join(sorted(list(result))))
1439
1440
1441 if __name__ == '__main__':
1442diff --git a/seeded-in-ubuntu b/seeded-in-ubuntu
1443index 1adc296..7c3b849 100755
1444--- a/seeded-in-ubuntu
1445+++ b/seeded-in-ubuntu
1446@@ -1,4 +1,4 @@
1447-#!/usr/bin/python
1448+#!/usr/bin/python3
1449 #
1450 # Copyright (C) 2011, Stefano Rivera <stefanor@ubuntu.com>
1451 #
1452@@ -20,7 +20,7 @@ import json
1453 import optparse
1454 import os
1455 import time
1456-import urllib
1457+import urllib.request
1458
1459 from ubuntutools.lp.lpapicache import (Distribution, Launchpad,
1460 PackageNotFoundException)
1461@@ -40,12 +40,12 @@ def load_index(url):
1462 or time.time() - os.path.getmtime(fn) > 60 * 60 * 2):
1463 if not os.path.isdir(cachedir):
1464 os.makedirs(cachedir)
1465- urllib.urlretrieve(url, fn)
1466+ urllib.request.urlretrieve(url, fn)
1467
1468 try:
1469 with gzip.open(fn, 'r') as f:
1470 return json.load(f)
1471- except Exception, e:
1472+ except Exception as e:
1473 Logger.error("Unable to parse seed data: %s. "
1474 "Deleting cached data, please try again.",
1475 str(e))
1476@@ -61,7 +61,7 @@ def resolve_binaries(sources):
1477 for source in sources:
1478 try:
1479 spph = archive.getSourcePackage(source)
1480- except PackageNotFoundException, e:
1481+ except PackageNotFoundException as e:
1482 Logger.error(str(e))
1483 continue
1484 binaries[source] = sorted(set(bpph.getPackageName()
1485@@ -75,11 +75,11 @@ def present_on(appearences):
1486 present = collections.defaultdict(set)
1487 for flavor, type_ in appearences:
1488 present[flavor].add(type_)
1489- for flavor, types in present.iteritems():
1490+ for flavor, types in present.items():
1491 if len(types) > 1:
1492 types.discard('supported')
1493 output = [' %s: %s' % (flavor, ', '.join(sorted(types)))
1494- for flavor, types in present.iteritems()]
1495+ for flavor, types in present.items()]
1496 output.sort()
1497 return '\n'.join(output)
1498
1499@@ -88,28 +88,28 @@ def output_binaries(index, binaries):
1500 '''Print binaries found in index'''
1501 for binary in binaries:
1502 if binary in index:
1503- print "%s is seeded in:" % binary
1504- print present_on(index[binary])
1505+ print("%s is seeded in:" % binary)
1506+ print(present_on(index[binary]))
1507 else:
1508- print "%s is not seeded (and may not exist)." % binary
1509+ print("%s is not seeded (and may not exist)." % binary)
1510
1511
1512 def output_by_source(index, by_source):
1513 '''Print binaries found in index. Grouped by source'''
1514- for source, binaries in by_source.iteritems():
1515+ for source, binaries in by_source.items():
1516 seen = False
1517 if not binaries:
1518- print ("Status unknown: No binary packages built by the latest "
1519- "%s.\nTry again using -b and the expected binary packages."
1520- % source)
1521+ print("Status unknown: No binary packages built by the latest "
1522+ "%s.\nTry again using -b and the expected binary packages."
1523+ % source)
1524 continue
1525 for binary in binaries:
1526 if binary in index:
1527 seen = True
1528- print "%s (from %s) is seeded in:" % (binary, source)
1529- print present_on(index[binary])
1530+ print("%s (from %s) is seeded in:" % (binary, source))
1531+ print(present_on(index[binary]))
1532 if not seen:
1533- print "%s's binaries are not seeded." % source
1534+ print("%s's binaries are not seeded." % source)
1535
1536
1537 def main():
1538diff --git a/setup.py b/setup.py
1539index 2136738..98a9b90 100755
1540--- a/setup.py
1541+++ b/setup.py
1542@@ -4,62 +4,54 @@ from setuptools import setup
1543 import glob
1544 import os
1545 import re
1546-import sys
1547-import codecs
1548
1549 # look/set what version we have
1550 changelog = "debian/changelog"
1551 if os.path.exists(changelog):
1552- head = codecs.open(changelog, 'r', 'utf-8', 'replace').readline()
1553+ head = open(changelog, 'r', encoding='utf-8').readline()
1554 match = re.compile(r".*\((.*)\).*").match(head)
1555 if match:
1556 version = match.group(1)
1557
1558-if sys.version_info[0] >= 3:
1559- scripts = [
1560- 'pull-debian-source',
1561- ]
1562- data_files = []
1563-else:
1564- scripts = [
1565- '404main',
1566- 'backportpackage',
1567- 'bitesize',
1568- 'check-mir',
1569- 'check-symbols',
1570- 'dch-repeat',
1571- 'grab-merge',
1572- 'grep-merges',
1573- 'hugdaylist',
1574- 'import-bug-from-debian',
1575- 'merge-changelog',
1576- 'mk-sbuild',
1577- 'pbuilder-dist',
1578- 'pbuilder-dist-simple',
1579- 'pull-debian-debdiff',
1580- 'pull-lp-source',
1581- 'pull-revu-source',
1582- 'pull-uca-source',
1583- 'requestbackport',
1584- 'requestsync',
1585- 'reverse-build-depends',
1586- 'reverse-depends',
1587- 'seeded-in-ubuntu',
1588- 'setup-packaging-environment',
1589- 'sponsor-patch',
1590- 'submittodebian',
1591- 'syncpackage',
1592- 'ubuntu-build',
1593- 'ubuntu-iso',
1594- 'ubuntu-upload-permission',
1595- 'update-maintainer',
1596- ]
1597- data_files = [
1598- ('share/bash-completion/completions', glob.glob("bash_completion/*")),
1599- ('share/man/man1', glob.glob("doc/*.1")),
1600- ('share/man/man5', glob.glob("doc/*.5")),
1601- ('share/ubuntu-dev-tools', ['enforced-editing-wrapper']),
1602- ]
1603+scripts = [
1604+ 'backportpackage',
1605+ 'bitesize',
1606+ 'check-mir',
1607+ 'check-symbols',
1608+ 'dch-repeat',
1609+ 'grab-merge',
1610+ 'grep-merges',
1611+ 'hugdaylist',
1612+ 'import-bug-from-debian',
1613+ 'merge-changelog',
1614+ 'mk-sbuild',
1615+ 'pbuilder-dist',
1616+ 'pbuilder-dist-simple',
1617+ 'pull-debian-debdiff',
1618+ 'pull-debian-source',
1619+ 'pull-lp-source',
1620+ 'pull-revu-source',
1621+ 'pull-uca-source',
1622+ 'requestbackport',
1623+ 'requestsync',
1624+ 'reverse-build-depends',
1625+ 'reverse-depends',
1626+ 'seeded-in-ubuntu',
1627+ 'setup-packaging-environment',
1628+ 'sponsor-patch',
1629+ 'submittodebian',
1630+ 'syncpackage',
1631+ 'ubuntu-build',
1632+ 'ubuntu-iso',
1633+ 'ubuntu-upload-permission',
1634+ 'update-maintainer',
1635+]
1636+data_files = [
1637+ ('share/bash-completion/completions', glob.glob("bash_completion/*")),
1638+ ('share/man/man1', glob.glob("doc/*.1")),
1639+ ('share/man/man5', glob.glob("doc/*.5")),
1640+ ('share/ubuntu-dev-tools', ['enforced-editing-wrapper']),
1641+]
1642
1643 if __name__ == '__main__':
1644 setup(
1645diff --git a/sponsor-patch b/sponsor-patch
1646index 4c6bce9..fe50146 100755
1647--- a/sponsor-patch
1648+++ b/sponsor-patch
1649@@ -1,4 +1,4 @@
1650-#!/usr/bin/python
1651+#!/usr/bin/python3
1652 #
1653 # Copyright (C) 2010-2011, Benjamin Drung <bdrung@ubuntu.com>
1654 #
1655@@ -123,7 +123,7 @@ def main():
1656 options.keyid, options.lpinstance, options.update,
1657 options.upload, workdir)
1658 except KeyboardInterrupt:
1659- print "\nUser abort."
1660+ print("\nUser abort.")
1661 sys.exit(2)
1662 finally:
1663 if options.workdir is None:
1664diff --git a/submittodebian b/submittodebian
1665index edb8626..894e2fd 100755
1666--- a/submittodebian
1667+++ b/submittodebian
1668@@ -1,4 +1,4 @@
1669-#!/usr/bin/python
1670+#!/usr/bin/python3
1671 # -*- coding: utf-8 -*-
1672 #
1673 # submittodebian - tool to submit patches to Debian's BTS
1674@@ -27,22 +27,16 @@ import os
1675 import re
1676 import shutil
1677 import sys
1678+from subprocess import call, check_call, Popen, PIPE
1679 from tempfile import mkdtemp
1680
1681+from debian.changelog import Changelog
1682 from distro_info import UbuntuDistroInfo, DistroDataOutdated
1683
1684 from ubuntutools.config import ubu_email
1685 from ubuntutools.question import YesNoQuestion, EditFile
1686-from ubuntutools.subprocess import call, check_call, Popen, PIPE
1687 from ubuntutools.update_maintainer import update_maintainer, restore_maintainer
1688
1689-try:
1690- from debian.changelog import Changelog
1691-except ImportError:
1692- print(u"This utility requires modules from the «python-debian» package, "
1693- u"which isn't currently installed.")
1694- sys.exit(1)
1695-
1696
1697 def get_most_recent_debian_version(changelog):
1698 for block in changelog:
1699@@ -94,7 +88,7 @@ def gen_debdiff(tmpdir, changelog):
1700 devnull = open('/dev/null', 'w')
1701 diff_cmd = ['bzr', 'diff', '-r', 'tag:' + str(oldver)]
1702 if call(diff_cmd, stdout=devnull, stderr=devnull) == 1:
1703- print "Extracting bzr diff between %s and %s" % (oldver, newver)
1704+ print("Extracting bzr diff between %s and %s" % (oldver, newver))
1705 else:
1706 if oldver.epoch is not None:
1707 oldver = str(oldver)[str(oldver).index(":") + 1:]
1708@@ -107,7 +101,7 @@ def gen_debdiff(tmpdir, changelog):
1709 check_file(olddsc)
1710 check_file(newdsc)
1711
1712- print "Generating debdiff between %s and %s" % (oldver, newver)
1713+ print("Generating debdiff between %s and %s" % (oldver, newver))
1714 diff_cmd = ['debdiff', olddsc, newdsc]
1715
1716 diff = Popen(diff_cmd, stdout=PIPE)
1717@@ -128,15 +122,15 @@ def check_file(fname, critical=True):
1718 else:
1719 if not critical:
1720 return False
1721- print u"Couldn't find «%s».\n" % fname
1722+ print("Couldn't find «%s».\n" % fname)
1723 sys.exit(1)
1724
1725
1726 def submit_bugreport(body, debdiff, deb_version, changelog):
1727 try:
1728 devel = UbuntuDistroInfo().devel()
1729- except DistroDataOutdated, e:
1730- print str(e)
1731+ except DistroDataOutdated as e:
1732+ print(str(e))
1733 devel = ''
1734
1735 if os.path.dirname(sys.argv[0]).startswith('/usr/bin'):
1736@@ -203,10 +197,10 @@ no-cc
1737 #smtptls
1738 """ % email
1739
1740- with file(fn, 'w') as f:
1741+ with open(fn, 'w') as f:
1742 f.write(reportbugrc)
1743
1744- print """\
1745+ print("""\
1746 You have not configured reportbug. Assuming this is the first time you have
1747 used it. Writing a ~/.reportbugrc that will use Debian's mail server, and CC
1748 the bug to you at <%s>
1749@@ -217,7 +211,7 @@ the bug to you at <%s>
1750
1751 If this is not correct, please exit now and edit ~/.reportbugrc or run
1752 reportbug --configure for its configuration wizard.
1753-""" % (email, reportbugrc.strip())
1754+""" % (email, reportbugrc.strip()))
1755
1756 if YesNoQuestion().ask("Continue submitting this bug", "yes") == "no":
1757 sys.exit(1)
1758@@ -230,14 +224,15 @@ def main():
1759 parser.parse_args()
1760
1761 if not os.path.exists('/usr/bin/reportbug'):
1762- print(u"This utility requires the «reportbug» package, which isn't "
1763- u"currently installed.")
1764+ print("This utility requires the «reportbug» package, which isn't "
1765+ "currently installed.")
1766 sys.exit(1)
1767
1768 check_reportbug_config()
1769 changelog_file = (check_file('debian/changelog', critical=False) or
1770 check_file('../debian/changelog'))
1771- changelog = Changelog(file(changelog_file).read())
1772+ with open(changelog_file) as f:
1773+ changelog = Changelog(f.read())
1774
1775 deb_version = get_most_recent_debian_version(changelog)
1776 bug_body = get_bug_body(changelog)
1777diff --git a/syncpackage b/syncpackage
1778index ee48c64..8dc296d 100755
1779--- a/syncpackage
1780+++ b/syncpackage
1781@@ -1,4 +1,4 @@
1782-#!/usr/bin/python
1783+#!/usr/bin/python3
1784 # -*- coding: utf-8 -*-
1785 #
1786 # Copyright (C) 2008-2010 Martin Pitt <martin.pitt@canonical.com>,
1787@@ -20,14 +20,14 @@
1788 #
1789 # ##################################################################
1790
1791-import codecs
1792 import fnmatch
1793 import optparse
1794 import os
1795 import shutil
1796+import subprocess
1797 import sys
1798 import textwrap
1799-import urllib
1800+import urllib.request
1801
1802 from lazr.restfulclient.errors import HTTPError
1803
1804@@ -44,13 +44,12 @@ from ubuntutools.requestsync.mail import (
1805 get_debian_srcpkg as requestsync_mail_get_debian_srcpkg)
1806 from ubuntutools.requestsync.lp import get_debian_srcpkg, get_ubuntu_srcpkg
1807 from ubuntutools.version import Version
1808-from ubuntutools import subprocess
1809
1810
1811 def remove_signature(dscname):
1812 '''Removes the signature from a .dsc file if the .dsc file is signed.'''
1813
1814- dsc_file = open(dscname)
1815+ dsc_file = open(dscname, encoding='utf-8')
1816 if dsc_file.readline().strip() == "-----BEGIN PGP SIGNED MESSAGE-----":
1817 unsigned_file = []
1818 # search until begin of body found
1819@@ -65,7 +64,7 @@ def remove_signature(dscname):
1820 unsigned_file.append(line)
1821
1822 dsc_file.close()
1823- dsc_file = open(dscname, "w")
1824+ dsc_file = open(dscname, "w", encoding='utf-8')
1825 dsc_file.writelines(unsigned_file)
1826 dsc_file.close()
1827
1828@@ -78,7 +77,7 @@ def add_fixed_bugs(changes, bugs):
1829 # Remove duplicates
1830 bugs = set(str(bug) for bug in bugs)
1831
1832- for i in xrange(len(changes)):
1833+ for i in range(len(changes)):
1834 if changes[i].startswith("Launchpad-Bugs-Fixed:"):
1835 bugs.update(changes[i][22:].strip().split(" "))
1836 changes[i] = "Launchpad-Bugs-Fixed: %s" % (" ".join(bugs))
1837@@ -137,7 +136,7 @@ def sync_dsc(src_pkg, debian_dist, release, name, email, bugs, ubuntu_mirror,
1838
1839 try:
1840 src_pkg.pull()
1841- except DownloadError, e:
1842+ except DownloadError as e:
1843 Logger.error('Failed to download: %s', str(e))
1844 sys.exit(1)
1845 src_pkg.unpack()
1846@@ -158,7 +157,7 @@ def sync_dsc(src_pkg, debian_dist, release, name, email, bugs, ubuntu_mirror,
1847 # Download Ubuntu files (override Debian source tarballs)
1848 try:
1849 ubu_pkg.pull()
1850- except DownloadError, e:
1851+ except DownloadError as e:
1852 Logger.error('Failed to download: %s', str(e))
1853 sys.exit(1)
1854
1855@@ -169,7 +168,7 @@ def sync_dsc(src_pkg, debian_dist, release, name, email, bugs, ubuntu_mirror,
1856
1857 # read Debian distribution from debian/changelog if not specified
1858 if debian_dist is None:
1859- line = open("debian/changelog").readline()
1860+ line = open("debian/changelog", encoding='utf-8').readline()
1861 debian_dist = line.split(" ")[2].strip(";")
1862
1863 if not fakesync:
1864@@ -187,8 +186,7 @@ def sync_dsc(src_pkg, debian_dist, release, name, email, bugs, ubuntu_mirror,
1865 if not Logger.verbose:
1866 cmd += ["-q"]
1867 Logger.command(cmd + ['>', '../' + changes_filename])
1868- process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
1869- changes = process.communicate()[0]
1870+ changes = subprocess.check_output(cmd, encoding='utf-8')
1871
1872 # Add additional bug numbers
1873 if len(bugs) > 0:
1874@@ -200,7 +198,7 @@ def sync_dsc(src_pkg, debian_dist, release, name, email, bugs, ubuntu_mirror,
1875 shutil.rmtree(directory, True)
1876
1877 # write changes file
1878- changes_file = open(changes_filename, "w")
1879+ changes_file = open(changes_filename, "w", encoding='utf-8')
1880 changes_file.writelines(changes)
1881 changes_file.close()
1882
1883@@ -274,7 +272,7 @@ def fetch_source_pkg(package, dist, version, component, ubuntu_release,
1884 try:
1885 debian_srcpkg = get_debian_srcpkg(package, dist)
1886 except (udtexceptions.PackageNotFoundException,
1887- udtexceptions.SeriesNotFoundException), e:
1888+ udtexceptions.SeriesNotFoundException) as e:
1889 Logger.error(str(e))
1890 sys.exit(1)
1891 if version is None:
1892@@ -286,7 +284,7 @@ def fetch_source_pkg(package, dist, version, component, ubuntu_release,
1893 ubuntu_version = Version(ubuntu_srcpkg.getVersion())
1894 except udtexceptions.PackageNotFoundException:
1895 ubuntu_version = Version('~')
1896- except udtexceptions.SeriesNotFoundException, e:
1897+ except udtexceptions.SeriesNotFoundException as e:
1898 Logger.error(str(e))
1899 sys.exit(1)
1900 if ubuntu_version >= version:
1901@@ -388,7 +386,7 @@ def copy(src_pkg, release, bugs, sponsoree=None, simulate=False, force=False):
1902 to_pocket=ubuntu_pocket,
1903 include_binaries=False,
1904 sponsored=sponsoree)
1905- except HTTPError, error:
1906+ except HTTPError as error:
1907 Logger.error("HTTP Error %s: %s", error.response.status,
1908 error.response.reason)
1909 Logger.error(error.content)
1910@@ -416,7 +414,7 @@ def is_blacklisted(query):
1911 series = Launchpad.distributions['ubuntu'].current_series
1912 lp_comments = series.getDifferenceComments(source_package_name=query)
1913 blacklisted = False
1914- comments = [u'%s\n -- %s %s'
1915+ comments = ['%s\n -- %s %s'
1916 % (c.body_text, c.comment_author.name,
1917 c.comment_date.strftime('%a, %d %b %Y %H:%M:%S +0000'))
1918 for c in lp_comments]
1919@@ -430,9 +428,10 @@ def is_blacklisted(query):
1920
1921 # Old blacklist:
1922 url = 'http://people.canonical.com/~ubuntu-archive/sync-blacklist.txt'
1923- with codecs.EncodedFile(urllib.urlopen(url), 'UTF-8') as f:
1924+ with urllib.request.urlopen(url) as f:
1925 applicable_lines = []
1926 for line in f:
1927+ line = line.decode('utf-8')
1928 if not line.strip():
1929 applicable_lines = []
1930 continue
1931@@ -475,7 +474,7 @@ def close_bugs(bugs, package, version, changes, sponsoree):
1932 bug.newMessage(content=message)
1933 break
1934 else:
1935- Logger.error(u"Cannot find any tasks on LP: #%i to close.", bug.id)
1936+ Logger.error("Cannot find any tasks on LP: #%i to close.", bug.id)
1937
1938
1939 def parse():
1940@@ -686,9 +685,9 @@ def main():
1941 "reasoning and subscribe ~ubuntu-archive."]
1942
1943 if blacklist_fail:
1944- Logger.error(u"Source package %s is blacklisted.", src_pkg.source)
1945+ Logger.error("Source package %s is blacklisted.", src_pkg.source)
1946 elif blacklisted == 'ALWAYS':
1947- Logger.normal(u"Source package %s is blacklisted.", src_pkg.source)
1948+ Logger.normal("Source package %s is blacklisted.", src_pkg.source)
1949 if messages:
1950 for message in messages:
1951 for line in textwrap.wrap(message):
1952@@ -698,7 +697,7 @@ def main():
1953 Logger.normal("Blacklist Comments:")
1954 for comment in comments:
1955 for line in textwrap.wrap(comment):
1956- Logger.normal(u" " + line)
1957+ Logger.normal(" " + line)
1958
1959 if blacklist_fail:
1960 sys.exit(1)
1961diff --git a/ubuntu-build b/ubuntu-build
1962index 8a70862..660f895 100755
1963--- a/ubuntu-build
1964+++ b/ubuntu-build
1965@@ -1,4 +1,4 @@
1966-#!/usr/bin/python
1967+#!/usr/bin/python3
1968 #
1969 # ubuntu-build - command line interface for Launchpad buildd operations.
1970 #
1971@@ -108,15 +108,15 @@ def main():
1972
1973 # Check our operation.
1974 if op not in ("rescore", "retry", "status"):
1975- print >> sys.stderr, "Invalid operation: %s." % op
1976+ print("Invalid operation: %s." % op, file=sys.stderr)
1977 sys.exit(1)
1978
1979 # If the user has specified an architecture to build, we only wish to
1980 # rebuild it and nothing else.
1981 if options.architecture:
1982 if options.architecture[0] not in valid_archs:
1983- print >> sys.stderr, ("Invalid architecture specified: %s."
1984- % options.architecture[0])
1985+ print("Invalid architecture specified: %s."
1986+ % options.architecture[0], file=sys.stderr)
1987 sys.exit(1)
1988 else:
1989 one_arch = True
1990@@ -126,8 +126,8 @@ def main():
1991 # split release and pocket
1992 try:
1993 (release, pocket) = split_release_pocket(release)
1994- except PocketDoesNotExistError, error:
1995- print 'E: %s' % error
1996+ except PocketDoesNotExistError as error:
1997+ print('E: %s' % error)
1998 sys.exit(1)
1999
2000 # Get the ubuntu archive
2001@@ -140,8 +140,8 @@ def main():
2002 try:
2003 sources = ubuntu_archive.getSourcePackage(package, release, pocket)
2004 distroseries = Distribution('ubuntu').getSeries(release)
2005- except (SeriesNotFoundException, PackageNotFoundException), error:
2006- print error
2007+ except (SeriesNotFoundException, PackageNotFoundException) as error:
2008+ print(error)
2009 sys.exit(1)
2010 # Get list of builds for that package.
2011 builds = sources.getBuilds()
2012@@ -163,16 +163,16 @@ def main():
2013 pocket=pocket)
2014
2015 if op in ('rescore', 'retry') and not necessary_privs:
2016- print >> sys.stderr, ("You cannot perform the %s operation on a %s "
2017- "package as you do not have the permissions "
2018- "to do this action." % (op, component))
2019+ print(("You cannot perform the %s operation on a %s package as "
2020+ "you do not have the permissions to do this action.")
2021+ % (op, component), file=sys.stderr)
2022 sys.exit(1)
2023
2024 # Output details.
2025- print("The source version for '%s' in %s (%s) is at %s." %
2026- (package, release.capitalize(), component, version))
2027+ print("The source version for '%s' in %s (%s) is at %s."
2028+ % (package, release.capitalize(), component, version))
2029
2030- print "Current build status for this package:"
2031+ print("Current build status for this package:")
2032
2033 # Output list of arches for package and their status.
2034 done = False
2035@@ -182,28 +182,29 @@ def main():
2036 continue
2037
2038 done = True
2039- print "%s: %s." % (build.arch_tag, build.buildstate)
2040+ print("%s: %s." % (build.arch_tag, build.buildstate))
2041 if op == 'rescore':
2042 if build.can_be_rescored:
2043 # FIXME: make priority an option
2044 priority = 5000
2045- print 'Rescoring build %s to %d...' % (build.arch_tag, priority)
2046+ print('Rescoring build %s to %d...'
2047+ % (build.arch_tag, priority))
2048 build.rescore(score=priority)
2049 else:
2050- print 'Cannot rescore build on %s.' % build.arch_tag
2051+ print('Cannot rescore build on %s.' % build.arch_tag)
2052 if op == 'retry':
2053 if build.can_be_retried:
2054- print 'Retrying build on %s...' % build.arch_tag
2055+ print('Retrying build on %s...' % build.arch_tag)
2056 build.retry()
2057 else:
2058- print 'Cannot retry build on %s.' % build.arch_tag
2059+ print('Cannot retry build on %s.' % build.arch_tag)
2060
2061 # We are done
2062 if done:
2063 sys.exit(0)
2064
2065- print("No builds for '%s' found in the %s release - it may have been "
2066- "built in a former release." % (package, release.capitalize()))
2067+ print(("No builds for '%s' found in the %s release - it may have been "
2068+ "built in a former release.") % (package, release.capitalize()))
2069 sys.exit(0)
2070
2071 # Batch mode
2072@@ -223,15 +224,15 @@ def main():
2073 + '-proposed')
2074 try:
2075 (release, pocket) = split_release_pocket(release)
2076- except PocketDoesNotExistError, error:
2077- print 'E: %s' % error
2078+ except PocketDoesNotExistError as error:
2079+ print('E: %s' % error)
2080 sys.exit(1)
2081
2082 ubuntu_archive = Distribution('ubuntu').getArchive()
2083 try:
2084 distroseries = Distribution('ubuntu').getSeries(release)
2085- except SeriesNotFoundException, error:
2086- print error
2087+ except SeriesNotFoundException as error:
2088+ print(error)
2089 sys.exit(1)
2090 me = PersonTeam.me
2091
2092@@ -240,14 +241,14 @@ def main():
2093 and me.isLpTeamMember('launchpad-buildd-admins'))
2094 or False)
2095 if options.priority and not can_rescore:
2096- print >> sys.stderr, ("You don't have the permissions to rescore "
2097- "builds. Ignoring your rescore request.")
2098+ print("You don't have the permissions to rescore builds. "
2099+ "Ignoring your rescore request.", file=sys.stderr)
2100
2101 for pkg in args:
2102 try:
2103 pkg = ubuntu_archive.getSourcePackage(pkg, release, pocket)
2104- except PackageNotFoundException, error:
2105- print error
2106+ except PackageNotFoundException as error:
2107+ print(error)
2108 continue
2109
2110 # Check permissions (part 2): check upload permissions for the source
2111@@ -257,20 +258,20 @@ def main():
2112 pkg.getPackageName(),
2113 pkg.getComponent())
2114 if options.retry and not can_retry:
2115- print >> sys.stderr, ("You don't have the permissions to retry the "
2116- "build of '%s'. Ignoring your request."
2117- % pkg.getPackageName())
2118+ print(("You don't have the permissions to retry the build of "
2119+ "'%s'. Ignoring your request.")
2120+ % pkg.getPackageName(), file=sys.stderr)
2121
2122- print "The source version for '%s' in '%s' (%s) is: %s" % (
2123- pkg.getPackageName(), release, pocket, pkg.getVersion())
2124+ print("The source version for '%s' in '%s' (%s) is: %s"
2125+ % (pkg.getPackageName(), release, pocket, pkg.getVersion()))
2126
2127- print pkg.getBuildStates(archs)
2128+ print(pkg.getBuildStates(archs))
2129 if can_retry:
2130- print pkg.retryBuilds(archs)
2131+ print(pkg.retryBuilds(archs))
2132 if options.priority and can_rescore:
2133- print pkg.rescoreBuilds(archs, options.priority)
2134+ print(pkg.rescoreBuilds(archs, options.priority))
2135
2136- print ''
2137+ print()
2138
2139
2140 if __name__ == '__main__':
2141diff --git a/ubuntu-iso b/ubuntu-iso
2142index f79b213..dc52bac 100755
2143--- a/ubuntu-iso
2144+++ b/ubuntu-iso
2145@@ -1,4 +1,4 @@
2146-#!/usr/bin/python
2147+#!/usr/bin/python3
2148
2149 # ubuntuiso - tool to examine Ubuntu CD (ISO) installation media
2150 # Copyright (C) 2008 Canonical Ltd.
2151@@ -21,15 +21,14 @@
2152 # ##################################################################
2153
2154 import optparse
2155+import subprocess
2156 import sys
2157
2158-from ubuntutools import subprocess
2159-
2160
2161 def extract(iso, path):
2162 command = ['isoinfo', '-R', '-i', iso, '-x', path]
2163 pipe = subprocess.Popen(command, stdout=subprocess.PIPE,
2164- stderr=subprocess.PIPE)
2165+ stderr=subprocess.PIPE, encoding='utf-8')
2166 stdout, stderr = pipe.communicate()
2167
2168 if pipe.returncode != 0:
2169@@ -55,11 +54,12 @@ def main():
2170 version = extract(iso, '/.disk/info')
2171
2172 if len(version) == 0:
2173- print >> sys.stderr, '%s does not appear to be an Ubuntu ISO' % iso
2174+ print('%s does not appear to be an Ubuntu ISO' % iso,
2175+ file=sys.stderr)
2176 err = True
2177 continue
2178
2179- print prefix + version
2180+ print(prefix + version)
2181
2182 if err:
2183 sys.exit(1)
2184diff --git a/ubuntu-upload-permission b/ubuntu-upload-permission
2185index 1c4c20e..2099134 100755
2186--- a/ubuntu-upload-permission
2187+++ b/ubuntu-upload-permission
2188@@ -1,4 +1,4 @@
2189-#!/usr/bin/python
2190+#!/usr/bin/python3
2191 #
2192 # Copyright (C) 2011, Stefano Rivera <stefanor@ubuntu.com>
2193 #
2194@@ -62,13 +62,13 @@ def main():
2195 try:
2196 release, pocket = split_release_pocket(options.release)
2197 series = ubuntu.getSeries(release)
2198- except SeriesNotFoundException, e:
2199+ except SeriesNotFoundException as e:
2200 Logger.error(str(e))
2201 sys.exit(2)
2202
2203 try:
2204 spph = archive.getSourcePackage(package)
2205- except PackageNotFoundException, e:
2206+ except PackageNotFoundException as e:
2207 Logger.error(str(e))
2208 sys.exit(2)
2209 component = spph.getComponent()
2210@@ -77,44 +77,46 @@ def main():
2211
2212 component_uploader = archive.getUploadersForComponent(
2213 component_name=component)[0]
2214- print "All upload permissions for %s:" % package
2215- print
2216- print "Component (%s)" % component
2217- print "============" + ("=" * len(component))
2218+ print("All upload permissions for %s:" % package)
2219+ print()
2220+ print("Component (%s)" % component)
2221+ print("============" + ("=" * len(component)))
2222 print_uploaders([component_uploader], options.list_team_members)
2223
2224 packagesets = sorted(Packageset.setsIncludingSource(
2225 distroseries=series,
2226 sourcepackagename=package))
2227 if packagesets:
2228- print
2229- print "Packagesets"
2230- print "==========="
2231+ print()
2232+ print("Packagesets")
2233+ print("===========")
2234 for packageset in packagesets:
2235- print
2236- print "%s:" % packageset.name
2237+ print()
2238+ print("%s:" % packageset.name)
2239 print_uploaders(archive.getUploadersForPackageset(
2240 packageset=packageset), options.list_team_members)
2241
2242 ppu_uploaders = archive.getUploadersForPackage(
2243 source_package_name=package)
2244 if ppu_uploaders:
2245- print
2246- print "Per-Package-Uploaders"
2247- print "====================="
2248- print
2249+ print()
2250+ print("Per-Package-Uploaders")
2251+ print("=====================")
2252+ print()
2253 print_uploaders(ppu_uploaders, options.list_team_members)
2254- print
2255+ print()
2256
2257 if PersonTeam.me.canUploadPackage(archive, series, package, component,
2258 pocket):
2259- print "You can upload %s to %s." % (package, options.release)
2260+ print("You can upload %s to %s." % (package, options.release))
2261 else:
2262- print("You can not upload %s to %s, yourself." % (package, options.release))
2263+ print("You can not upload %s to %s, yourself."
2264+ % (package, options.release))
2265 if (series.status in ('Current Stable Release', 'Supported', 'Obsolete')
2266 and pocket == 'Release'):
2267- print("%s is in the '%s' state. You may want to query the %s-proposed pocket." %
2268- (release, series.status, release))
2269+ print(("%s is in the '%s' state. You may want to query the "
2270+ "%s-proposed pocket.")
2271+ % (release, series.status, release))
2272 else:
2273 print("But you can still contribute to it via the sponsorship "
2274 "process: https://wiki.ubuntu.com/SponsorshipProcess")
2275@@ -131,9 +133,9 @@ def print_uploaders(uploaders, expand_teams=False, prefix=''):
2276 recursion.
2277 """
2278 for uploader in sorted(uploaders, key=lambda p: p.display_name):
2279- print("%s* %s (%s)%s" %
2280+ print(("%s* %s (%s)%s" %
2281 (prefix, uploader.display_name, uploader.name,
2282- ' [team]' if uploader.is_team else ''))
2283+ ' [team]' if uploader.is_team else '')))
2284 if expand_teams and uploader.is_team:
2285 print_uploaders(uploader.participants, True, prefix=prefix + ' ')
2286
2287diff --git a/ubuntutools/archive.py b/ubuntutools/archive.py
2288index 9237bca..b271db7 100644
2289--- a/ubuntutools/archive.py
2290+++ b/ubuntutools/archive.py
2291@@ -27,19 +27,15 @@ Approach:
2292 3. Verify checksums.
2293 """
2294
2295-from __future__ import with_statement, print_function
2296-
2297+from urllib.error import URLError, HTTPError
2298+from urllib.parse import urlparse
2299+from urllib.request import ProxyHandler, build_opener, urlopen
2300 import codecs
2301 import hashlib
2302+import json
2303 import os.path
2304-try:
2305- from urllib.request import ProxyHandler, build_opener, urlopen
2306- from urllib.parse import urlparse
2307- from urllib.error import URLError, HTTPError
2308-except ImportError:
2309- from urllib2 import ProxyHandler, build_opener, urlopen, URLError, HTTPError
2310- from urlparse import urlparse
2311 import re
2312+import subprocess
2313 import sys
2314
2315 from debian.changelog import Changelog, Version
2316@@ -51,11 +47,6 @@ from ubuntutools.config import UDTConfig
2317 from ubuntutools.lp.lpapicache import (Launchpad, Distribution,
2318 SourcePackagePublishingHistory)
2319 from ubuntutools.logger import Logger
2320-from ubuntutools import subprocess
2321-
2322-if sys.version_info[0] >= 3:
2323- basestring = str
2324- unicode = str
2325
2326
2327 class DownloadError(Exception):
2328@@ -496,15 +487,6 @@ class DebianSourcePackage(SourcePackage):
2329 def snapshot_list(self):
2330 "Return a filename -> hash dictionary from snapshot.debian.org"
2331 if self._snapshot_list is None:
2332- try:
2333- import json
2334- except ImportError:
2335- import simplejson as json
2336- except ImportError:
2337- Logger.error("Please install python-simplejson.")
2338- raise DownloadError("Unable to dowload from "
2339- "snapshot.debian.org without "
2340- "python-simplejson")
2341
2342 try:
2343 data = self.url_opener.open(
2344@@ -601,15 +583,15 @@ class FakeSPPH(object):
2345 if since_version is None:
2346 return self._changelog
2347
2348- if isinstance(since_version, basestring):
2349+ if isinstance(since_version, str):
2350 since_version = Version(since_version)
2351
2352 new_entries = []
2353 for block in Changelog(self._changelog):
2354 if block.version <= since_version:
2355 break
2356- new_entries.append(unicode(block))
2357- return u''.join(new_entries)
2358+ new_entries.append(str(block))
2359+ return ''.join(new_entries)
2360
2361
2362 def rmadison(url, package, suite=None, arch=None):
2363@@ -620,8 +602,8 @@ def rmadison(url, package, suite=None, arch=None):
2364 if arch:
2365 cmd += ['-a', arch]
2366 cmd.append(package)
2367- process = subprocess.Popen(cmd, stdout=subprocess.PIPE,
2368- stderr=subprocess.PIPE, close_fds=True)
2369+ process = subprocess.Popen(
2370+ cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='utf-8')
2371 output, error_output = process.communicate()
2372 if process.wait() != 0:
2373 if error_output:
2374@@ -636,7 +618,7 @@ def rmadison(url, package, suite=None, arch=None):
2375
2376 # pylint bug: http://www.logilab.org/ticket/46273
2377 # pylint: disable=E1103
2378- for line in output.decode().strip().splitlines():
2379+ for line in output.strip().splitlines():
2380 # pylint: enable=E1103
2381 pkg, ver, dist, archs = [x.strip() for x in line.split('|')]
2382 comp = 'main'
2383diff --git a/ubuntutools/builder.py b/ubuntutools/builder.py
2384index a9f8e58..4c201d9 100644
2385--- a/ubuntutools/builder.py
2386+++ b/ubuntutools/builder.py
2387@@ -19,9 +19,9 @@
2388 #
2389
2390 import os
2391+import subprocess
2392
2393 from ubuntutools.logger import Logger
2394-from ubuntutools import subprocess
2395
2396
2397 def _build_preparation(result_directory):
2398@@ -34,8 +34,8 @@ class Builder(object):
2399 def __init__(self, name):
2400 self.name = name
2401 cmd = ["dpkg-architecture", "-qDEB_BUILD_ARCH_CPU"]
2402- process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
2403- self.architecture = process.communicate()[0].strip()
2404+ self.architecture = subprocess.check_output(
2405+ cmd, encoding='utf-8').strip()
2406
2407 def _build_failure(self, returncode, dsc_file):
2408 if returncode != 0:
2409@@ -124,7 +124,8 @@ class Sbuild(Builder):
2410 def update(self, dist):
2411 cmd = ["schroot", "--list"]
2412 Logger.command(cmd)
2413- process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
2414+ process = subprocess.Popen(
2415+ cmd, stdout=subprocess.PIPE, encoding='utf-8')
2416 chroots, _ = process.communicate()[0].strip().split()
2417 if process.returncode != 0:
2418 return process.returncode
2419diff --git a/ubuntutools/lp/libsupport.py b/ubuntutools/lp/libsupport.py
2420index 64f3cf4..24b1d3c 100644
2421--- a/ubuntutools/lp/libsupport.py
2422+++ b/ubuntutools/lp/libsupport.py
2423@@ -18,12 +18,7 @@
2424 # the GNU General Public License license.
2425 #
2426
2427-# Modules.
2428-try:
2429- from urllib.parse import urlsplit, urlencode, urlunsplit
2430-except ImportError:
2431- from urllib import urlencode
2432- from urlparse import urlsplit, urlunsplit
2433+from urllib.parse import urlsplit, urlencode, urlunsplit
2434
2435
2436 def query_to_dict(query_string):
2437diff --git a/ubuntutools/lp/lpapicache.py b/ubuntutools/lp/lpapicache.py
2438index 601bea8..11edb15 100644
2439--- a/ubuntutools/lp/lpapicache.py
2440+++ b/ubuntutools/lp/lpapicache.py
2441@@ -21,8 +21,6 @@
2442 #
2443 # Based on code written by Jonathan Davies <jpds@ubuntu.com>
2444
2445-from __future__ import print_function
2446-
2447 # Uncomment for tracing LP API calls
2448 # import httplib2
2449 # httplib2.debuglevel = 1
2450@@ -44,27 +42,6 @@ from ubuntutools.lp.udtexceptions import (AlreadyLoggedInError,
2451 PocketDoesNotExistError,
2452 SeriesNotFoundException)
2453
2454-if sys.version_info[0] >= 3:
2455- basestring = str
2456- unicode = str
2457-
2458-
2459-# Shameless steal from python-six
2460-def add_metaclass(metaclass):
2461- """Class decorator for creating a class with a metaclass."""
2462- def wrapper(cls):
2463- orig_vars = cls.__dict__.copy()
2464- slots = orig_vars.get('__slots__')
2465- if slots is not None:
2466- if isinstance(slots, str):
2467- slots = [slots]
2468- for slots_var in slots:
2469- orig_vars.pop(slots_var)
2470- orig_vars.pop('__dict__', None)
2471- orig_vars.pop('__weakref__', None)
2472- return metaclass(cls.__name__, cls.__bases__, orig_vars)
2473- return wrapper
2474-
2475
2476 __all__ = [
2477 'Archive',
2478@@ -140,15 +117,14 @@ class MetaWrapper(type):
2479 cls._cache = dict()
2480
2481
2482-@add_metaclass(MetaWrapper)
2483-class BaseWrapper(object):
2484+class BaseWrapper(object, metaclass=MetaWrapper):
2485 '''
2486 A base class from which other wrapper classes are derived.
2487 '''
2488 resource_type = None # it's a base class after all
2489
2490 def __new__(cls, data):
2491- if isinstance(data, basestring) and data.startswith(str(Launchpad._root_uri)):
2492+ if isinstance(data, str) and data.startswith(str(Launchpad._root_uri)):
2493 # looks like a LP API URL
2494 # check if it's already cached
2495 cached = cls._cache.get(data)
2496@@ -225,7 +201,7 @@ class Distribution(BaseWrapper):
2497 '''
2498 Fetch the distribution object identified by 'dist' from LP.
2499 '''
2500- if not isinstance(dist, basestring):
2501+ if not isinstance(dist, str):
2502 raise TypeError("Don't know what do with '%r'" % dist)
2503 cached = cls._cache.get(dist)
2504 if not cached:
2505@@ -385,7 +361,7 @@ class Archive(BaseWrapper):
2506 '''
2507 if pocket is None:
2508 pockets = frozenset(('Proposed', 'Updates', 'Security', 'Release'))
2509- elif isinstance(pocket, basestring):
2510+ elif isinstance(pocket, str):
2511 pockets = frozenset((pocket,))
2512 else:
2513 pockets = frozenset(pocket)
2514@@ -593,15 +569,15 @@ class SourcePackagePublishingHistory(BaseWrapper):
2515 if since_version is None:
2516 return self._changelog
2517
2518- if isinstance(since_version, basestring):
2519+ if isinstance(since_version, str):
2520 since_version = Version(since_version)
2521
2522 new_entries = []
2523 for block in Changelog(self._changelog):
2524 if block.version <= since_version:
2525 break
2526- new_entries.append(unicode(block))
2527- return u''.join(new_entries)
2528+ new_entries.append(str(block))
2529+ return ''.join(new_entries)
2530
2531 def getBinaries(self):
2532 '''
2533@@ -719,8 +695,7 @@ class MetaPersonTeam(MetaWrapper):
2534 return cls._me
2535
2536
2537-@add_metaclass(MetaPersonTeam)
2538-class PersonTeam(BaseWrapper):
2539+class PersonTeam(BaseWrapper, metaclass=MetaPersonTeam):
2540 '''
2541 Wrapper class around a LP person or team object.
2542 '''
2543@@ -743,7 +718,7 @@ class PersonTeam(BaseWrapper):
2544 '''
2545 Fetch the person or team object identified by 'url' from LP.
2546 '''
2547- if not isinstance(person_or_team, basestring):
2548+ if not isinstance(person_or_team, str):
2549 raise TypeError("Don't know what do with '%r'" % person_or_team)
2550 cached = cls._cache.get(person_or_team)
2551 if not cached:
2552@@ -771,9 +746,9 @@ class PersonTeam(BaseWrapper):
2553 raise TypeError("'%r' is not an Archive object." % archive)
2554 if not isinstance(distroseries, DistroSeries):
2555 raise TypeError("'%r' is not a DistroSeries object." % distroseries)
2556- if package is not None and not isinstance(package, basestring):
2557+ if package is not None and not isinstance(package, str):
2558 raise TypeError('A source package name expected.')
2559- if component is not None and not isinstance(component, basestring):
2560+ if component is not None and not isinstance(component, str):
2561 raise TypeError('A component name expected.')
2562 if package is None and component is None:
2563 raise ValueError('Either a source package name or a component has '
2564diff --git a/ubuntutools/misc.py b/ubuntutools/misc.py
2565index f61a84a..8409108 100644
2566--- a/ubuntutools/misc.py
2567+++ b/ubuntutools/misc.py
2568@@ -22,9 +22,8 @@
2569 #
2570 # ##################################################################
2571
2572-from __future__ import print_function
2573-
2574 # Modules.
2575+from subprocess import Popen, PIPE
2576 import locale
2577 import os
2578 import sys
2579@@ -32,7 +31,6 @@ import sys
2580 import distro_info
2581
2582 from ubuntutools.lp.udtexceptions import PocketDoesNotExistError
2583-from ubuntutools.subprocess import Popen, PIPE
2584
2585 _system_distribution_chain = []
2586
2587@@ -50,7 +48,7 @@ def system_distribution_chain():
2588 if len(_system_distribution_chain) == 0:
2589 try:
2590 p = Popen(('dpkg-vendor', '--query', 'Vendor'),
2591- stdout=PIPE)
2592+ stdout=PIPE, encoding='utf-8')
2593 _system_distribution_chain.append(p.communicate()[0].strip())
2594 except OSError:
2595 print('Error: Could not determine what distribution you are running.')
2596@@ -61,7 +59,7 @@ def system_distribution_chain():
2597 p = Popen(('dpkg-vendor',
2598 '--vendor', _system_distribution_chain[-1],
2599 '--query', 'Parent'),
2600- stdout=PIPE)
2601+ stdout=PIPE, encoding='utf-8')
2602 parent = p.communicate()[0].strip()
2603 # Don't check return code, because if a vendor has no
2604 # parent, dpkg-vendor returns 1
2605diff --git a/ubuntutools/question.py b/ubuntutools/question.py
2606index 9adbeff..32e3dee 100644
2607--- a/ubuntutools/question.py
2608+++ b/ubuntutools/question.py
2609@@ -16,18 +16,12 @@
2610 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
2611 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2612
2613-from __future__ import print_function
2614-
2615 import tempfile
2616 import os
2617 import re
2618+import subprocess
2619 import sys
2620
2621-import ubuntutools.subprocess
2622-
2623-if sys.version_info[0] < 3:
2624- input = raw_input # noqa, pylint: disable=undefined-variable
2625-
2626
2627 class Question(object):
2628 def __init__(self, options, show_help=True):
2629@@ -133,7 +127,7 @@ class EditFile(object):
2630 def edit(self, optional=False):
2631 if optional:
2632 print("\n\nCurrently the %s looks like:" % self.description)
2633- with open(self.filename, 'r') as f:
2634+ with open(self.filename, 'r', encoding='utf-8') as f:
2635 print(f.read())
2636 if YesNoQuestion().ask("Edit", "no") == "no":
2637 return
2638@@ -141,12 +135,11 @@ class EditFile(object):
2639 done = False
2640 while not done:
2641 old_mtime = os.stat(self.filename).st_mtime
2642- ubuntutools.subprocess.check_call(['sensible-editor',
2643- self.filename])
2644+ subprocess.check_call(['sensible-editor', self.filename])
2645 modified = old_mtime != os.stat(self.filename).st_mtime
2646 placeholders_present = False
2647 if self.placeholders:
2648- with open(self.filename, 'r') as f:
2649+ with open(self.filename, 'r', encoding='utf-8') as f:
2650 for line in f:
2651 for placeholder in self.placeholders:
2652 if placeholder.search(line.strip()):
2653@@ -188,8 +181,8 @@ class EditBugReport(EditFile):
2654 placeholders)
2655
2656 def check_edit(self):
2657- with open(self.filename, 'r') as f:
2658- report = f.read().decode('utf-8')
2659+ with open(self.filename, 'r', encoding='utf-8') as f:
2660+ report = f.read()
2661
2662 if self.split_re.match(report) is None:
2663 print("The %s doesn't start with 'Summary:' and 'Description:' "
2664@@ -199,8 +192,8 @@ class EditBugReport(EditFile):
2665 return True
2666
2667 def get_report(self):
2668- with open(self.filename, 'r') as f:
2669- report = f.read().decode('utf-8')
2670+ with open(self.filename, 'r', encoding='utf-8') as f:
2671+ report = f.read()
2672
2673 match = self.split_re.match(report)
2674 title = match.group(1).replace(u'\n', u' ')
2675diff --git a/ubuntutools/requestsync/lp.py b/ubuntutools/requestsync/lp.py
2676index ea176de..7632612 100644
2677--- a/ubuntutools/requestsync/lp.py
2678+++ b/ubuntutools/requestsync/lp.py
2679@@ -20,8 +20,6 @@
2680 # Please see the /usr/share/common-licenses/GPL-2 file for the full text
2681 # of the GNU General Public License license.
2682
2683-from __future__ import print_function
2684-
2685 import re
2686
2687 from debian.deb822 import Changes
2688diff --git a/ubuntutools/requestsync/mail.py b/ubuntutools/requestsync/mail.py
2689index 9170195..729fe60 100644
2690--- a/ubuntutools/requestsync/mail.py
2691+++ b/ubuntutools/requestsync/mail.py
2692@@ -20,13 +20,12 @@
2693 # Please see the /usr/share/common-licenses/GPL-2 file for the full text
2694 # of the GNU General Public License license.
2695
2696-from __future__ import print_function
2697-
2698 import os
2699 import re
2700 import sys
2701 import smtplib
2702 import socket
2703+import subprocess
2704 import tempfile
2705
2706 from debian.changelog import Changelog, Version
2707@@ -36,11 +35,6 @@ from ubuntutools.archive import rmadison, FakeSPPH
2708 from ubuntutools.lp.udtexceptions import PackageNotFoundException
2709 from ubuntutools.logger import Logger
2710 from ubuntutools.question import confirmation_prompt, YesNoQuestion
2711-from ubuntutools import subprocess
2712-
2713-if sys.version_info[0] >= 3:
2714- basestring = str
2715- unicode = str
2716
2717
2718 __all__ = [
2719@@ -110,17 +104,17 @@ def get_ubuntu_delta_changelog(srcpkg):
2720 '''
2721 changelog = Changelog(srcpkg.getChangelog())
2722 if changelog is None:
2723- return u''
2724+ return ''
2725 delta = []
2726 debian_info = DebianDistroInfo()
2727 for block in changelog:
2728 distribution = block.distributions.split()[0].split('-')[0]
2729 if debian_info.valid(distribution):
2730 break
2731- delta += [unicode(change) for change in block.changes()
2732+ delta += [str(change) for change in block.changes()
2733 if change.strip()]
2734
2735- return u'\n'.join(delta)
2736+ return '\n'.join(delta)
2737
2738
2739 def mail_bug(srcpkg, subscribe, status, bugtitle, bugtext, bug_mail_domain,
2740@@ -161,15 +155,16 @@ def mail_bug(srcpkg, subscribe, status, bugtitle, bugtext, bug_mail_domain,
2741 gpg_command.extend(('-u', keyid))
2742
2743 # sign the mail body
2744- gpg = subprocess.Popen(gpg_command, stdin=subprocess.PIPE,
2745- stdout=subprocess.PIPE)
2746- signed_report = gpg.communicate(mailbody.encode('utf-8'))[0].decode('utf-8')
2747+ gpg = subprocess.Popen(
2748+ gpg_command, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
2749+ encoding='utf-8')
2750+ signed_report = gpg.communicate(mailbody)[0]
2751 if gpg.returncode != 0:
2752 Logger.error("%s failed.", gpg_command[0])
2753 sys.exit(1)
2754
2755 # generate email
2756- mail = u'''\
2757+ mail = '''\
2758 From: %s
2759 To: %s
2760 Subject: %s
2761diff --git a/ubuntutools/sponsor_patch/bugtask.py b/ubuntutools/sponsor_patch/bugtask.py
2762index ebb40f6..c641145 100644
2763--- a/ubuntutools/sponsor_patch/bugtask.py
2764+++ b/ubuntutools/sponsor_patch/bugtask.py
2765@@ -17,11 +17,8 @@
2766
2767 import os
2768 import re
2769-try:
2770- from urllib.parse import unquote
2771- from urllib.request import urlretrieve
2772-except ImportError:
2773- from urllib import unquote, urlretrieve
2774+from urllib.parse import unquote
2775+from urllib.request import urlretrieve
2776
2777 import debian.debian_support
2778 import distro_info
2779diff --git a/ubuntutools/sponsor_patch/patch.py b/ubuntutools/sponsor_patch/patch.py
2780index cd99672..b0d993f 100644
2781--- a/ubuntutools/sponsor_patch/patch.py
2782+++ b/ubuntutools/sponsor_patch/patch.py
2783@@ -17,8 +17,8 @@
2784
2785 import os
2786 import re
2787+import subprocess
2788
2789-from ubuntutools import subprocess
2790 from ubuntutools.logger import Logger
2791 from ubuntutools.sponsor_patch.question import ask_for_manual_fixing
2792 from functools import reduce
2793@@ -71,8 +71,7 @@ class Patch(object):
2794 patch_f.close()
2795
2796 cmd = ["diffstat", "-l", "-p0", self._full_path]
2797- process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
2798- changed_files = process.communicate()[0]
2799+ changed_files = subprocess.check_output(cmd, encoding='utf-8')
2800 self._changed_files = [f for f in changed_files.split("\n") if f != ""]
2801
2802 def get_strip_level(self):
2803diff --git a/ubuntutools/sponsor_patch/question.py b/ubuntutools/sponsor_patch/question.py
2804index 0472049..b49ff99 100644
2805--- a/ubuntutools/sponsor_patch/question.py
2806+++ b/ubuntutools/sponsor_patch/question.py
2807@@ -15,8 +15,6 @@
2808 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
2809 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2810
2811-from __future__ import print_function
2812-
2813 import sys
2814
2815 from ubuntutools.question import Question, YesNoQuestion
2816diff --git a/ubuntutools/sponsor_patch/source_package.py b/ubuntutools/sponsor_patch/source_package.py
2817index 8adecd3..d4c54e3 100644
2818--- a/ubuntutools/sponsor_patch/source_package.py
2819+++ b/ubuntutools/sponsor_patch/source_package.py
2820@@ -15,16 +15,14 @@
2821 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
2822 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2823
2824-from __future__ import print_function
2825-
2826 import os
2827 import re
2828+import subprocess
2829 import sys
2830
2831 import debian.changelog
2832 import debian.deb822
2833
2834-from ubuntutools import subprocess
2835 from ubuntutools.logger import Logger
2836 from ubuntutools.question import Question, YesNoQuestion
2837
2838@@ -327,8 +325,7 @@ class SourcePackage(object):
2839 if not Logger.verbose:
2840 cmd.insert(1, "-q")
2841 Logger.command(cmd + [">", self._debdiff_filename])
2842- process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
2843- debdiff = process.communicate()[0]
2844+ debdiff = subprocess.check_output(cmd, encoding='utf-8')
2845
2846 # write debdiff file
2847 debdiff_file = open(self._debdiff_filename, "w")
2848@@ -421,8 +418,7 @@ class SourcePackage(object):
2849 self._package + "_" +
2850 strip_epoch(self._version) + ".lintian")
2851 Logger.command(cmd + [">", lintian_filename])
2852- process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
2853- report = process.communicate()[0]
2854+ report = subprocess.check_output(cmd, encoding='utf-8')
2855
2856 # write lintian report file
2857 lintian_file = open(lintian_filename, "w")
2858diff --git a/ubuntutools/sponsor_patch/sponsor_patch.py b/ubuntutools/sponsor_patch/sponsor_patch.py
2859index 8f3fbbf..d1d1b62 100644
2860--- a/ubuntutools/sponsor_patch/sponsor_patch.py
2861+++ b/ubuntutools/sponsor_patch/sponsor_patch.py
2862@@ -15,18 +15,16 @@
2863 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
2864 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2865
2866-from __future__ import print_function
2867-
2868 import os
2869 import pwd
2870 import shutil
2871+import subprocess
2872 import sys
2873
2874 from distro_info import UbuntuDistroInfo
2875
2876 from launchpadlib.launchpad import Launchpad
2877
2878-from ubuntutools import subprocess
2879 from ubuntutools.logger import Logger
2880 from ubuntutools.update_maintainer import (update_maintainer,
2881 MaintainerUpdateException)
2882@@ -37,9 +35,6 @@ from ubuntutools.sponsor_patch.patch import Patch
2883 from ubuntutools.sponsor_patch.question import ask_for_manual_fixing
2884 from ubuntutools.sponsor_patch.source_package import SourcePackage
2885
2886-if sys.version_info[0] < 3:
2887- range = xrange # noqa, pylint: disable=redefined-builtin,undefined-variable
2888-
2889
2890 def is_command_available(command, check_sbin=False):
2891 "Is command in $PATH?"
2892diff --git a/ubuntutools/subprocess.py b/ubuntutools/subprocess.py
2893deleted file mode 100644
2894index 1d9e90a..0000000
2895--- a/ubuntutools/subprocess.py
2896+++ /dev/null
2897@@ -1,116 +0,0 @@
2898-"""Drop-in replacement for subprocess with better defaults
2899-
2900-This is an API-compatible replacement for the built-in subprocess
2901-module whose defaults better line up with our tastes.
2902-
2903-In particular, it:
2904- - Adds support for the restore_signals flag if subprocess itself
2905- doesn't support it
2906- - Defaults close_fds to True
2907-"""
2908-
2909-
2910-from __future__ import absolute_import
2911-
2912-import inspect
2913-import signal
2914-import subprocess
2915-import sys
2916-
2917-from subprocess import PIPE, STDOUT, CalledProcessError
2918-
2919-__all__ = ['Popen', 'call', 'check_call', 'check_output', 'CalledProcessError',
2920- 'PIPE', 'STDOUT']
2921-
2922-
2923-class Popen(subprocess.Popen):
2924- def __init__(self, *args, **kwargs):
2925- kwargs.setdefault('close_fds', True)
2926- if sys.version_info[0] >= 3:
2927- getargs = inspect.getfullargspec
2928- else:
2929- getargs = inspect.getargspec
2930-
2931- if 'restore_signals' not in getargs(subprocess.Popen.__init__)[0]:
2932- given_preexec_fn = kwargs.pop('preexec_fn', None)
2933- restore_signals = kwargs.pop('restore_signals', True)
2934-
2935- def preexec_fn():
2936- if restore_signals:
2937- for sig in ('SIGPIPE', 'SIGXFZ', 'SIGXFSZ'):
2938- if hasattr(signal, sig):
2939- signal.signal(getattr(signal, sig),
2940- signal.SIG_DFL)
2941-
2942- if given_preexec_fn:
2943- given_preexec_fn()
2944- kwargs['preexec_fn'] = preexec_fn
2945-
2946- subprocess.Popen.__init__(self, *args, **kwargs)
2947-
2948-
2949-# call, check_call, and check_output are copied directly from the
2950-# subprocess module shipped with Python 2.7.1-5ubuntu2
2951-
2952-
2953-def call(*popenargs, **kwargs):
2954- """Run command with arguments. Wait for command to complete, then
2955- return the returncode attribute.
2956-
2957- The arguments are the same as for the Popen constructor. Example:
2958-
2959- retcode = call(["ls", "-l"])
2960- """
2961- return Popen(*popenargs, **kwargs).wait()
2962-
2963-
2964-def check_call(*popenargs, **kwargs):
2965- """Run command with arguments. Wait for command to complete. If
2966- the exit code was zero then return, otherwise raise
2967- CalledProcessError. The CalledProcessError object will have the
2968- return code in the returncode attribute.
2969-
2970- The arguments are the same as for the Popen constructor. Example:
2971-
2972- check_call(["ls", "-l"])
2973- """
2974- retcode = call(*popenargs, **kwargs)
2975- if retcode:
2976- cmd = kwargs.get("args")
2977- if cmd is None:
2978- cmd = popenargs[0]
2979- raise CalledProcessError(retcode, cmd)
2980- return 0
2981-
2982-
2983-def check_output(*popenargs, **kwargs):
2984- r"""Run command with arguments and return its output as a byte string.
2985-
2986- If the exit code was non-zero it raises a CalledProcessError. The
2987- CalledProcessError object will have the return code in the returncode
2988- attribute and output in the output attribute.
2989-
2990- The arguments are the same as for the Popen constructor. Example:
2991-
2992- >>> check_output(["ls", "-l", "/dev/null"])
2993- 'crw-rw-rw- 1 root root 1, 3 Oct 18 2007 /dev/null\n'
2994-
2995- The stdout argument is not allowed as it is used internally.
2996- To capture standard error in the result, use stderr=STDOUT.
2997-
2998- >>> check_output(["/bin/sh", "-c",
2999- ... "ls -l non_existent_file ; exit 0"],
3000- ... stderr=STDOUT)
3001- 'ls: non_existent_file: No such file or directory\n'
3002- """
3003- if 'stdout' in kwargs:
3004- raise ValueError('stdout argument not allowed, it will be overridden.')
3005- process = Popen(stdout=PIPE, *popenargs, **kwargs)
3006- output, unused_err = process.communicate()
3007- retcode = process.poll()
3008- if retcode:
3009- cmd = kwargs.get("args")
3010- if cmd is None:
3011- cmd = popenargs[0]
3012- raise CalledProcessError(retcode, cmd, output=output)
3013- return output
3014diff --git a/ubuntutools/test/__init__.py b/ubuntutools/test/__init__.py
3015index 6917e90..252092e 100644
3016--- a/ubuntutools/test/__init__.py
3017+++ b/ubuntutools/test/__init__.py
3018@@ -21,10 +21,7 @@ import sys
3019
3020 import setup
3021
3022-if sys.version_info < (2, 7):
3023- import unittest2 as unittest
3024-else:
3025- import unittest
3026+import unittest
3027
3028
3029 def discover():
3030@@ -49,8 +46,7 @@ def get_source_files():
3031 if is_script:
3032 with open(code_file, "rb") as script_file:
3033 shebang = script_file.readline().decode("utf-8")
3034- if ((sys.version_info[0] == 3 and "python3" in shebang)
3035- or ("python" in shebang and "python3" not in shebang)):
3036+ if "python3" in shebang:
3037 files.append(code_file)
3038 else:
3039 files.append(code_file)
3040diff --git a/ubuntutools/test/test_archive.py b/ubuntutools/test/test_archive.py
3041index 077ca83..aa8c372 100644
3042--- a/ubuntutools/test/test_archive.py
3043+++ b/ubuntutools/test/test_archive.py
3044@@ -15,21 +15,16 @@
3045 # PERFORMANCE OF THIS SOFTWARE.
3046
3047
3048+import mock
3049 import os.path
3050 import shutil
3051-import sys
3052 import tempfile
3053 from io import BytesIO
3054-try:
3055- from urllib.request import OpenerDirector, urlopen
3056- from urllib.error import HTTPError, URLError
3057-except ImportError:
3058- from urllib2 import OpenerDirector, urlopen
3059- from urllib2 import HTTPError, URLError
3060-import httplib2
3061-import mock
3062+from urllib.error import HTTPError, URLError
3063+from urllib.request import OpenerDirector, urlopen
3064
3065 import debian.deb822
3066+import httplib2
3067
3068 import ubuntutools.archive
3069 from ubuntutools.test import unittest
3070@@ -64,18 +59,11 @@ class DscVerificationTestCase(unittest.TestCase):
3071 fn = 'test-data/example_1.0.orig.tar.gz'
3072 with open(fn, 'rb') as f:
3073 data = f.read()
3074- if sys.version_info[0] >= 3:
3075- last_byte = chr(data[-1] ^ 8).encode()
3076- else:
3077- last_byte = chr(ord(data[-1]) ^ 8)
3078+ last_byte = chr(data[-1] ^ 8).encode()
3079 data = data[:-1] + last_byte
3080 m = mock.MagicMock(name='open', spec=open)
3081 m.return_value = BytesIO(data)
3082- if sys.version_info[0] >= 3:
3083- target = 'builtins.open'
3084- else:
3085- target = '__builtin__.open'
3086- with mock.patch(target, m):
3087+ with mock.patch('builtins.open', m):
3088 self.assertFalse(self.dsc.verify_file(fn))
3089
3090 def test_sha1(self):
3091diff --git a/ubuntutools/test/test_config.py b/ubuntutools/test/test_config.py
3092index d78dcee..08b37fb 100644
3093--- a/ubuntutools/test/test_config.py
3094+++ b/ubuntutools/test/test_config.py
3095@@ -15,15 +15,11 @@
3096 # OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
3097 # PERFORMANCE OF THIS SOFTWARE.
3098
3099-import os
3100-import sys
3101 import locale
3102-try:
3103- from StringIO import StringIO
3104-except ImportError:
3105- from io import StringIO
3106-
3107 import mock
3108+import os
3109+import sys
3110+from io import StringIO
3111
3112 from ubuntutools.config import UDTConfig, ubu_email
3113 from ubuntutools.logger import Logger
3114@@ -49,15 +45,9 @@ class ConfigTestCase(unittest.TestCase):
3115
3116 def setUp(self):
3117 super(ConfigTestCase, self).setUp()
3118- if sys.version_info[0] < 3:
3119- self.assertRegex = self.assertRegexpMatches
3120 m = mock.mock_open()
3121 m.side_effect = self._fake_open
3122- if sys.version_info[0] >= 3:
3123- target = 'builtins.open'
3124- else:
3125- target = '__builtin__.open'
3126- patcher = mock.patch(target, m)
3127+ patcher = mock.patch('builtins.open', m)
3128 self.addCleanup(patcher.stop)
3129 patcher.start()
3130
3131diff --git a/ubuntutools/test/test_flake8.py b/ubuntutools/test/test_flake8.py
3132index b604bc2..c6d31d3 100644
3133--- a/ubuntutools/test/test_flake8.py
3134+++ b/ubuntutools/test/test_flake8.py
3135@@ -33,17 +33,18 @@ class Flake8TestCase(unittest.TestCase):
3136 cmd = [sys.executable, "-m", "flake8", "--max-line-length=99"] + get_source_files()
3137 if unittest_verbosity() >= 2:
3138 sys.stderr.write("Running following command:\n{}\n".format(" ".join(cmd)))
3139- process = subprocess.Popen(cmd, stdout=subprocess.PIPE,
3140- stderr=subprocess.PIPE, close_fds=True)
3141+ process = subprocess.Popen(
3142+ cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
3143+ encoding='utf-8')
3144
3145 out, err = process.communicate()
3146 if process.returncode != 0: # pragma: no cover
3147 msgs = []
3148 if err:
3149 msgs.append("flake8 exited with code {} and has unexpected output on stderr:\n{}"
3150- .format(process.returncode, err.decode().rstrip()))
3151+ .format(process.returncode, err.rstrip()))
3152 if out:
3153- msgs.append("flake8 found issues:\n{}".format(out.decode().rstrip()))
3154+ msgs.append("flake8 found issues:\n{}".format(out.rstrip()))
3155 if not msgs:
3156 msgs.append("flake8 exited with code {} and has no output on stdout or stderr."
3157 .format(process.returncode))
3158diff --git a/ubuntutools/test/test_help.py b/ubuntutools/test/test_help.py
3159index 83c639a..b691739 100644
3160--- a/ubuntutools/test/test_help.py
3161+++ b/ubuntutools/test/test_help.py
3162@@ -18,10 +18,10 @@ import fcntl
3163 import os
3164 import select
3165 import signal
3166+import subprocess
3167 import time
3168
3169 import setup
3170-from ubuntutools import subprocess
3171 from ubuntutools.test import unittest
3172
3173 TIMEOUT = 10
3174@@ -46,7 +46,7 @@ class HelpTestCase(unittest.TestCase):
3175 def tester(self):
3176 null = open('/dev/null', 'r')
3177 process = subprocess.Popen(['./' + script, '--help'],
3178- close_fds=True, stdin=null,
3179+ encoding='utf-8', stdin=null,
3180 universal_newlines=True,
3181 stdout=subprocess.PIPE,
3182 stderr=subprocess.PIPE)
3183@@ -73,6 +73,8 @@ class HelpTestCase(unittest.TestCase):
3184 if process.poll() is None:
3185 os.kill(process.pid, signal.SIGKILL)
3186 null.close()
3187+ process.stdout.close()
3188+ process.stderr.close()
3189
3190 self.assertEqual(process.poll(), 0,
3191 "%s failed to return usage within %i seconds.\n"
3192diff --git a/ubuntutools/test/test_logger.py b/ubuntutools/test/test_logger.py
3193index 6593646..3f7fec3 100644
3194--- a/ubuntutools/test/test_logger.py
3195+++ b/ubuntutools/test/test_logger.py
3196@@ -14,10 +14,7 @@
3197 # OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
3198 # PERFORMANCE OF THIS SOFTWARE.
3199
3200-try:
3201- from StringIO import StringIO
3202-except ImportError:
3203- from io import StringIO
3204+from io import StringIO
3205 import sys
3206
3207 from ubuntutools.logger import Logger
3208diff --git a/ubuntutools/test/test_pylint.py b/ubuntutools/test/test_pylint.py
3209index 4bc3d53..df6c890 100644
3210--- a/ubuntutools/test/test_pylint.py
3211+++ b/ubuntutools/test/test_pylint.py
3212@@ -17,10 +17,10 @@
3213
3214 import os
3215 import re
3216+import subprocess
3217 import sys
3218
3219 from ubuntutools.test import get_source_files, unittest, unittest_verbosity
3220-from ubuntutools import subprocess
3221
3222 CONFIG = os.path.join(os.path.dirname(__file__), "pylint.conf")
3223
3224@@ -40,8 +40,9 @@ class PylintTestCase(unittest.TestCase):
3225 "-E", "--"] + get_source_files()
3226 if unittest_verbosity() >= 2:
3227 sys.stderr.write("Running following command:\n{}\n".format(" ".join(cmd)))
3228- process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
3229- close_fds=True)
3230+ process = subprocess.Popen(
3231+ cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
3232+ encoding='utf-8')
3233 out, err = process.communicate()
3234
3235 if process.returncode != 0: # pragma: no cover
3236@@ -50,11 +51,11 @@ class PylintTestCase(unittest.TestCase):
3237 # ------------------------------------
3238 # Your code has been rated at 10.00/10
3239 #
3240- out = re.sub("^(-+|Your code has been rated at .*)$", "", out.decode(),
3241+ out = re.sub("^(-+|Your code has been rated at .*)$", "", out,
3242 flags=re.MULTILINE).rstrip()
3243
3244 # Strip logging of used config file (introduced in pylint 1.8)
3245- err = re.sub("^Using config file .*\n", "", err.decode()).rstrip()
3246+ err = re.sub("^Using config file .*\n", "", err).rstrip()
3247
3248 msgs = []
3249 if err:
3250diff --git a/ubuntutools/test/test_update_maintainer.py b/ubuntutools/test/test_update_maintainer.py
3251index 38ba40f..bd5d567 100644
3252--- a/ubuntutools/test/test_update_maintainer.py
3253+++ b/ubuntutools/test/test_update_maintainer.py
3254@@ -16,15 +16,10 @@
3255
3256 """Test suite for ubuntutools.update_maintainer"""
3257
3258-try:
3259- from StringIO import StringIO
3260-except ImportError:
3261- from io import StringIO
3262-
3263+import mock
3264 import os
3265 import sys
3266-
3267-import mock
3268+from io import StringIO
3269
3270 from ubuntutools.logger import Logger
3271 from ubuntutools.test import unittest
3272@@ -231,15 +226,9 @@ class UpdateMaintainerTestCase(unittest.TestCase):
3273
3274 # pylint: disable=C0103
3275 def setUp(self):
3276- if sys.version_info[0] < 3:
3277- self.assertRegex = self.assertRegexpMatches
3278 m = mock.mock_open()
3279 m.side_effect = self._fake_open
3280- if sys.version_info[0] >= 3:
3281- target = 'builtins.open'
3282- else:
3283- target = '__builtin__.open'
3284- patcher = mock.patch(target, m)
3285+ patcher = mock.patch('builtins.open', m)
3286 self.addCleanup(patcher.stop)
3287 patcher.start()
3288 m = mock.MagicMock(side_effect=self._fake_isfile)
3289diff --git a/ubuntutools/update_maintainer.py b/ubuntutools/update_maintainer.py
3290index 9cbbecc..2c5de57 100644
3291--- a/ubuntutools/update_maintainer.py
3292+++ b/ubuntutools/update_maintainer.py
3293@@ -14,8 +14,6 @@
3294 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
3295 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
3296
3297-from __future__ import print_function
3298-
3299 """This module is for updating the Maintainer field of an Ubuntu package."""
3300
3301 import os
3302diff --git a/update-maintainer b/update-maintainer
3303index ebe213b..95f551c 100755
3304--- a/update-maintainer
3305+++ b/update-maintainer
3306@@ -1,4 +1,4 @@
3307-#!/usr/bin/python
3308+#!/usr/bin/python3
3309 #
3310 # Copyright (C) 2010, Benjamin Drung <bdrung@ubuntu.com>
3311 #
3312@@ -39,8 +39,8 @@ def main():
3313 (options, args) = parser.parse_args()
3314
3315 if len(args) != 0:
3316- print >> sys.stderr, ("%s: Error: Unsupported additional parameters "
3317- "specified: %s") % (script_name, ", ".join(args))
3318+ print("%s: Error: Unsupported additional parameters specified: %s"
3319+ % (script_name, ", ".join(args)), file=sys.stderr)
3320 sys.exit(1)
3321
3322 if not options.restore:

Subscribers

People subscribed via source and target branches