=== modified file 'setup.py'
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
 
-description = file(os.path.join(os.path.dirname(__file__), 'README'), 'rb').read()
+with open(os.path.join(os.path.dirname(__file__), 'README'), 'r') as f:
+    description = f.read()
 
 setup(
     name='lptools',
@@ -20,7 +21,7 @@ setup(
                                              'templates/recipe-status.html'])],
     packages=['lptools'],
     scripts=glob('bin/*'),
-    classifiers = [
+    classifiers=[
         '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.dawes@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.collins@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.collins@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 <jelmer@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.dawes@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.dawes@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")
