Merge lp:~xnox/apt-btrfs-snapshot/py3 into lp:apt-btrfs-snapshot

Proposed by Dimitri John Ledkov
Status: Merged
Merged at revision: 39
Proposed branch: lp:~xnox/apt-btrfs-snapshot/py3
Merge into: lp:apt-btrfs-snapshot
Diff against target: 288 lines (+93/-33)
6 files modified
apt-btrfs-snapshot (+6/-6)
apt_btrfs_snapshot.py (+20/-17)
debian/changelog (+26/-2)
debian/control (+8/-2)
debian/rules (+23/-1)
test/test_apt_btrfs_snapshot.py (+10/-5)
To merge this branch: bzr merge lp:~xnox/apt-btrfs-snapshot/py3
Reviewer Review Type Date Requested Status
Colin Watson (community) Approve
Michael Vogt Pending
Review via email: mp+109632@code.launchpad.net

Description of the change

python3 port and other fixes

To post a comment you must log in.
Revision history for this message
Colin Watson (cjwatson) wrote :

Looks good to me, though I'd like Michael to review this and merge if he's happy.

review: Approve
Revision history for this message
Barry Warsaw (barry) wrote :
Download full text (3.9 KiB)

On Jun 11, 2012, at 01:20 PM, Dmitrijs Ledkovs wrote:

>Dmitrijs Ledkovs has proposed merging lp:~dmitrij.ledkov/apt-btrfs-snapshot/py3 into lp:apt-btrfs-snapshot.
>
>Requested reviews:
> Canonical Foundations Team (canonical-foundations)
> Michael Vogt (mvo)
>
>For more details, see:
>https://code.launchpad.net/~dmitrij.ledkov/apt-btrfs-snapshot/py3/+merge/109632
>
>python3 port and other fixes

=== modified file 'apt-btrfs-snapshot'
--- apt-btrfs-snapshot 2011-07-19 11:42:45 +0000
+++ apt-btrfs-snapshot 2012-06-11 13:19:19 +0000
> @@ -1,4 +1,4 @@
> -#!/usr/bin/python
> +#!/usr/bin/python3
> # Copyright (C) 2011 Canonical
> #
> # Author:
> @@ -17,6 +17,8 @@
> # this program; if not, write to the Free Software Foundation, Inc.,
> # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
>
> +from __future__ import print_function

This import got me thinking. If apt-btrfs-snapshot (the script) will only run
in Python 3, then clearly we don't need this. If it could run in Python 2
(e.g. explicitly invoked ignoring the #! line, or if you want to hold out the
possibility of reverting to Python 2), then the import is fine, but possibly
incomplete.

