tag 941175 + patch thanks
Patch attached.
diff -Nru lptools-0.2.0/debian/changelog lptools-0.2.0/debian/changelog --- lptools-0.2.0/debian/changelog 2019-08-31 04:54:34.000000000 -0600 +++ lptools-0.2.0/debian/changelog 2019-11-26 12:47:54.000000000 -0700 @@ -1,3 +1,11 @@ +lptools (0.2.0-6) UNRELEASED; urgency=medium + + * Update patch 02_python3: Also convert /usr/bin/lp-* to Python 3. + Conversion performed using 2to3-2.7 with visual inspection and + spot testing. Closes: #941175 + + -- dann frazier <da...@debian.org> Tue, 26 Nov 2019 12:47:54 -0700 + lptools (0.2.0-5) unstable; urgency=medium * Add patch 02_python3: Convert to Python 3. Closes: #936967 diff -Nru lptools-0.2.0/debian/patches/02_python3 lptools-0.2.0/debian/patches/02_python3 --- lptools-0.2.0/debian/patches/02_python3 2019-08-31 04:54:34.000000000 -0600 +++ lptools-0.2.0/debian/patches/02_python3 2019-11-26 12:46:37.000000000 -0700 @@ -1,7 +1,9 @@ === modified file 'setup.py' ---- old/setup.py 2019-08-31 10:44:24 +0000 -+++ new/setup.py 2019-08-31 10:49:36 +0000 -@@ -4,7 +4,8 @@ +Index: lptools-0.2.0/setup.py +=================================================================== +--- lptools-0.2.0.orig/setup.py ++++ lptools-0.2.0/setup.py +@@ -4,7 +4,8 @@ from glob import glob from distutils.core import setup import os.path @@ -11,7 +13,7 @@ setup( name='lptools', -@@ -20,7 +21,7 @@ +@@ -20,7 +21,7 @@ setup( 'templates/recipe-status.html'])], packages=['lptools'], scripts=glob('bin/*'), @@ -20,4 +22,818 @@ 'Development Status :: 4 - Beta', 'Intended Audience :: Developers', 'License :: OSI Approved :: GNU General Public License v3 (GPL3)' - +Index: lptools-0.2.0/bin/lp-attach +=================================================================== +--- lptools-0.2.0.orig/bin/lp-attach ++++ lptools-0.2.0/bin/lp-attach +@@ -1,4 +1,4 @@ +-#! /usr/bin/python ++#! /usr/bin/python3 + # + # Copyright (C) 2010 Canonical Ltd + +@@ -35,7 +35,7 @@ from lptools import config + def guess_mime_type(attachment_bytes): + try: + import magic +- except ImportError, e: ++ except ImportError as e: + sys.stderr.write("can't guess mime-types without the python-magic library: %s" % e) + mimetype = None + else: +@@ -43,13 +43,13 @@ def guess_mime_type(attachment_bytes): + mimetype = mime.buffer(attachment_bytes) + if mimetype is None: + mimetype = 'application/binary' +- print 'attachment type %s' % mimetype ++ print('attachment type %s' % mimetype) + return mimetype + + + def main(argv): + if len(argv) != 2 or argv[1] == '--help': +- print __doc__ ++ print(__doc__) + return 3 + + try: +@@ -59,23 +59,23 @@ def main(argv): + return 1 + + lp = config.get_launchpad("attach") +- print "getting bug %s" % bugnumber ++ print("getting bug %s" % bugnumber) + bug = lp.bugs[bugnumber] +- print 'Attaching to %s' % bug ++ print('Attaching to %s' % bug) + + attachment_bytes = sys.stdin.read() +- print '%d bytes to attach' % len(attachment_bytes) ++ print('%d bytes to attach' % len(attachment_bytes)) + + mime_type = guess_mime_type(attachment_bytes) + + # mime type must be specified otherwise + # <https://bugs.edge.launchpad.net/malone/+bug/204560> assumes it's + # chemical/x-mopac-input +- print bug.addAttachment(comment='', ++ print(bug.addAttachment(comment='', + data=attachment_bytes, + description='', + filename='attachment', +- content_type=mime_type) ++ content_type=mime_type)) + + + if __name__ == '__main__': +Index: lptools-0.2.0/bin/lp-bug-dupe-properties +=================================================================== +--- lptools-0.2.0.orig/bin/lp-bug-dupe-properties ++++ lptools-0.2.0/bin/lp-bug-dupe-properties +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/python3 + # + # Copyright (C) 2012, Canonical Ltd. + # Written by Brian Murray +@@ -99,25 +99,25 @@ def main(): + key = None + + if bug.number_of_duplicates == 0: +- print('LP: #%s has no duplicates!' % bug_number) ++ print(('LP: #%s has no duplicates!' % bug_number)) + sys.exit(1) + + for dupe in bug.duplicates: + dupe_num = dupe.id + prop = check_duplicate(dupe, search, key) +- if prop in dupe_props.keys(): ++ if prop in list(dupe_props.keys()): + dupe_props[prop].append(str(dupe_num)) + else: + dupe_props[prop] = [str(dupe_num)] + + dupe_count = bug.number_of_duplicates + if dupe_count > 1: +- print('LP: #%s has %s duplicates' % (bug_number, dupe_count)) ++ print(('LP: #%s has %s duplicates' % (bug_number, dupe_count))) + elif dupe_count == 1: +- print('LP: #%s has %s duplicate' % (bug_number, dupe_count)) ++ print(('LP: #%s has %s duplicate' % (bug_number, dupe_count))) + + for prop, bugs in sorted(dupe_props.items()): +- print(' %s: %s' % (prop, ' '.join(bugs))) ++ print((' %s: %s' % (prop, ' '.join(bugs)))) + + + if __name__ == '__main__': +Index: lptools-0.2.0/bin/lp-capture-bug-counts +=================================================================== +--- lptools-0.2.0.orig/bin/lp-capture-bug-counts ++++ lptools-0.2.0/bin/lp-capture-bug-counts +@@ -1,4 +1,4 @@ +-#! /usr/bin/python ++#! /usr/bin/python3 + + import sys + +@@ -70,10 +70,10 @@ class CannedQuery(object): + def show_text(self): + # print self.get_name() + for category in self.query_categories(): +- print '%6d %s %s' % (category.count_bugs(), ++ print('%6d %s %s' % (category.count_bugs(), + category.get_name(), +- category.get_link_url() or '') +- print ++ category.get_link_url() or '')) ++ print() + + + class PatchCannedQuery(CannedQuery): +@@ -103,7 +103,7 @@ class StatusCannedQuery(CannedQuery): + if bugtask.status not in by_status: + by_status[bugtask.status] = StatusBugCategory(bugtask.status) + by_status[bugtask.status].add(bugtask) +- return by_status.values() ++ return list(by_status.values()) + + + def show_bug_report(project): +Index: lptools-0.2.0/bin/lp-check-membership +=================================================================== +--- lptools-0.2.0.orig/bin/lp-check-membership ++++ lptools-0.2.0/bin/lp-check-membership +@@ -1,4 +1,4 @@ +-#! /usr/bin/python ++#! /usr/bin/python3 + # + # Copyright (C) 2009 Canonical Ltd + +@@ -38,7 +38,7 @@ def main(argv): + parser = optparse.OptionParser('%prog [options] PERSON GROUP') + opts, args = parser.parse_args() + if len(args) != 2: +- print __doc__ ++ print(__doc__) + return 2 + user_name = args[0] + group_name = args[1] +@@ -46,10 +46,10 @@ def main(argv): + user = lp.people[user_name] + for user_team in user.super_teams: + if user_team.name == group_name: +- print '%s is a member of %s' % (user_name, group_name) ++ print('%s is a member of %s' % (user_name, group_name)) + return 0 + else: +- print '%s is not a member of %s' % (user_name, group_name) ++ print('%s is not a member of %s' % (user_name, group_name)) + return 1 + + +Index: lptools-0.2.0/bin/lp-force-branch-mirror +=================================================================== +--- lptools-0.2.0.orig/bin/lp-force-branch-mirror ++++ lptools-0.2.0/bin/lp-force-branch-mirror +@@ -1,4 +1,4 @@ +-#! /usr/bin/python ++#! /usr/bin/python3 + # vi: expandtab:sts=4 + + # Copyright (C) 2011 Jelmer Vernooij +@@ -22,12 +22,12 @@ def main(argv): + + lp = config.get_launchpad("force-branch-mirror") + branches = lp.branches.getByUrls(urls=args) +- for url, branch_dict in branches.iteritems(): ++ for url, branch_dict in branches.items(): + if branch_dict is None: +- print "Branch %s not found" % url ++ print("Branch %s not found" % url) + else: + branch = lp.load(branch_dict["self_link"]) +- print "%s: %s" % (branch.bzr_identity, branch.requestMirror()) ++ print("%s: %s" % (branch.bzr_identity, branch.requestMirror())) + + if __name__ == '__main__': + sys.exit(main(sys.argv)) +Index: lptools-0.2.0/bin/lp-get-branches +=================================================================== +--- lptools-0.2.0.orig/bin/lp-get-branches ++++ lptools-0.2.0/bin/lp-get-branches +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/python3 + # -*- coding: utf-8 -*- + # + # Copyright (C) 2007 Canonical Ltd. +@@ -79,13 +79,13 @@ def main(): + try: + team = launchpad.people[team] + except KeyError: +- print >> sys.stderr, "E: The team '%s' doesn't exist." % team ++ print("E: The team '%s' doesn't exist." % team, file=sys.stderr) + + # Get a list of branches + branches = team.getBranches() + +- print "Downloading all branches for the '%s' team. This may take some " \ +- "time." % team.display_name ++ print("Downloading all branches for the '%s' team. This may take some " \ ++ "time." % team.display_name) + + try: + os.makedirs(team.name) +@@ -101,11 +101,11 @@ def main(): + os.chdir(project_name) + + if not os.path.exists(branch.name): +- print "Branching %s ..." % branch.display_name ++ print("Branching %s ..." % branch.display_name) + cmd = ["bzr", operation_type, branch.bzr_identity, branch.name] + subprocess.call(cmd) + else: +- print "Merging %s ..." % branch.display_name ++ print("Merging %s ..." % branch.display_name) + os.chdir(branch.name) + subprocess.call(["bzr", "merge", "--pull", "--remember"]) + os.chdir(os.path.join(directory, team.name)) +@@ -117,4 +117,4 @@ if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: +- print "Operation was interrupted by user." ++ print("Operation was interrupted by user.") +Index: lptools-0.2.0/bin/lp-grab-attachments +=================================================================== +--- lptools-0.2.0.orig/bin/lp-grab-attachments ++++ lptools-0.2.0/bin/lp-grab-attachments +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/python3 + # + # Copyright (C) 2007, Canonical Ltd. + # Written by Daniel Holbach, +@@ -36,7 +36,7 @@ def download_attachments(bug, descriptio + + try: + os.mkdir(bug_folder_name) +- except OSError, error: ++ except OSError as error: + if error.errno == errno.EEXIST: + return + +Index: lptools-0.2.0/bin/lp-list-bugs +=================================================================== +--- lptools-0.2.0.orig/bin/lp-list-bugs ++++ lptools-0.2.0/bin/lp-list-bugs +@@ -1,4 +1,4 @@ +-#! /usr/bin/python ++#! /usr/bin/python3 + # -*- coding: UTF-8 -*- + """Briefly list status of Launchpad bugs.""" + +@@ -42,18 +42,17 @@ def main(): + for bugnum in args: + try: + bug = launchpad.bugs[bugnum] +- print "Bug %s: %s" % (bugnum, bug.title) ++ print("Bug %s: %s" % (bugnum, bug.title)) + for task in bug.bug_tasks: +- print " %s: %s" % (task.bug_target_name, task.status) +- except HTTPError, error: ++ print(" %s: %s" % (task.bug_target_name, task.status)) ++ except HTTPError as error: + if error.response.status == 401: +- print >> sys.stderr, \ +- ("E: Don't have enough permissions to access bug %s" % +- bugnum) +- print >> sys.stderr, error.content ++ print(("E: Don't have enough permissions to access bug %s" % ++ bugnum), file=sys.stderr) ++ print(error.content, file=sys.stderr) + continue + elif error.response.status == 404: +- print >> sys.stderr, "E: Bug %s not found" % bugnum ++ print("E: Bug %s not found" % bugnum, file=sys.stderr) + else: + raise + +Index: lptools-0.2.0/bin/lp-milestone2ical +=================================================================== +--- lptools-0.2.0.orig/bin/lp-milestone2ical ++++ lptools-0.2.0/bin/lp-milestone2ical +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/python3 + # + # Author: Rodney Dawes <rodney.da...@canonical.com> + # +@@ -16,7 +16,7 @@ + # You should have received a copy of the GNU General Public License along + # with this program. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import with_statement ++ + + import os + import sys +@@ -84,7 +84,7 @@ class MSMain(object): + finally: + self.__convert_to_ical(lp_project) + self.__end_calendar() +- print self.calendar() ++ print(self.calendar()) + + def run(self): + self.thread = Thread(target=self.__login_and_go).start() +@@ -99,7 +99,7 @@ if __name__ == "__main__": + try: + project = sys.argv[1] + except IndexError: +- print "Usage: %s <project>" % sys.argv[0] ++ print("Usage: %s <project>" % sys.argv[0]) + exit(1) + + try: +Index: lptools-0.2.0/bin/lp-milestones +=================================================================== +--- lptools-0.2.0.orig/bin/lp-milestones ++++ lptools-0.2.0/bin/lp-milestones +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/python3 + # + # Author: Robert Collins <robert.coll...@canonical.com> + # +@@ -74,7 +74,7 @@ class cmd_delete(LaunchpadCommand): + m = self.launchpad.load('%s/+milestone/%s' % tuple(components)) + try: + m.delete() +- except HTTPError, e: ++ except HTTPError as e: + if e.response.status == 404: + pass + elif e.response.status == 500: +Index: lptools-0.2.0/bin/lp-project +=================================================================== +--- lptools-0.2.0.orig/bin/lp-project ++++ lptools-0.2.0/bin/lp-project +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/python3 + # + # Author: Robert Collins <robert.coll...@canonical.com> + # +Index: lptools-0.2.0/bin/lp-project-upload +=================================================================== +--- lptools-0.2.0.orig/bin/lp-project-upload ++++ lptools-0.2.0/bin/lp-project-upload +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/python3 + + # Copyright (c) 2009 Canonical Ltd. + # +@@ -34,8 +34,8 @@ from lptools import config + def create_release(project, version): + '''Create new release and milestone for LP project.''' + +- print 'Release %s could not be found for project. Create it? (Y/n)' % \ +- version ++ print('Release %s could not be found for project. Create it? (Y/n)' % \ ++ version) + answer = sys.stdin.readline().strip() + if answer.startswith('n'): + sys.exit(0) +@@ -46,21 +46,21 @@ def create_release(project, version): + elif n_series > 1: + msg = 'More than one series exist. Which one would you like to ' \ + 'upload to? Possible series are (listed as index, name):' +- print msg ++ print(msg) + for idx, serie in enumerate(project.series): +- print '\t%i - %s' % (idx, serie.name) +- print 'Enter series index: ' ++ print('\t%i - %s' % (idx, serie.name)) ++ print('Enter series index: ') + answer = sys.stdin.readline().strip() + try: + series = project.series[int(answer)] + except (ValueError, IndexError): +- print >> sys.stderr, 'The series index is invalid (%s).' % answer ++ print('The series index is invalid (%s).' % answer, file=sys.stderr) + sys.exit(3) + else: +- print "Using series named '%s'" % series.name ++ print("Using series named '%s'" % series.name) + else: +- print >> sys.stderr, ('Does not support creating releases if no ' +- 'series exists.') ++ print(('Does not support creating releases if no ' ++ 'series exists.'), file=sys.stderr) + sys.exit(3) + + release_date = datetime.date.today().strftime('%Y-%m-%d') +@@ -86,9 +86,9 @@ def cat_file(f): + + def main(): + if len(sys.argv) < 4 or len(sys.argv) > 7: +- print >> sys.stderr, '''Upload a release tarball to a Launchpad project. ++ print('''Upload a release tarball to a Launchpad project. + +- Usage: %s <project name> <version> <tarball> [new milestone] [changelog file] [releasenotes file]''' % sys.argv[0] ++ Usage: %s <project name> <version> <tarball> [new milestone] [changelog file] [releasenotes file]''' % sys.argv[0], file=sys.stderr) + sys.exit(1) + + new_milestone = None +@@ -127,10 +127,10 @@ def main(): + # Get the signature, if available. + signature = tarball + '.asc' + if not os.path.exists(signature): +- print 'Calling GPG to create tarball signature...' ++ print('Calling GPG to create tarball signature...') + cmd = ['gpg', '--armor', '--sign', '--detach-sig', tarball] + if subprocess.call(cmd) != 0: +- print >> sys.stderr, 'gpg failed, aborting' ++ print('gpg failed, aborting', file=sys.stderr) + + if os.path.exists(signature): + signature_content = open(signature, 'r').read() +@@ -167,8 +167,8 @@ def main(): + if mil.name in [milestone.name for milestone in series.all_milestones]: + series.newMilestone(name=new_milestone) + +- except HTTPError, error: +- print 'An error happened in the upload:', error.content ++ except HTTPError as error: ++ print('An error happened in the upload:', error.content) + sys.exit(1) + + if __name__ == '__main__': +Index: lptools-0.2.0/bin/lp-recipe-status +=================================================================== +--- lptools-0.2.0.orig/bin/lp-recipe-status ++++ lptools-0.2.0/bin/lp-recipe-status +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/python3 + # vi: expandtab:sts=4 + + # Copyright (C) 2011 Jelmer Vernooij <jel...@samba.org> +@@ -22,13 +22,13 @@ + """Show the status of the recipes owned by a particular user. + """ + +-from cStringIO import StringIO ++from io import StringIO + import gzip + import optparse + import os + import re + import sys +-import urllib ++import urllib.request, urllib.parse, urllib.error + + from lptools import config + +@@ -70,7 +70,7 @@ def source_build_find_version(source_bui + if cached_version: + return tuple(cached_version.split(" ")) + # FIXME: Find a more efficient way to retrieve the package/version that was built +- build_log_gz = urllib.urlopen(source_build.build_log_url) ++ build_log_gz = urllib.request.urlopen(source_build.build_log_url) + build_log = gzip.GzipFile(fileobj=StringIO(build_log_gz.read())) + version = None + source_name = None +@@ -172,10 +172,10 @@ def recipe_status_html(launchpad, person + last_per_distroseries = gather_per_distroseries_source_builds(recipe) + source_builds[recipe.name] = last_per_distroseries + relevant_distroseries.update(set(last_per_distroseries)) +- (sp_success, sp_failures) = filter_source_builds(last_per_distroseries.values()) ++ (sp_success, sp_failures) = filter_source_builds(list(last_per_distroseries.values())) + binary_builds[recipe.name] = find_binary_builds(recipe, sp_success) + all_binary_builds_ok[recipe.name] = {} +- for distroseries, recipe_binary_builds in binary_builds[recipe.name].iteritems(): ++ for distroseries, recipe_binary_builds in binary_builds[recipe.name].items(): + all_binary_builds_ok[recipe.name][distroseries] = all( + [bb.buildstate == "Successfully built" for bb in recipe_binary_builds]) + relevant_distroseries = list(relevant_distroseries) +@@ -201,7 +201,7 @@ def recipe_status_text(recipes, outf): + for recipe in recipes: + last_per_distroseries = gather_per_distroseries_source_builds(recipe) + (sp_success, sp_failures) = filter_source_builds( +- last_per_distroseries.values()) ++ list(last_per_distroseries.values())) + sp_success_distroseries = [build.distro_series.name for build in sp_success] + if sp_failures: + outf.write("%s source build failures (%s successful):\n" % ( +Index: lptools-0.2.0/bin/lp-remove-team-members +=================================================================== +--- lptools-0.2.0.orig/bin/lp-remove-team-members ++++ lptools-0.2.0/bin/lp-remove-team-members +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/python3 + # + # Copyright 2011 Canonical Ltd. + # +@@ -28,21 +28,21 @@ from lptools.config import ( + + def main(args): + if len(args) < 3: +- print __doc__ ++ print(__doc__) + return 1 + lp = get_launchpad('lptools on %s' % (socket.gethostname(),)) + team_name = args[1] + team = lp.people[team_name] + members_details = team.members_details + for exile_name in args[2:]: +- print 'remove %s from %s...' % (exile_name, team_name), ++ print('remove %s from %s...' % (exile_name, team_name), end=' ') + for m in members_details: + if m.member.name == exile_name: + m.setStatus(status='Deactivated') +- print 'done' ++ print('done') + break + else: +- print 'not a member?' ++ print('not a member?') + + + if __name__ == '__main__': +Index: lptools-0.2.0/bin/lp-review-list +=================================================================== +--- lptools-0.2.0.orig/bin/lp-review-list ++++ lptools-0.2.0/bin/lp-review-list +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/python3 + # + # Author: Rodney Dawes <rodney.da...@canonical.com> + # +@@ -16,7 +16,7 @@ + # You should have received a copy of the GNU General Public License along + # with this program. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import with_statement ++ + import re + import subprocess + from threading import Thread +@@ -87,7 +87,7 @@ class Window(gtk.Window): + + self.me = self.launchpad.me + +- print "Allo, %s" % self.me.name ++ print("Allo, %s" % self.me.name) + gtk.gdk.threads_enter() + self.__refresh(None) + gtk.gdk.threads_leave() +@@ -114,18 +114,18 @@ class Window(gtk.Window): + + def __load_merges(self): + merges = [] +- mine = self.me.getRequestedReviews(status=[u'Needs review']) ++ mine = self.me.getRequestedReviews(status=['Needs review']) + for merge in mine: + merges.append(merge) + + for team in self.me.super_teams: +- for merge in team.getRequestedReviews(status=[u'Needs review']): ++ for merge in team.getRequestedReviews(status=['Needs review']): + if merge not in merges: + merges.append(merge) + + for merge in merges: + votes = {} +- for key in VOTES.keys(): ++ for key in list(VOTES.keys()): + votes[key] = 0 + + for vote in merge.votes: +@@ -134,14 +134,14 @@ class Window(gtk.Window): + else: + votes[vote.comment.vote] += 1 + +- for key in votes.keys(): ++ for key in list(votes.keys()): + if votes[key] == 0: + votes.pop(key, None) + + vstr = ", ".join( + ["<span color='%s'>%s</span>: %d" \ + % (VOTES[key], key, votes[key]) \ +- for key in votes.keys()] ++ for key in list(votes.keys())] + ) + if vstr == "": + vstr = "No Reviews" +Index: lptools-0.2.0/bin/lp-review-notifier +=================================================================== +--- lptools-0.2.0.orig/bin/lp-review-notifier ++++ lptools-0.2.0/bin/lp-review-notifier +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/python3 + # + # Author: Rodney Dawes <rodney.da...@canonical.com> + # +@@ -16,7 +16,7 @@ + # You should have received a copy of the GNU General Public License along + # with this program. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import with_statement ++ + import os + import sys + +@@ -25,7 +25,7 @@ import gtk + import pygtk + import pynotify + +-from ConfigParser import ConfigParser ++from configparser import ConfigParser + import subprocess + + from xdg.BaseDirectory import ( +@@ -182,7 +182,7 @@ class Main(object): + self.config = Preferences() + + if len(self.config.projects) == 0: +- print "No Projects specified" ++ print("No Projects specified") + sys.exit(1) + + for project in self.config.projects: +@@ -209,14 +209,14 @@ class Main(object): + lp_project = self.launchpad.projects[project] + focus = lp_project.development_focus.branch + except AttributeError: +- print "Project %s has no development focus." % project ++ print("Project %s has no development focus." % project) + return False + except KeyError: +- print "Project %s not found." % project ++ print("Project %s not found." % project) + return False + + if not focus: +- print "Project %s has no development focus." % project ++ print("Project %s has no development focus." % project) + return False + + trunk = focus +@@ -280,7 +280,7 @@ class Main(object): + ICON_NAME) + updated = True + else: +- print "%s status is %s." % (source, c.queue_status) ++ print("%s status is %s." % (source, c.queue_status)) + + if updated: + n.set_urgency(pynotify.URGENCY_LOW) +Index: lptools-0.2.0/bin/lp-set-dup +=================================================================== +--- lptools-0.2.0.orig/bin/lp-set-dup ++++ lptools-0.2.0/bin/lp-set-dup +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/python3 + # -*- coding: UTF-8 -*- + """Sets the "duplicate of" bug of a bug and its dups.""" + +@@ -30,7 +30,7 @@ from launchpadlib.errors import HTTPErro + from lptools import config + + def die(message): +- print >> sys.stderr, "Fatal: " + message ++ print("Fatal: " + message, file=sys.stderr) + sys.exit(1) + + def main(): +@@ -57,10 +57,10 @@ def main(): + # check that the new main bug isn't a duplicate + try: + new_main_bug = launchpad.bugs[args[0]] +- except HTTPError, error: ++ except HTTPError as error: + if error.response.status == 401: +- print >> sys.stderr, ("E: Don't have enough permissions to access " +- "bug %s") % (args[0]) ++ print(("E: Don't have enough permissions to access " ++ "bug %s") % (args[0]), file=sys.stderr) + die(error.content) + else: + raise +@@ -68,7 +68,7 @@ def main(): + if new_main_dup_of is not None: + answer = None + try: +- answer = raw_input("Bug %s is a duplicate of %s; would you like to " ++ answer = input("Bug %s is a duplicate of %s; would you like to " + "use %s as the new main bug instead? [y/N]" % \ + (new_main_bug.id, new_main_dup_of.id, + new_main_dup_of.id)) +@@ -81,38 +81,38 @@ def main(): + # build list of bugs to process, first the dups then the bug + bugs_to_process = [] + for bug_number in args[1:]: +- print "Processing %s" % (bug_number) ++ print("Processing %s" % (bug_number)) + try: + bug = launchpad.bugs[bug_number] +- except HTTPError, error: ++ except HTTPError as error: + if error.response.status == 401: +- print >> sys.stderr, ("W: Don't have enough permissions to " +- "access bug %s") % (bug_number) +- print >> sys.stderr, "W: %s" % (error.content) ++ print(("W: Don't have enough permissions to " ++ "access bug %s") % (bug_number), file=sys.stderr) ++ print("W: %s" % (error.content), file=sys.stderr) + continue + else: + raise + dups = bug.duplicates + if dups is not None: + bugs_to_process.extend(dups) +- print "Found %i dups for %s" % (len(dups), bug_number) ++ print("Found %i dups for %s" % (len(dups), bug_number)) + bugs_to_process.append(bug) + + # process dups first, then their main bug +- print "Would set the following bugs as duplicates of %s: %s" % \ +- (new_main_bug.id, " ".join([str(b.id) for b in bugs_to_process])) ++ print("Would set the following bugs as duplicates of %s: %s" % \ ++ (new_main_bug.id, " ".join([str(b.id) for b in bugs_to_process]))) + + if not options.force: + answer = None + try: +- answer = raw_input("Proceed? [y/N]") ++ answer = input("Proceed? [y/N]") + except: + die("Aborted") + if answer.lower() not in ("y", "yes"): + die("User aborted") + + for bug in bugs_to_process: +- print "Marking bug %s as a duplicate of %s" % (bug.id, new_main_bug.id) ++ print("Marking bug %s as a duplicate of %s" % (bug.id, new_main_bug.id)) + bug.duplicate_of = new_main_bug + bug.lp_save() + +Index: lptools-0.2.0/bin/lp-shell +=================================================================== +--- lptools-0.2.0.orig/bin/lp-shell ++++ lptools-0.2.0/bin/lp-shell +@@ -1,4 +1,4 @@ +-#!/usr/bin/python ++#!/usr/bin/python3 + + # Open an interactive launchpadlib Python shell. + # It supports all known LP service instances and API versions. The login +@@ -52,16 +52,16 @@ def main(): + if len(args) >= 1: + try: + instance = lookup_service_root(args[0]) +- except ValueError, err: +- print 'E: %s' % (err) +- print 'I: Falling back to "production".' ++ except ValueError as err: ++ print('E: %s' % (err)) ++ print('I: Falling back to "production".') + + if len(args) >= 2: + if args[1] in valid_api_versions: + api_version = args[1] + else: +- print 'E: "%s" is not a valid LP API version.' % (args[1]) +- print 'I: Falling back to "1.0".' ++ print('E: "%s" is not a valid LP API version.' % (args[1])) ++ print('I: Falling back to "1.0".') + + if options.anonymous: + launchpad = Launchpad.login_anonymously('lp-shell', instance, +@@ -94,7 +94,7 @@ def main(): + sh.set_banner(sh.IP.BANNER + '\n' + banner) + sh.excepthook = sys.__excepthook__ + except ImportError: +- print "E: ipython not available. Using normal python shell." ++ print("E: ipython not available. Using normal python shell.") + + if sh: + sh() +@@ -106,7 +106,7 @@ def main(): + try: + import readline + except ImportError: +- print 'I: readline module not available.' ++ print('I: readline module not available.') + else: + import rlcompleter + readline.parse_and_bind("tab: complete")