[py3porters-devel] Porting of apt-listchanges to Python 3
James Lu
GLolol1 at hotmail.com
Wed Jun 3 02:05:26 UTC 2015
Hello all,
Lately, there has been an ongoing effort
<https://wiki.debian.org/Python/Python3Port> to port Python code in
Debian to Python 3. So, I've decided to take a look at apt-listchanges,
and modified it so that it supports both Python 2 and 3. The code is
currently hosted at GitHub, since I don't have access to alioth:
https://github.com/GLolol/apt-listchanges
I had to make a lot of changes for the code to work properly. For
starters I migrated the Gtk frontend from the deprecated PyGTK to the
newer PyGObject: this involved changing Glade signals from destroy-event
to destroy for window closing, updating imports (gtk.glade->gettext for
example), and at the same time transitioning the code to GTK 3. For some
of this, GNOME's pygi-convert.sh and Glade were quite helpful.
I also adjusted many imports using "try, import Y, except ImportError,
import X as Y" clauses, which preserve compatibility even though many
libraries have renamed in Python 3. Text strings had to be updated to
handle the difference between bytes and str, etc. Finally, I changed the
build system from python-support to dh_python3 in order to build Python
3 .debs.
So far, I've tested all the various frontends (pager, browser,
xterm-pager, xterm-browser, text, mail, gtk) from the command line on
.deb files, which seemed to work fine. The only thing untested is the
actual APT pipeline support, since I haven't gotten any NEWS files that
would be displayed there. Anyone, please feel free to comment and review
the changes, which can be found here:
https://github.com/GLolol/apt-listchanges/compare/5e72a2cf32c2395f027bfb1c3cf3e4e72dceef4a...debian-sid
(patch form <cid:part4.06010006.07000306 at hotmail.com>).
Best,
James
<https://github.com/GLolol/apt-listchanges/compare/5e72a2cf32c2395f027bfb1c3cf3e4e72dceef4a...debian-sid>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.alioth.debian.org/pipermail/py3porters-devel/attachments/20150602/95bb60a1/attachment-0001.html>
-------------- next part --------------
From 642fc81252aef1d624699c0e06ce98f2b158fea9 Mon Sep 17 00:00:00 2001
From: James Lu <GLolol1 at hotmail.com>
Date: Mon, 1 Jun 2015 21:55:08 -0700
Subject: [PATCH 1/4] Begin port to Python 3
- Replacing python-gtk2 and python-glade2 code with python3-gi
- Many syntax / import fixes in a way that should preserve compatibility with both Python 2 and 3
---
apt-listchanges.py | 24 +++---
apt-listchanges/ALCConfig.py | 11 ++-
apt-listchanges/AptListChangesGtk.py | 58 +++++++------
apt-listchanges/DebianFiles.py | 12 +--
apt-listchanges/apt-listchanges.glade | 152 ----------------------------------
apt-listchanges/apt-listchanges.ui | 144 ++++++++++++++++++++++++++++++++
apt-listchanges/apt_listchanges.py | 36 ++++----
7 files changed, 223 insertions(+), 214 deletions(-)
delete mode 100644 apt-listchanges/apt-listchanges.glade
create mode 100644 apt-listchanges/apt-listchanges.ui
diff --git a/apt-listchanges.py b/apt-listchanges.py
index d73affb..39a88b8 100755
--- a/apt-listchanges.py
+++ b/apt-listchanges.py
@@ -26,8 +26,12 @@
import sys, os, os.path
import apt_pkg
-import anydbm
-import commands
+try:
+ import subprocess
+ from dbm import ndbm
+except ImportError:
+ import anydbm as ndbm
+ import commands as subprocess
sys.path += [os.path.dirname(sys.argv[0]) + '/apt-listchanges', '/usr/share/apt-listchanges']
from ALChacks import *
@@ -83,8 +87,8 @@ def main():
if config.save_seen:
try:
- seen = anydbm.open(config.save_seen, 'c')
- seen.has_key('foo%0')
+ seen = dbm.ndbm.open(config.save_seen, 'c')
+ 'foo%0' in seen
except:
sys.stderr.write(_("database %s failed to load.\n") % config.save_seen)
sys.exit(1)
@@ -119,7 +123,7 @@ def main():
fromversion = None
if not config.show_all:
- if config.save_seen and seen.has_key(srcpackage):
+ if config.save_seen and srcpakge in seen:
fromversion = seen[srcpackage]
elif config.since:
fromversion = config.since
@@ -140,7 +144,7 @@ def main():
#
# This is why even if we've seen a package we may miss bits of
# changelog in some odd cases
- if found.has_key(srcpackage) and \
+ if srcpackage in found and \
apt_pkg.version_compare(srcversion, found[srcpackage]) <= 0:
continue
@@ -186,7 +190,7 @@ def main():
package = rec.package
header = _('News for %s') % package
- if len(filter(lambda x: x != package, source_packages[package])) > 0:
+ if len([x for x in source_packages[package] if x != package]) > 0:
# Differing source and binary packages
header += ' (' + ' '.join(source_packages[package]) + ')'
news += '--- ' + header + ' ---\n' + rec.changes
@@ -197,7 +201,7 @@ def main():
package = rec.package
header = _('Changes for %s') % package
- if len(filter(lambda x: x != package, source_packages[package])) > 0:
+ if len([x for x in source_packages[package] if x != package]) > 0:
# Differing source and binary packages
header += ' (' + ' '.join(source_packages[package]) + ')'
changes += '--- ' + header + ' ---\n' + rec.changes
@@ -226,7 +230,7 @@ def main():
sys.stderr.write(_("Confirmation failed, don't save seen state")+'.\n')
sys.exit(0)
- hostname = commands.getoutput('hostname')
+ hostname = subprocess.getoutput('hostname')
if config.email_address and os.path.exists("/usr/sbin/sendmail"):
if changes:
@@ -239,7 +243,7 @@ def main():
# Write out seen db
if config.save_seen:
- seen = anydbm.open(config.save_seen, 'c')
+ seen = dbm.ndbm.open(config.save_seen, 'c')
for (key, value) in seen_new.items():
seen[key] = value
seen.close()
diff --git a/apt-listchanges/ALCConfig.py b/apt-listchanges/ALCConfig.py
index 1f490a8..b15e8f8 100644
--- a/apt-listchanges/ALCConfig.py
+++ b/apt-listchanges/ALCConfig.py
@@ -23,7 +23,10 @@
# MA 02111-1307 USA
#
-import ConfigParser
+try:
+ import ConfigParser
+except ImportError:
+ import configparser as ConfigParser
import getopt
import sys, os
import re
@@ -130,8 +133,8 @@ def getopt(self, argv):
if arg in self.allowed_which:
self.which = arg
else:
- print _('Unknown option %s for --which. Allowed are: %s.') % \
- (arg, ', '.join(self.allowed_which))
+ print(_('Unknown option %s for --which. Allowed are: %s.') % \
+ (arg, ', '.join(self.allowed_which)))
sys.exit(1)
elif opt == '--debug':
self.debug = 1
@@ -145,7 +148,7 @@ def getopt(self, argv):
if self.since is not None:
if len(args) is not 1:
- print _('--since=<version> expects a only path to a .deb')
+ print(_('--since=<version> expects a only path to a .deb'))
sys.exit(1)
self.save_seen = None
return args
diff --git a/apt-listchanges/AptListChangesGtk.py b/apt-listchanges/AptListChangesGtk.py
index b7c1fcd..bd0ab24 100644
--- a/apt-listchanges/AptListChangesGtk.py
+++ b/apt-listchanges/AptListChangesGtk.py
@@ -2,48 +2,52 @@
from apt_listchanges import frontend
-import pygtk
-pygtk.require('2.0')
-import gtk
-import gobject
-import gtk.glade
+import gi
+gi.require_version('Gtk', '3.0')
+import gettext
+
+from gi.repository import Gtk
+from gi.repository import GObject
from ALChacks import *
# set the i18n dirs
-gtk.glade.bindtextdomain("apt-listchanges", "/usr/share/locale")
-gtk.glade.textdomain("apt-listchanges")
+gettext.bindtextdomain("apt-listchanges", "/usr/share/locale")
+gettext.textdomain("apt-listchanges")
class gtk2(frontend):
def flush_interface(self):
- while gtk.events_pending():
- gtk.main_iteration()
+ while Gtk.events_pending():
+ Gtk.main_iteration()
def cb_close(self, widget):
if self.button_close.get_property("sensitive") == False:
# window manager was used to close before the parsing was complete
sys.exit()
- gtk.main_quit()
+ Gtk.main_quit()
def __init__(self, packages, config):
frontend.__init__(self,packages, config)
+ self.builder = Gtk.Builder()
try:
- file("apt-listchanges/apt-listchanges.glade").close()
- self.glade = gtk.glade.XML("apt-listchanges/apt-listchanges.glade")
- except:
- self.glade = gtk.glade.XML("/usr/share/apt-listchanges/apt-listchanges.glade")
- self.window_main = self.glade.get_widget("window_main")
- self.window_main.connect("destroy", self.cb_close)
- self.glade.signal_connect("on_button_close_clicked", self.cb_close)
- self.progressbar_main = self.glade.get_widget("progressbar_main")
- self.button_close = self.glade.get_widget("button_close")
+ self.builder.add_from_file("apt-listchanges/apt-listchanges.ui")
+ except ValueError:
+ self.builder.add_from_file("/usr/share/apt-listchanges/apt-listchanges.ui")
+ self.window_main = self.builder.get_object("window_main")
+ handlers = {
+ "on_button_close_clicked": self.cb_close,
+ "on_window_main_destroy_event": self.cb_close,
+ }
+ self.progressbar_main = self.builder.get_object("progressbar_main")
+ self.button_close = self.builder.get_object("button_close")
+ self.builder.connect_signals(handlers)
self.flush_interface()
def display_output(self,text):
self.button_close.set_sensitive(True)
- buf = self.glade.get_widget("textview_main").get_buffer()
+ buf = self.builder.get_object("textview_main").get_buffer()
buf.set_text(self._render(text))
- gtk.main()
+ Gtk.main()
def update_progress(self):
if not hasattr(self,'progress'):
@@ -60,12 +64,12 @@ def progress_done(self):
self.flush_interface()
def confirm(self):
- m = gtk.MessageDialog(self.window_main,
- gtk.DIALOG_MODAL,
- gtk.MESSAGE_QUESTION,
- gtk.BUTTONS_YES_NO)
- m.set_default_response(gtk.RESPONSE_YES)
+ m = Gtk.MessageDialog(self.window_main,
+ Gtk.DialogFlags.MODAL,
+ Gtk.MessageType.QUESTION,
+ Gtk.ButtonsType.YES_NO)
+ m.set_default_response(Gtk.ResponseType.YES)
m.set_markup("<big><b>%s</b></big>\n\n%s" % (_("Continue Installation?"), _("You can abort the installation if you select 'no'.")))
- if m.run() == gtk.RESPONSE_NO:
+ if m.run() == Gtk.ResponseType.NO:
return False
return True
diff --git a/apt-listchanges/DebianFiles.py b/apt-listchanges/DebianFiles.py
index 0efc41e..18818dd 100644
--- a/apt-listchanges/DebianFiles.py
+++ b/apt-listchanges/DebianFiles.py
@@ -23,8 +23,9 @@
# MA 02111-1307 USA
#
+from __future__ import print_function
import re
-import sys, os, os.path
+import sys, os
import tempfile
import gzip
import errno
@@ -35,6 +36,7 @@
import apt_pkg
from ALChacks import *
+from functools import reduce
# TODO:
# indexed lookups by package at least, maybe by arbitrary field
@@ -110,8 +112,8 @@ def readdeb(self, deb):
self.stanzas.append(ControlStanza(fh.read()))
def find(self, field, value):
- if self.index.has_key(field):
- if self.index[field].has_key(value):
+ if field in self.index:
+ if value in self.index[field]:
return self.index[field][value]
else:
return None
@@ -191,13 +193,13 @@ def read_changelog(self, filename, since_version, reverse=False):
for filename in filenames:
try:
if os.path.isdir(filename):
- print >> sys.stderr, _("Ignoring `%s' (seems to be a directory!)") % filename
+ print(_("Ignoring `%s' (seems to be a directory!)") % filename, file=sys.stderr)
elif filename.endswith('.gz'):
fd = gzip.GzipFile(filename)
else:
fd = open(filename)
break
- except IOError, e:
+ except IOError as e:
if e.errno == errno.ENOENT:
pass
else:
diff --git a/apt-listchanges/apt-listchanges.glade b/apt-listchanges/apt-listchanges.glade
deleted file mode 100644
index d5998a9..0000000
--- a/apt-listchanges/apt-listchanges.glade
+++ /dev/null
@@ -1,152 +0,0 @@
-<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
-<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
-
-<glade-interface>
-
-<widget class="GtkWindow" id="window_main">
- <property name="border_width">6</property>
- <property name="visible">True</property>
- <property name="title" translatable="yes">List the changes</property>
- <property name="type">GTK_WINDOW_TOPLEVEL</property>
- <property name="window_position">GTK_WIN_POS_CENTER</property>
- <property name="modal">False</property>
- <property name="default_width">600</property>
- <property name="default_height">400</property>
- <property name="resizable">True</property>
- <property name="destroy_with_parent">False</property>
- <property name="decorated">True</property>
- <property name="skip_taskbar_hint">False</property>
- <property name="skip_pager_hint">False</property>
- <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
- <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
- <property name="focus_on_map">True</property>
- <signal name="destroy_event" handler="on_window_main_destroy_event" last_modification_time="Sat, 05 Feb 2005 13:12:24 GMT"/>
-
- <child>
- <widget class="GtkVBox" id="vbox1">
- <property name="border_width">6</property>
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkLabel" id="label_header">
- <property name="visible">True</property>
- <property name="label" translatable="yes"><big><b>Changelogs</b></big>
-
-The following changes are found in the packages you are about to install:</property>
- <property name="use_underline">True</property>
- <property name="use_markup">True</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkScrolledWindow" id="scrolledwindow2">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
- <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
- <property name="shadow_type">GTK_SHADOW_IN</property>
- <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
-
- <child>
- <widget class="GtkTextView" id="textview_main">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="editable">False</property>
- <property name="overwrite">False</property>
- <property name="accepts_tab">True</property>
- <property name="justification">GTK_JUSTIFY_LEFT</property>
- <property name="wrap_mode">GTK_WRAP_NONE</property>
- <property name="cursor_visible">False</property>
- <property name="pixels_above_lines">0</property>
- <property name="pixels_below_lines">0</property>
- <property name="pixels_inside_wrap">0</property>
- <property name="left_margin">0</property>
- <property name="right_margin">0</property>
- <property name="indent">0</property>
- <property name="text" translatable="yes">Reading changelogs. Please wait.</property>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkProgressBar" id="progressbar_main">
- <property name="orientation">GTK_PROGRESS_LEFT_TO_RIGHT</property>
- <property name="fraction">0</property>
- <property name="pulse_step">0.10000000149</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkHBox" id="hbox4">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkHButtonBox" id="hbuttonbox1">
- <property name="visible">True</property>
- <property name="layout_style">GTK_BUTTONBOX_END</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkButton" id="button_close">
- <property name="visible">True</property>
- <property name="sensitive">False</property>
- <property name="can_default">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-close</property>
- <property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <signal name="clicked" handler="on_button_close_clicked" last_modification_time="Sat, 05 Feb 2005 11:13:29 GMT"/>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- </widget>
- </child>
-</widget>
-
-</glade-interface>
diff --git a/apt-listchanges/apt-listchanges.ui b/apt-listchanges/apt-listchanges.ui
new file mode 100644
index 0000000..69eb02b
--- /dev/null
+++ b/apt-listchanges/apt-listchanges.ui
@@ -0,0 +1,144 @@
+<?xml version="1.0"?>
+<!--*- mode: xml -*-->
+<interface>
+ <object class="GtkTextBuffer" id="textbuffer1">
+ <property name="text">Reading changelogs. Please wait.</property>
+ </object>
+ <object class="GtkWindow" id="window_main">
+ <property name="border_width">6</property>
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">List the changes</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_CENTER</property>
+ <property name="modal">False</property>
+ <property name="default_width">600</property>
+ <property name="default_height">400</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <signal handler="on_window_main_destroy_event" last_modification_time="Sat, 05 Feb 2005 13:12:24 GMT" name="destroy_event"/>
+ <child>
+ <object class="GtkVBox" id="vbox1">
+ <property name="border_width">6</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label_header">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"><big><b>Changelogs</b></big>
+
+The following changes are found in the packages you are about to install:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </object>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+ <child>
+ <object class="GtkTextView" id="textview_main">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">False</property>
+ <property name="overwrite">False</property>
+ <property name="accepts_tab">True</property>
+ <property name="justification">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap_mode">GTK_WRAP_NONE</property>
+ <property name="cursor_visible">False</property>
+ <property name="pixels_above_lines">0</property>
+ <property name="pixels_below_lines">0</property>
+ <property name="pixels_inside_wrap">0</property>
+ <property name="left_margin">0</property>
+ <property name="right_margin">0</property>
+ <property name="indent">0</property>
+ <property name="buffer">textbuffer1</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkProgressBar" id="progressbar_main">
+ <property name="orientation">GTK_PROGRESS_LEFT_TO_RIGHT</property>
+ <property name="fraction">0</property>
+ <property name="pulse_step">0.10000000149</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ </object>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox4">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkHButtonBox" id="hbuttonbox1">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkButton" id="button_close">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-close</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal handler="on_button_close_clicked" last_modification_time="Sat, 05 Feb 2005 11:13:29 GMT" name="clicked"/>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/apt-listchanges/apt_listchanges.py b/apt-listchanges/apt_listchanges.py
index cc879e5..a7bc273 100644
--- a/apt-listchanges/apt_listchanges.py
+++ b/apt-listchanges/apt_listchanges.py
@@ -25,16 +25,21 @@
import sys
import os
-import os.path
import re
import locale
import email.Message
import email.Header
import email.Charset
-import cStringIO
+try:
+ import io
+except ImportError:
+ import cStringIO as io
import tempfile
from ALChacks import *
+if sys.version_info[0] >= 3:
+ unicode = str
+
# TODO:
# newt-like frontend, or maybe some GUI bit
# keep track of tar/dpkg-deb errors like in pre-2.0
@@ -107,7 +112,7 @@ def read_apt_pipeline(config):
return ordered_filenames
def mail_changes(address, changes, subject):
- print "apt-listchanges: " + _("Mailing %s: %s") % (address, subject)
+ print("apt-listchanges: " + _("Mailing %s: %s") % (address, subject))
charset = email.Charset.Charset('utf-8')
charset.body_encoding = '8bit'
@@ -145,13 +150,12 @@ def make_frontend(name, packages, config):
# import from that. that would mean a uniform mechanism for all
# frontends (that would become small files inside
if name == "gtk":
- if os.environ.has_key("DISPLAY"):
+ if "DISPLAY" in os.environ:
try:
gtk = __import__("AptListChangesGtk")
frontends[name] = gtk.gtk2
- except ImportError, e:
- sys.stderr.write(_("The gtk frontend needs a working python-gtk2 "
- "and python-glade2.\n"
+ except ImportError as e:
+ sys.stderr.write(_("The gtk frontend needs a working python-gi.\n"
"Those imports can not be found. Falling back "
"to pager.\n"
"The error is: %s\n") % e)
@@ -159,7 +163,7 @@ def make_frontend(name, packages, config):
else:
name = 'pager'
- if not frontends.has_key(name):
+ if name not in frontends:
return None
return frontends[name](packages, config)
@@ -212,7 +216,7 @@ def display_output(self, text):
sock.close()
db = dc.Debconf(read=dcfd, write=dcfd)
tmp = tempfile.NamedTemporaryFile(prefix="apt-listchanges-tmp")
- os.fchmod(tmp.fileno(), 0644)
+ os.fchmod(tmp.fileno(), 0o644)
tmp.write('''Template: apt-listchanges/info
Type: title
Description: NEWS
@@ -245,7 +249,7 @@ class ttyconfirm:
def confirm(self):
try:
tty = open('/dev/tty', 'r+')
- except IOError, e:
+ except IOError as e:
return -1
tty.write('apt-listchanges: ' + _('Do you want to continue? [Y/n] '))
tty.flush()
@@ -320,12 +324,12 @@ class pager(runcommand, ttyconfirm, fancyprogress, frontend):
def __init__(self, *args):
if not 'LESS' in os.environ:
os.environ['LESS'] = "-P?e(q to quit)"
- apply(frontend.__init__, [self] + list(args))
+ frontend.__init__(*[self] + list(args))
self.command = self.config.get('pager', 'sensible-pager')
class xterm(runcommand, ttyconfirm, fancyprogress, frontend):
def __init__(self, *args):
- apply(frontend.__init__, [self] + list(args))
+ frontend.__init__(*[self] + list(args))
self.mode = os.P_NOWAIT
self.xterm = self.config.get('xterm', 'x-terminal-emulator')
@@ -334,7 +338,7 @@ def get_command(self):
class xterm_pager(xterm):
def __init__(self, *args):
- apply(xterm.__init__, [self] + list(args))
+ xterm.__init__(*[self] + list(args))
self.xterm_command = self.config.get('pager', 'sensible-pager')
class html:
@@ -354,7 +358,7 @@ class html:
title = '''apt-listchanges output'''
def _render(self, text):
- htmltext = cStringIO.StringIO()
+ htmltext = io.StringIO()
htmltext.write('''<html>
<head>
<title>''')
@@ -388,13 +392,13 @@ def _render(self, text):
class browser(html, pager):
def __init__(self, *args):
- apply(pager.__init__, [self] + list(args))
+ pager.__init__(*[self] + list(args))
self.command = self.config.get('browser', 'sensible-browser')
def set_title(self, text):
self.title = text
class xterm_browser(html, xterm):
def __init__(self, *args):
- apply(xterm.__init__, [self] + list(args))
+ xterm.__init__(*[self] + list(args))
self.xterm_command = self.config.get('browser', 'sensible-browser')
From 7ce945e328434fd6fbb1d7598b7cb85a0107e369 Mon Sep 17 00:00:00 2001
From: James Lu <GLolol1 at hotmail.com>
Date: Tue, 2 Jun 2015 17:41:02 -0700
Subject: [PATCH 2/4] fix browser and gtk frontends
- In Glade, migrate the signal from destroy-event to destroy. Otherwise, the window doesn't get the event to close properly.
---
apt-listchanges/AptListChangesGtk.py | 7 ++-
apt-listchanges/apt-listchanges.ui | 88 +++++++++++++-----------------------
apt-listchanges/apt_listchanges.py | 6 +--
3 files changed, 37 insertions(+), 64 deletions(-)
diff --git a/apt-listchanges/AptListChangesGtk.py b/apt-listchanges/AptListChangesGtk.py
index bd0ab24..c00789f 100644
--- a/apt-listchanges/AptListChangesGtk.py
+++ b/apt-listchanges/AptListChangesGtk.py
@@ -8,6 +8,7 @@
from gi.repository import Gtk
from gi.repository import GObject
+import sys
from ALChacks import *
@@ -21,10 +22,8 @@ def flush_interface(self):
Gtk.main_iteration()
def cb_close(self, widget):
- if self.button_close.get_property("sensitive") == False:
- # window manager was used to close before the parsing was complete
- sys.exit()
Gtk.main_quit()
+ sys.exit()
def __init__(self, packages, config):
frontend.__init__(self,packages, config)
@@ -36,7 +35,7 @@ def __init__(self, packages, config):
self.window_main = self.builder.get_object("window_main")
handlers = {
"on_button_close_clicked": self.cb_close,
- "on_window_main_destroy_event": self.cb_close,
+ "on_window_main_destroy": self.cb_close,
}
self.progressbar_main = self.builder.get_object("progressbar_main")
self.button_close = self.builder.get_object("button_close")
diff --git a/apt-listchanges/apt-listchanges.ui b/apt-listchanges/apt-listchanges.ui
index 69eb02b..9963b97 100644
--- a/apt-listchanges/apt-listchanges.ui
+++ b/apt-listchanges/apt-listchanges.ui
@@ -1,141 +1,115 @@
-<?xml version="1.0"?>
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.18.3 -->
<!--*- mode: xml -*-->
<interface>
+ <requires lib="gtk+" version="3.0"/>
<object class="GtkTextBuffer" id="textbuffer1">
<property name="text">Reading changelogs. Please wait.</property>
</object>
<object class="GtkWindow" id="window_main">
- <property name="border_width">6</property>
<property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="border_width">6</property>
<property name="title" translatable="yes">List the changes</property>
- <property name="type">GTK_WINDOW_TOPLEVEL</property>
- <property name="window_position">GTK_WIN_POS_CENTER</property>
- <property name="modal">False</property>
+ <property name="window_position">center</property>
<property name="default_width">600</property>
<property name="default_height">400</property>
- <property name="resizable">True</property>
- <property name="destroy_with_parent">False</property>
- <property name="decorated">True</property>
- <property name="skip_taskbar_hint">False</property>
- <property name="skip_pager_hint">False</property>
- <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
- <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
- <property name="focus_on_map">True</property>
- <signal handler="on_window_main_destroy_event" last_modification_time="Sat, 05 Feb 2005 13:12:24 GMT" name="destroy_event"/>
+ <signal name="destroy" handler="on_window_main_destroy" swapped="no"/>
<child>
<object class="GtkVBox" id="vbox1">
- <property name="border_width">6</property>
<property name="visible">True</property>
- <property name="homogeneous">False</property>
+ <property name="can_focus">False</property>
+ <property name="border_width">6</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel" id="label_header">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
<property name="label" translatable="yes"><big><b>Changelogs</b></big>
The following changes are found in the packages you are about to install:</property>
- <property name="use_underline">True</property>
<property name="use_markup">True</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
+ <property name="use_underline">True</property>
</object>
<packing>
- <property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
+ <property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow2">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
- <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
- <property name="shadow_type">GTK_SHADOW_IN</property>
- <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+ <property name="shadow_type">in</property>
<child>
<object class="GtkTextView" id="textview_main">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="editable">False</property>
- <property name="overwrite">False</property>
- <property name="accepts_tab">True</property>
- <property name="justification">GTK_JUSTIFY_LEFT</property>
- <property name="wrap_mode">GTK_WRAP_NONE</property>
<property name="cursor_visible">False</property>
- <property name="pixels_above_lines">0</property>
- <property name="pixels_below_lines">0</property>
- <property name="pixels_inside_wrap">0</property>
- <property name="left_margin">0</property>
- <property name="right_margin">0</property>
- <property name="indent">0</property>
<property name="buffer">textbuffer1</property>
</object>
</child>
</object>
<packing>
- <property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
+ <property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkProgressBar" id="progressbar_main">
- <property name="orientation">GTK_PROGRESS_LEFT_TO_RIGHT</property>
- <property name="fraction">0</property>
+ <property name="can_focus">False</property>
<property name="pulse_step">0.10000000149</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
</object>
<packing>
- <property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
+ <property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkHBox" id="hbox4">
<property name="visible">True</property>
- <property name="homogeneous">False</property>
+ <property name="can_focus">False</property>
<property name="spacing">6</property>
<child>
<object class="GtkHButtonBox" id="hbuttonbox1">
<property name="visible">True</property>
- <property name="layout_style">GTK_BUTTONBOX_END</property>
+ <property name="can_focus">False</property>
<property name="spacing">6</property>
+ <property name="layout_style">end</property>
<child>
<object class="GtkButton" id="button_close">
+ <property name="label">gtk-close</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
- <property name="can_default">True</property>
<property name="can_focus">True</property>
- <property name="label">gtk-close</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
<property name="use_stock">True</property>
- <property name="relief">GTK_RELIEF_NORMAL</property>
- <property name="focus_on_click">True</property>
- <signal handler="on_button_close_clicked" last_modification_time="Sat, 05 Feb 2005 11:13:29 GMT" name="clicked"/>
+ <signal name="clicked" handler="on_button_close_clicked" swapped="no"/>
</object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
</child>
</object>
<packing>
- <property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
+ <property name="position">0</property>
</packing>
</child>
</object>
<packing>
- <property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
+ <property name="position">3</property>
</packing>
</child>
</object>
diff --git a/apt-listchanges/apt_listchanges.py b/apt-listchanges/apt_listchanges.py
index a7bc273..f9042c5 100644
--- a/apt-listchanges/apt_listchanges.py
+++ b/apt-listchanges/apt_listchanges.py
@@ -27,9 +27,9 @@
import os
import re
import locale
-import email.Message
-import email.Header
-import email.Charset
+import email.message
+import email.header
+import email.charset
try:
import io
except ImportError:
From 0f65a2fcc53a3dca18c1d48dd5cc88738fb6205b Mon Sep 17 00:00:00 2001
From: James Lu <GLolol1 at hotmail.com>
Date: Tue, 2 Jun 2015 18:14:30 -0700
Subject: [PATCH 3/4] More Python 3-specific fixes
---
apt-listchanges.py | 9 ++++-----
apt-listchanges/DebianFiles.py | 14 +++++++++-----
apt-listchanges/apt_listchanges.py | 29 +++++++++++++++++++----------
3 files changed, 32 insertions(+), 20 deletions(-)
diff --git a/apt-listchanges.py b/apt-listchanges.py
index 39a88b8..2c9f190 100755
--- a/apt-listchanges.py
+++ b/apt-listchanges.py
@@ -171,12 +171,11 @@ def main():
if config.save_seen:
seen.close()
- all_news = all_news.values()
- all_changelogs = all_changelogs.values()
- all_binnmus = all_binnmus.values()
+ all_news = list(all_news.values())
+ all_changelogs = list(all_changelogs.values())
+ all_binnmus = list(all_binnmus.values())
for batch in (all_news, all_changelogs, all_binnmus):
- batch.sort(lambda a, b: -cmp(a.urgency, b.urgency) or
- cmp(a.package, b.package))
+ batch.sort(key=lambda x: x.urgency or x.package)
# FIXME: two headers with -h
all_changelogs = all_binnmus + all_changelogs
diff --git a/apt-listchanges/DebianFiles.py b/apt-listchanges/DebianFiles.py
index 18818dd..d3f9f0c 100644
--- a/apt-listchanges/DebianFiles.py
+++ b/apt-listchanges/DebianFiles.py
@@ -23,7 +23,7 @@
# MA 02111-1307 USA
#
-from __future__ import print_function
+from __future__ import print_function, unicode_literals
import re
import sys, os
import tempfile
@@ -54,10 +54,10 @@ def numeric_urgency(u):
class ControlStanza:
source_version_re = re.compile('^\S+ \((?P<version>.*)\).*')
- def __init__(self, str):
+ def __init__(self, s):
field = None
- for line in str.split('\n'):
+ for line in s.split('\n'):
if not line:
break
if line[0] in (' ', '\t'):
@@ -86,7 +86,7 @@ def version(self):
"""
v = self.Version
if hasattr(self, 'Source'):
- match = self.source_version_re.match(self.Source)
+ match = self.source_version_re.match(self.Source.decode('utf-8'))
if match:
sv = match.group('version')
if not v.startswith(sv):
@@ -105,7 +105,10 @@ def makeindex(self, field):
self.index[field][getattr(stanza, field)] = stanza
def readfile(self, file):
- self.stanzas += [ControlStanza(x) for x in open(file, 'r').read().split('\n\n') if x]
+ try:
+ self.stanzas += [ControlStanza(x) for x in open(file, 'r').read().split('\n\n') if x]
+ except UnicodeDecodeError:
+ self.stanzas += [ControlStanza(x) for x in open(file, 'r').read().decode('utf-8').split('\n\n') if x]
def readdeb(self, deb):
fh = os.popen('dpkg-deb -f %s' % deb)
@@ -213,6 +216,7 @@ def read_changelog(self, filename, since_version, reverse=False):
entries = []
is_debian_changelog = 0
for line in fd.readlines():
+ line = line.decode('utf-8')
match = self.changelog_header.match(line)
if match:
entries += [entry]
diff --git a/apt-listchanges/apt_listchanges.py b/apt-listchanges/apt_listchanges.py
index f9042c5..5ee4617 100644
--- a/apt-listchanges/apt_listchanges.py
+++ b/apt-listchanges/apt_listchanges.py
@@ -23,6 +23,7 @@
# MA 02111-1307 USA
#
+# Implicitly use Unicode for all strings
import sys
import os
import re
@@ -31,9 +32,9 @@
import email.header
import email.charset
try:
- import io
+ import StringIO as io
except ImportError:
- import cStringIO as io
+ import io
import tempfile
from ALChacks import *
@@ -186,13 +187,16 @@ def _render(self, text):
for line in text.split('\n'):
try:
# changelogs are supposed to be in UTF-8
- uline = line.decode('utf-8')
+ if sys.version_info[0] < 3:
+ uline = line.decode('utf-8')
+ else:
+ uline = line
except UnicodeError:
# ... but handle gracefully if they aren't.
# (That's also the reason we do it line by line.)
# This is possibly wrong, but our best guess.
uline = line.decode('iso8859-1')
- newtext.append(uline.encode(locale.getpreferredencoding() or 'ascii', 'replace'))
+ newtext.append(uline)
return '\n'.join(newtext)
def confirm(self):
@@ -217,7 +221,7 @@ def display_output(self, text):
db = dc.Debconf(read=dcfd, write=dcfd)
tmp = tempfile.NamedTemporaryFile(prefix="apt-listchanges-tmp")
os.fchmod(tmp.fileno(), 0o644)
- tmp.write('''Template: apt-listchanges/info
+ tmp.write(b'''Template: apt-listchanges/info
Type: title
Description: NEWS
@@ -305,7 +309,7 @@ def display_output(self, text):
return
tmp = tempfile.NamedTemporaryFile(prefix="apt-listchanges-tmp", suffix=self.suffix)
- tmp.write(self._render(text))
+ tmp.write(self._render(text).encode('utf-8'))
tmp.flush()
shellcommand = self.get_command() + ' ' + tmp.name
@@ -373,15 +377,20 @@ def _render(self, text):
for line in text.split('\n'):
try:
# changelogs are supposed to be in UTF-8
- uline = line.decode('utf-8')
+ if sys.version_info[0] < 3:
+ uline = line.decode('utf-8')
+ else:
+ uline = line
except UnicodeError:
# ... but handle gracefully if they aren't.
# This is possibly wrong, but our best guess.
uline = line.decode('iso8859-1')
line = uline.encode('utf-8').replace(
- '&', '&').replace(
- '<', '<').replace(
- '>', '>')
+ b'&', b'&').replace(
+ b'<', b'<').replace(
+ b'>', b'>')
+ if sys.version_info[0] >= 3:
+ line = line.decode('utf-8')
line = self.lp_bug_stanza_re.sub(lambda m: self.lp_bug_re.sub(self.lp_bug_fmt, m.group(0)), line)
line = self.bug_stanza_re.sub(lambda m: self.bug_re.sub(self.bug_fmt, m.group(0)), line)
line = self.email_re.sub(r'<a href="mailto:\g<0>">\g<0></a>', line)
From be624db8408436bc396c5f236733e588e7b99b9a Mon Sep 17 00:00:00 2001
From: James Lu <GLolol1 at hotmail.com>
Date: Tue, 2 Jun 2015 18:23:13 -0700
Subject: [PATCH 4/4] Migrate debian/ to dh_python3 and fix po/Makefile
---
debian/control | 9 ++--
debian/pyversions | 1 -
debian/rules | 4 +-
po/Makefile | 2 +-
po/apt-listchanges.pot | 139 +++++++++++++++++++++++++++----------------------
5 files changed, 86 insertions(+), 69 deletions(-)
delete mode 100644 debian/pyversions
diff --git a/debian/control b/debian/control
index 9b787d9..d42cf4d 100644
--- a/debian/control
+++ b/debian/control
@@ -3,18 +3,19 @@ Section: utils
Priority: standard
Maintainer: Sandro Tosi <morph at debian.org>
Uploaders: Thadeu Lima de Souza Cascardo <cascardo at minaslivre.org>
-Standards-Version: 3.9.5
+Standards-Version: 3.9.6
Vcs-Browser: http://anonscm.debian.org/gitweb/?p=collab-maint/apt-listchanges.git;a=summary
Vcs-Git: git://anonscm.debian.org/collab-maint/apt-listchanges.git
Build-Depends: debhelper (>= 5)
Build-Depends-Indep: docbook-to-man, gettext, po-debconf, libexpat1-dev,
- python-support (>= 0.4.0)
+ python3:any
+X-Python-Version: >= 3.4
Package: apt-listchanges
Architecture: all
-Depends: ${python:Depends}, apt (>= 0.5.3), python-apt (>= 0.7.93),
+Depends: ${python3:Depends}, apt (>= 0.5.3), python3-apt (>= 0.7.93),
ucf (>= 0.28), debianutils (>= 2.0.2), ${misc:Depends}
-Suggests: x-terminal-emulator, www-browser, python-glade2, python-gtk2,
+Suggests: x-terminal-emulator, www-browser, python3-gi,
default-mta | mail-transport-agent
Description: package change history notification tool
The tool apt-listchanges can compare a new version of a
diff --git a/debian/pyversions b/debian/pyversions
deleted file mode 100644
index 8b253bc..0000000
--- a/debian/pyversions
+++ /dev/null
@@ -1 +0,0 @@
-2.4-
diff --git a/debian/rules b/debian/rules
index a66feed..d128bca 100755
--- a/debian/rules
+++ b/debian/rules
@@ -15,7 +15,7 @@ clean:
dh_testroot
rm -f build-stamp
- rm -f *.py[co] *~
+ rm -f *.py[co] *~ __pycache__/ */__pycache__
$(MAKE) clean
dh_clean
@@ -40,7 +40,7 @@ binary-indep: build install
dh_installchangelogs
# dh_link
# dh_strip
- dh_pysupport
+ dh_python3
dh_compress
dh_fixperms
dh_installdeb
diff --git a/po/Makefile b/po/Makefile
index 5dcca6b..2517080 100644
--- a/po/Makefile
+++ b/po/Makefile
@@ -25,7 +25,7 @@ POFILES = $(wildcard *.po)
MOFILES = $(patsubst %.po,%.mo,$(POFILES))
SRCFILES = ../apt-listchanges.py $(wildcard ../apt-listchanges/*.py) \
- ../apt-listchanges/apt-listchanges.glade
+ ../apt-listchanges/apt-listchanges.ui
all: $(PACKAGE).pot $(MOFILES)
diff --git a/po/apt-listchanges.pot b/po/apt-listchanges.pot
index 6d66434..7cd5c68 100644
--- a/po/apt-listchanges.pot
+++ b/po/apt-listchanges.pot
@@ -1,144 +1,161 @@
# SOME DESCRIPTIVE TITLE.
-# Copyright (C) YEAR ORGANIZATION
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL at ADDRESS>, YEAR.
#
+#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
-"POT-Creation-Date: 2010-07-09 15:16+CEST\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2015-06-02 18:20-0700\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL at ADDRESS>\n"
"Language-Team: LANGUAGE <LL at li.org>\n"
+"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
-"Content-Transfer-Encoding: ENCODING\n"
-"Generated-By: pygettext.py 1.5\n"
+"Content-Transfer-Encoding: 8bit\n"
-
-#: ../apt-listchanges.py:80
-msgid ""
-"database %s failed to load.\n"
+#: ../apt-listchanges.py:93
+#, python-format
+msgid "database %s failed to load.\n"
msgstr ""
-#: ../apt-listchanges.py:97
-msgid ""
-"Unknown frontend: %s\n"
+#: ../apt-listchanges.py:111
+#, python-format
+msgid "Unknown frontend: %s\n"
msgstr ""
-#: ../apt-listchanges.py:122
+#: ../apt-listchanges.py:136
+#, python-format
msgid "%s: will be newly installed"
msgstr ""
-#: ../apt-listchanges.py:138
+#: ../apt-listchanges.py:152
+#, python-format
msgid "%s: Version %s has already been seen"
msgstr ""
-#: ../apt-listchanges.py:172
+#: ../apt-listchanges.py:191
+#, python-format
msgid "News for %s"
msgstr ""
-#: ../apt-listchanges.py:183
+#: ../apt-listchanges.py:202
+#, python-format
msgid "Changes for %s"
msgstr ""
-#: ../apt-listchanges.py:193
+#: ../apt-listchanges.py:212
msgid "Informational notes"
msgstr ""
-#: ../apt-listchanges.py:196
+#: ../apt-listchanges.py:215
msgid "apt-listchanges: News"
msgstr ""
-#: ../apt-listchanges.py:200
+#: ../apt-listchanges.py:219
msgid "apt-listchanges: Changelogs"
msgstr ""
-#: ../apt-listchanges.py:207
+#: ../apt-listchanges.py:226
msgid "Aborting"
msgstr ""
-#: ../apt-listchanges.py:210
+#: ../apt-listchanges.py:229
msgid "Confirmation failed, don't save seen state"
msgstr ""
-#: ../apt-listchanges.py:216
+#: ../apt-listchanges.py:236
+#, python-format
msgid "apt-listchanges: changelogs for %s"
msgstr ""
-#: ../apt-listchanges.py:220
+#: ../apt-listchanges.py:240
+#, python-format
msgid "apt-listchanges: news for %s"
msgstr ""
-#: ../apt-listchanges.py:232
+#: ../apt-listchanges.py:252
msgid "didn't find any valid .deb archives"
msgstr ""
-#: ../apt-listchanges/ALCConfig.py:76
+#: ../apt-listchanges/apt_listchanges.py:55
msgid ""
-"Usage: apt-listchanges [options] {--apt | filename.deb ...}\n"
+"Wrong or missing VERSION from apt pipeline\n"
+"(is Dpkg::Tools::Options::/usr/bin/apt-listchanges::Version set to 2?)\n"
msgstr ""
-#: ../apt-listchanges/ALCConfig.py:133
-msgid "Unknown option %s for --which. Allowed are: %s."
+#: ../apt-listchanges/apt_listchanges.py:116
+#, python-format
+msgid "Mailing %s: %s"
msgstr ""
-#: ../apt-listchanges/ALCConfig.py:148
-msgid "--since=<version> expects a only path to a .deb"
+#: ../apt-listchanges/apt_listchanges.py:143
+#, python-format
+msgid "The %s frontend is deprecated, using pager"
msgstr ""
-#: ../apt-listchanges/ALChacks.py:32
-msgid ""
-"Can't set locale; make sure $LC_* and $LANG are correct!\n"
+#: ../apt-listchanges/apt_listchanges.py:147
+msgid "The mail frontend needs a installed 'sendmail', using pager"
msgstr ""
-#: ../apt-listchanges/AptListChangesGtk.py:68
-msgid "Continue Installation?"
+#: ../apt-listchanges/apt_listchanges.py:159
+#, python-format
+msgid ""
+"The gtk frontend needs a working python-gi.\n"
+"Those imports can not be found. Falling back to pager.\n"
+"The error is: %s\n"
msgstr ""
-#: ../apt-listchanges/AptListChangesGtk.py:68
-msgid "You can abort the installation if you select 'no'."
+#: ../apt-listchanges/apt_listchanges.py:258
+msgid "Do you want to continue? [Y/n] "
msgstr ""
-#: ../apt-listchanges/DebianFiles.py:171
-msgid "Ignoring `%s' (seems to be a directory!)"
+#: ../apt-listchanges/apt_listchanges.py:271
+#: ../apt-listchanges/apt_listchanges.py:291
+#: ../apt-listchanges/apt_listchanges.py:299
+msgid "Reading changelogs"
msgstr ""
-#: ../apt-listchanges/apt_listchanges.py:45
-msgid ""
-"Wrong or missing VERSION from apt pipeline\n"
-"(is Dpkg::Tools::Options::/usr/bin/apt-listchanges::Version set to 2?)\n"
+#: ../apt-listchanges/apt_listchanges.py:299
+msgid "Done"
msgstr ""
-#: ../apt-listchanges/apt_listchanges.py:86
-msgid "Mailing %s: %s"
+#: ../apt-listchanges/ALCConfig.py:79
+msgid "Usage: apt-listchanges [options] {--apt | filename.deb ...}\n"
msgstr ""
-#: ../apt-listchanges/apt_listchanges.py:111
-msgid "The %s frontend is deprecated, using pager"
+#: ../apt-listchanges/ALCConfig.py:136
+#, python-format
+msgid "Unknown option %s for --which. Allowed are: %s."
msgstr ""
-#: ../apt-listchanges/apt_listchanges.py:115
-msgid "The mail frontend needs a installed 'sendmail', using pager"
+#: ../apt-listchanges/ALCConfig.py:151
+msgid "--since=<version> expects a only path to a .deb"
msgstr ""
-#: ../apt-listchanges/apt_listchanges.py:127
-msgid ""
-"The gtk frontend needs a working python-gtk2 and python-glade2.\n"
-"Those imports can not be found. Falling back to pager.\n"
-"The error is: %s\n"
+#: ../apt-listchanges/DebianFiles.py:199
+#, python-format
+msgid "Ignoring `%s' (seems to be a directory!)"
msgstr ""
-#: ../apt-listchanges/apt_listchanges.py:180
-msgid "Do you want to continue? [Y/n] "
+#: ../apt-listchanges/AptListChangesGtk.py:71
+msgid "Continue Installation?"
msgstr ""
-#: ../apt-listchanges/apt_listchanges.py:193
-#: ../apt-listchanges/apt_listchanges.py:213
-#: ../apt-listchanges/apt_listchanges.py:221
-msgid "Reading changelogs"
+#: ../apt-listchanges/AptListChangesGtk.py:71
+msgid "You can abort the installation if you select 'no'."
msgstr ""
-#: ../apt-listchanges/apt_listchanges.py:221
-msgid "Done"
+#: ../apt-listchanges/apt-listchanges.ui:13
+msgid "List the changes"
msgstr ""
+#: ../apt-listchanges/apt-listchanges.ui:29
+msgid ""
+"<big><b>Changelogs</b></big>\n"
+"\n"
+"The following changes are found in the packages you are about to install:"
+msgstr ""
More information about the py3porters-devel
mailing list