(Aside: print_function was introduced in Python 2.6.0a2:
http://docs.python.org/py3k/library/__future__.html)

It might be incompletely because you may also need to import unicode_literals
(FWIW, just as a blanket rule, I always import those two plus
absolute_import). The other thing you'll need to check is that the _()
function is defined properly for cross-py2/py3 compatibility. It's not clear
from the diff if this is the case.

Here's the thing: you always want _() to return unicode strings, and you want
the input to be unicode strings. In Python 2, gettext.gettext() is *not* the
right thing to use, you need gettext.ugettext(). In Python 3,
gettext.gettext() does operate on and return unicodes.

You can do something like this to make it work right (this is pulled from the
c-j code in u-m).

def setup_gettext():
    domain = 'foo'
    localedir = os.environ.get('LOCPATH')
    t = gettext.translation(domain, localedir=localedir, fallback=True)
    try:
        return t.ugettext
    except AttributeError:
        return t.gettext

Then...

_ = setup_gettext()

OTOH, if the script will always run under Python 3, most of that won't be
necessary.

=== modified file 'apt_btrfs_snapshot.py'
--- apt_btrfs_snapshot.py 2011-10-17 08:05:22 +0000
+++ apt_btrfs_snapshot.py 2012-06-11 13:19:19 +0000
> @@ -16,9 +16,10 @@
> # this program; if not, write to the Free Software Foundation, Inc.,
> # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
>
> +from __future__ import print_function

Even though you're not using gettext, I'd still consider including
unicode_literals here. The problem is that if in Python 2, you're operating
on 8-bit strings, they'll magically become unicodes in Python 3, and then
you're just asking for trouble. If the literals really should be 8-bit
strings (a.k.a. bytes) in both versions, then import unicode_literals and
prefix your byte literals with b''. That way, the intentions are clear, and
things will work the same in both versions.

> @@ -57,14 +58,16 @@
...

Read more...

lp:~xnox/apt-btrfs-snapshot/py3 updated
43. By Dimitri John Ledkov

Address barry's comments

Revision history for this message
Michael Vogt (mvo) wrote :

Thanks for your work on this branch!

it looks good. One comment below:

On Mon, Jun 11, 2012 at 01:20:25PM -0000, Dmitrijs Ledkovs wrote:
> - def test_fstab_detect_snapshot(self):
> + @mock.patch('os.path.exists', side_effect=lambda f: f in ('/sbin/btrfs'))

This seems this requires python-mock 0.8, it would be nice if that
would still work on 12.04 for now if its not too much hassle to make
it easy for contributors to hack on it without the need to upgrade to
quantal just yet.

We should probably add a generic pyflakes and pep8 test to the tests
dir, I will do that in a bit.

Thanks,
 Michael

Revision history for this message
Dimitri John Ledkov (xnox) wrote :

Pushed upto -r44, which uses python-mock 0.7 style api/syntax. Works in precise pbuilder.
Regards,
Dmitrijs.

lp:~xnox/apt-btrfs-snapshot/py3 updated
44. By Dimitri John Ledkov

use python-mock 0.7 API/syntax

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'apt-btrfs-snapshot'
2--- apt-btrfs-snapshot 2011-07-19 11:42:45 +0000
3+++ apt-btrfs-snapshot 2012-06-11 17:29:49 +0000
4@@ -1,4 +1,4 @@
5-#!/usr/bin/python
6+#!/usr/bin/python3
7 # Copyright (C) 2011 Canonical
8 #
9 # Author:
10@@ -84,21 +84,21 @@
11 logging.basicConfig(level=logging.INFO)
12
13 if os.getuid() != 0:
14- print _("Sorry, you need to be root to run this program")
15+ print(_("Sorry, you need to be root to run this program"))
16 sys.exit(1)
17
18 apt_btrfs = AptBtrfsSnapshot()
19 if not apt_btrfs.snapshots_supported():
20- print _("Sorry, your system lacks support for the snapshot feature")
21+ print(_("Sorry, your system lacks support for the snapshot feature"))
22 sys.exit(1)
23
24 res = False
25 if args.command == "supported":
26 res = apt_btrfs.snapshots_supported()
27 if res:
28- print _("Supported")
29+ print(_("Supported"))
30 else:
31- print _("Not supported")
32+ print(_("Not supported"))
33 elif args.command == "snapshot":
34 res = apt_btrfs.create_btrfs_root_snapshot()
35 elif args.command == "list":
36@@ -112,7 +112,7 @@
37 elif args.command == "delete-older-than":
38 res = apt_btrfs.clean_btrfs_root_snapshots_older_than(args.time)
39 else:
40- print _("ERROR: Unhandled command: '%s'") % args.command
41+ print(_("ERROR: Unhandled command: '%s'") % args.command)
42
43 # return the right exit code
44 if res:
45
46=== modified file 'apt_btrfs_snapshot.py'
47--- apt_btrfs_snapshot.py 2011-10-17 08:05:22 +0000
48+++ apt_btrfs_snapshot.py 2012-06-11 17:29:49 +0000
49@@ -16,9 +16,10 @@
50 # this program; if not, write to the Free Software Foundation, Inc.,
51 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
52
53+from __future__ import print_function, unicode_literals
54+
55 import datetime
56 import os
57-import string
58 import subprocess
59 import sys
60 import time
61@@ -57,14 +58,16 @@
62 """ a list of FstabEntry items """
63 def __init__(self, fstab="/etc/fstab"):
64 super(Fstab, self).__init__()
65- for line in map(string.strip, open(fstab)):
66- if line == "" or line.startswith("#"):
67- continue
68- try:
69- entry = FstabEntry.from_line(line)
70- except ValueError:
71- continue
72- self.append(entry)
73+
74+ with open(fstab) as fstab_file:
75+ for line in (l.strip() for l in fstab_file):
76+ if line == "" or line.startswith("#"):
77+ continue
78+ try:
79+ entry = FstabEntry.from_line(line)
80+ except ValueError:
81+ continue
82+ self.append(entry)
83
84 class LowLevelCommands(object):
85 """ lowlevel commands invoked to perform various tasks like
86@@ -133,7 +136,7 @@
87 self._btrfs_root_mountpoint = None
88 return res
89 def _get_now_str(self):
90- return datetime.datetime.now().replace(microsecond=0).isoformat("_")
91+ return datetime.datetime.now().replace(microsecond=0).isoformat(str('_'))
92 def create_btrfs_root_snapshot(self, additional_prefix=""):
93 mp = self.mount_btrfs_root_volume()
94 snap_id = self._get_now_str()
95@@ -153,7 +156,7 @@
96 if older_than != 0:
97 entry = self._get_supported_btrfs_root_fstab_entry()
98 if not entry:
99- raise AptBtrfsSnapshotNotSupportedError()
100+ raise AptBtrfsNotSupportedError()
101 if "noatime" in entry.options:
102 raise AptBtrfsRootWithNoatimeError()
103 # if there is no older than, interpret that as "now"
104@@ -170,8 +173,8 @@
105 self.umount_btrfs_root_volume()
106 return l
107 def print_btrfs_root_snapshots(self):
108- print "Available snapshots:"
109- print " \n".join(self.get_btrfs_root_snapshots_list())
110+ print("Available snapshots:")
111+ print(" \n".join(self.get_btrfs_root_snapshots_list()))
112 return True
113 def _parse_older_than_to_unixtime(self, timefmt):
114 now = time.time()
115@@ -182,9 +185,9 @@
116 def print_btrfs_root_snapshots_older_than(self, timefmt):
117 older_than_unixtime = self._parse_older_than_to_unixtime(timefmt)
118 try:
119- print "Available snapshots older than '%s':" % timefmt
120- print " \n".join(self.get_btrfs_root_snapshots_list(
121- older_than=older_than_unixtime))
122+ print("Available snapshots older than '%s':" % timefmt)
123+ print(" \n".join(self.get_btrfs_root_snapshots_list(
124+ older_than=older_than_unixtime)))
125 except AptBtrfsRootWithNoatimeError:
126 sys.stderr.write("Error: fstab option 'noatime' incompatible with option")
127 return False
128@@ -202,7 +205,7 @@
129 return res
130 def command_set_default(self, snapshot_name):
131 res = self.set_default(snapshot_name)
132- print "Please reboot"
133+ print("Please reboot")
134 return res
135 def set_default(self, snapshot_name, backup=True):
136 """ set new default """
137
138=== modified file 'debian/changelog'
139--- debian/changelog 2011-10-17 08:05:22 +0000
140+++ debian/changelog 2012-06-11 17:29:49 +0000
141@@ -1,5 +1,6 @@
142-apt-btrfs-snapshot (0.2.2) UNRELEASEDoneiric-proposed; urgency=low
143+apt-btrfs-snapshot (0.2.2) UNRELEASED; urgency=low
144
145+ [ Michael Vogt ]
146 * apt_btrfs_snapshot.py, test/test_apt_btrfs_snapshot.py:
147 - disable "delete-older-than" command if noatime is in use on
148 the snapshot fs (LP: #833980)
149@@ -8,7 +9,30 @@
150 - be even more robust against invalid fstab entries
151 (LP: #873411 comment #7)
152
153- -- Michael Vogt <michael.vogt@ubuntu.com> Tue, 11 Oct 2011 10:20:45 +0200
154+ [ Dmitrijs Ledkovs ]
155+ * apt_btrfs_snapshot.py, apt-btrfs-snapshot:
156+ - port to python3
157+ * apt_btrfs_snapshot.py:
158+ - fix pyflakes warning use 'AptBtrfsNotSupportedError' instead of
159+ undefined name 'AptBtrfsSnapshotNotSupportedError'
160+ * test/test_apt_btrfs_snapshot.py:
161+ - remove unused imports 'LowLevelCommands' and 'apt_btrfs_snapshot'
162+ - mock sys.stdout and sys.stderr to avoid confusing and spurious output
163+ - mock /sbin/btrfs to allow running unit-tests without btrfs-tools
164+ * debian/rules:
165+ - build with supported versions of python2 and python3
166+ - run unittests at build time, honoring nocheck
167+ * debian/control:
168+ - adjust dependencies for python3 support
169+ - bump standards version to 3.9.3
170+
171+ -- Dmitrijs Ledkovs <dmitrij.ledkov@ubuntu.com> Mon, 11 Jun 2012 14:07:41 +0100
172+
173+apt-btrfs-snapshot (0.2.1build1) precise; urgency=low
174+
175+ * Rebuild to drop python2.6 dependencies.
176+
177+ -- Matthias Klose <doko@ubuntu.com> Sat, 31 Dec 2011 02:00:37 +0000
178
179 apt-btrfs-snapshot (0.2.1) oneiric; urgency=low
180
181
182=== modified file 'debian/control'
183--- debian/control 2011-10-10 21:21:46 +0000
184+++ debian/control 2012-06-11 17:29:49 +0000
185@@ -2,16 +2,22 @@
186 Section: admin
187 Priority: optional
188 Maintainer: Michael Vogt <michael.vogt@ubuntu.com>
189-Build-Depends: debhelper (>= 7),
190+Build-Depends: debhelper (>= 7.0.50~),
191+ python3,
192+ python3-distutils-extra,
193+ python3-mock,
194 python (>= 2.6.5-2~),
195 python-distutils-extra,
196+ python-mock,
197 X-Python-Version: all
198-Standards-Version: 3.9.1
199+X-Python3-Version: >= 3.2
200+Standards-Version: 3.9.3
201 Vcs-Bzr: https://code.launchpad.net/apt-btrfs-snapshot
202
203 Package: apt-btrfs-snapshot
204 Architecture: all
205 Depends: ${python:Depends},
206+ ${python3:Depends},
207 ${misc:Depends},
208 btrfs-tools
209 Description: Automatically create snapshot on apt operations
210
211=== modified file 'debian/rules'
212--- debian/rules 2011-02-16 11:56:59 +0000
213+++ debian/rules 2012-06-11 17:29:49 +0000
214@@ -1,5 +1,27 @@
215 #!/usr/bin/make -f
216+PYTHON2:=$(shell pyversions -r)
217+PYTHON3:=$(shell py3versions -r)
218+py3sdo=set -e; $(foreach py, $(PYTHON3), $(py) $(1);)
219+pyalldo=set -e; $(foreach py, $(PYTHON2) $(PYTHON3), $(py) $(1);)
220
221 %:
222- dh $@ --with python2
223+ dh $@ --with python2,python3
224+
225+ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
226+override_dh_auto_test:
227+ $(call pyalldo, -m unittest discover -vv test/)
228+endif
229+
230+override_dh_auto_build:
231+ dh_auto_build
232+ $(call py3sdo, setup.py build)
233+
234+override_dh_auto_install:
235+ dh_auto_install
236+ $(call py3sdo, setup.py install --root=$(CURDIR)/debian/apt-btrfs-snapshot --install-layout=deb)
237+
238+override_dh_auto_clean:
239+ dh_auto_clean
240+ rm -rf build
241+ rm -rf *.egg-info
242
243
244=== modified file 'test/test_apt_btrfs_snapshot.py'
245--- test/test_apt_btrfs_snapshot.py 2011-10-17 08:05:22 +0000
246+++ test/test_apt_btrfs_snapshot.py 2012-06-11 17:29:49 +0000
247@@ -1,5 +1,9 @@
248 #!/usr/bin/python
249
250+try:
251+ from StringIO import StringIO
252+except ImportError:
253+ from io import StringIO
254 import mock
255 import os
256 import sys
257@@ -8,17 +12,16 @@
258
259 sys.path.insert(0, "..")
260 sys.path.insert(0, ".")
261-import apt_btrfs_snapshot
262 from apt_btrfs_snapshot import (AptBtrfsSnapshot,
263- AptBtrfsRootWithNoatimeError,
264- LowLevelCommands)
265+ AptBtrfsRootWithNoatimeError)
266
267 class TestFstab(unittest.TestCase):
268
269 def setUp(self):
270 self.testdir = os.path.dirname(os.path.abspath(__file__))
271
272- def test_fstab_detect_snapshot(self):
273+ @mock.patch('os.path.exists', side_effect=lambda f: f in ('/sbin/btrfs'))
274+ def test_fstab_detect_snapshot(self, mock_commands):
275 apt_btrfs = AptBtrfsSnapshot(
276 fstab=os.path.join(self.testdir, "data", "fstab"))
277 self.assertTrue(apt_btrfs.snapshots_supported())
278@@ -38,7 +41,9 @@
279 self.assertEqual(apt_btrfs._uuid_for_mountpoint("/"),
280 "UUID=fe63f598-1906-478e-acc7-f74740e78d1f")
281
282- def test_fstab_noatime(self):
283+ @mock.patch('sys.stdout', new_callable=StringIO)
284+ @mock.patch('sys.stderr', new_callable=StringIO)
285+ def test_fstab_noatime(self, mock_stdout, mock_stderr):
286 apt_btrfs = AptBtrfsSnapshot(
287 fstab=os.path.join(self.testdir, "data", "fstab.bug833980"))
288 # ensure our test is right

Subscribers

People subscribed via source and target branches