Merge lp:~barry/aptdaemon/lp1120322 into lp:aptdaemon

Proposed by Barry Warsaw
Status: Merged
Merged at revision: 889
Proposed branch: lp:~barry/aptdaemon/lp1120322
Merge into: lp:aptdaemon
Diff against target: 111 lines (+62/-5)
3 files modified
README.tests (+3/-0)
aptdaemon/gtk3widgets.py (+10/-5)
tests/test_gtk3widgets.py (+49/-0)
To merge this branch: bzr merge lp:~barry/aptdaemon/lp1120322
Reviewer Review Type Date Requested Status
Michael Vogt Needs Information
Sebastian Heinlein Pending
Review via email: mp+151083@code.launchpad.net

Description of the change

Proposed fix for UnboundLocalError.

To post a comment you must log in.
lp:~barry/aptdaemon/lp1120322 updated
891. By Barry Warsaw

After better analysis by lifeless, fix LP: #1120322 in a complementary way:

- Improve the REGEX_RANGE to allow for optional ,### parts, so that one line
  diffs will properly match.

- Move the constant to the module globals for better wrapping (and because
  being a class instance isn't necessary).

- Still initialize line_number to 0 because it can't hurt.

- Be explicit about closing the file objects instead of hoping that gc does
  its job. This eliminates warnings in the test suite.

- Add a test for both one line and multiline diffs, showing that LP: #1120322
  is actually fixed, and doesn't regress.

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

This looks good, thanks Barry!

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

There is a issue however, the code tries to be py2 compatible as well to make e.g. backporting easier.
And e.g.:

    print('one', file=f)
                     ^
SyntaxError: invalid syntax

Is not py2 compatible. Its ultimately the decision of glatzor for how long he wants to keep py2
compatibility but in this case it seems easy enough to add.

Out of curiosity, why do you move the regexp out of the class?

review: Needs Information
lp:~barry/aptdaemon/lp1120322 updated
892. By Barry Warsaw

Restore Python 2 compatibility in the tests. Document that the tests still
need to be Python 2 compatible.

Revision history for this message
Barry Warsaw (barry) wrote :

On Mar 01, 2013, at 09:05 AM, Michael Vogt wrote:

>There is a issue however, the code tries to be py2 compatible as well to make
>e.g. backporting easier. And e.g.:
>
> print('one', file=f)
> ^
>SyntaxError: invalid syntax
>
>Is not py2 compatible. Its ultimately the decision of glatzor for how long he
>wants to keep py2 compatibility but in this case it seems easy enough to add.

Ah darn, I forgot about Python 2 compatibility. I just pushed an update to
the branch which restores that for the test, and which describes the need to
run against Python 2 in the README.test.

>Out of curiosity, why do you move the regexp out of the class?

Purely cosmetic - I hate long lines and the changes to the regexp pushed it
past the PEP 8 line length limit. I didn't want to artificially wrap the
string, and then I noticed that there's no technical reason why it has to be a
class attribute. I can revert that if you hate it. :)

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

On Fri, Mar 01, 2013 at 04:31:21PM -0000, Barry Warsaw wrote:
> On Mar 01, 2013, at 09:05 AM, Michael Vogt wrote:
>
> >There is a issue however, the code tries to be py2 compatible as well to make
> >e.g. backporting easier. And e.g.:
> >
> > print('one', file=f)
> > ^
> >SyntaxError: invalid syntax
> >
> >Is not py2 compatible. Its ultimately the decision of glatzor for how long he
> >wants to keep py2 compatibility but in this case it seems easy enough to add.
>
> Ah darn, I forgot about Python 2 compatibility. I just pushed an update to
> the branch which restores that for the test, and which describes the need to
> run against Python 2 in the README.test.

Thank you very much! Looks good now, merged :)

> >Out of curiosity, why do you move the regexp out of the class?
>
> Purely cosmetic - I hate long lines and the changes to the regexp pushed it
> past the PEP 8 line length limit. I didn't want to artificially wrap the
> string, and then I noticed that there's no technical reason why it has to be a
> class attribute. I can revert that if you hate it. :)

No, its fine with me, I was just curious if there is/was a reason that I
am unaware of. PEP8 is a good reason.

Cheers,
 Michael

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'README.tests'
2--- README.tests 2012-05-11 00:46:44 +0000
3+++ README.tests 2013-03-01 16:26:21 +0000
4@@ -2,3 +2,6 @@
5
6 To run the tests you can either use the "python3 setup.py test" or
7 the "nosetests3" command.
8+
9+Since Python 2 is still supported, you should also run the tests with
10+"python setup.py test" or the "nosetests" command.
11
12=== modified file 'aptdaemon/gtk3widgets.py'
13--- aptdaemon/gtk3widgets.py 2012-12-29 19:27:25 +0000
14+++ aptdaemon/gtk3widgets.py 2013-03-01 16:26:21 +0000
15@@ -1062,12 +1062,14 @@
16 return _ExpandableDialog.run(self)
17
18
19+REGEX_RANGE = "^@@ \-(?P<from_start>[0-9]+)(?:,(?P<from_context>[0-9]+))? " \
20+ "\+(?P<to_start>[0-9]+)(?:,(?P<to_context>[0-9]+))? @@"
21+
22+
23 class DiffView(Gtk.TextView):
24
25 """Shows the difference between two files."""
26
27- REGEX_RANGE = "^@@ \-(?P<from_start>[0-9]+),(?P<from_context>[0-9]+) " \
28- "\+(?P<to_start>[0-9]+),(?P<to_context>[0-9]+) @@"
29 ELLIPSIS = "[…]\n"
30
31 def __init__(self):
32@@ -1097,8 +1099,10 @@
33 """Show the difference between two files."""
34 #FIXME: Use gio
35 try:
36- from_lines = open(from_path).readlines()
37- to_lines = open(to_path).readlines()
38+ with open(from_path) as fp:
39+ from_lines = fp.readlines()
40+ with open(to_path) as fp:
41+ to_lines = fp.readlines()
42 except IOError:
43 return
44
45@@ -1111,10 +1115,11 @@
46 self.textbuffer.apply_tag_by_name(
47 tag, self.textbuffer.get_iter_at_offset(offset), iter)
48
49+ line_number = 0
50 iter = self.textbuffer.get_start_iter()
51 for line in difflib.unified_diff(from_lines, to_lines, lineterm=""):
52 if line.startswith("@@"):
53- match = re.match(self.REGEX_RANGE, line)
54+ match = re.match(REGEX_RANGE, line)
55 if not match:
56 continue
57 line_number = int(match.group("from_start"))
58
59=== added file 'tests/test_gtk3widgets.py'
60--- tests/test_gtk3widgets.py 1970-01-01 00:00:00 +0000
61+++ tests/test_gtk3widgets.py 2013-03-01 16:26:21 +0000
62@@ -0,0 +1,49 @@
63+#!/usr/bin/env python3
64+
65+"""Test gtk3widgets.py."""
66+
67+import os
68+import codecs
69+import shutil
70+import tempfile
71+import unittest
72+
73+from aptdaemon.gtk3widgets import DiffView
74+
75+
76+class TestLP1120322(unittest.TestCase):
77+
78+ def setUp(self):
79+ tempdir = tempfile.mkdtemp()
80+ self.addCleanup(shutil.rmtree, tempdir)
81+ self.a = os.path.join(tempdir, 'a.txt')
82+ self.b = os.path.join(tempdir, 'b.txt')
83+ with codecs.open(self.a, 'w', encoding='utf-8') as f:
84+ f.write('one\n')
85+ with codecs.open(self.b, 'w', encoding='utf-8') as f:
86+ f.write('onee\n')
87+
88+ def test_lp_1120322(self):
89+ # UnboundLocalError when the diff is one line long.
90+ dv = DiffView()
91+ # This simply should not traceback.
92+ dv.show_diff(self.a, self.b)
93+
94+
95+class TestGoodPath(unittest.TestCase):
96+
97+ def setUp(self):
98+ tempdir = tempfile.mkdtemp()
99+ self.addCleanup(shutil.rmtree, tempdir)
100+ self.a = os.path.join(tempdir, 'a.txt')
101+ self.b = os.path.join(tempdir, 'b.txt')
102+ with codecs.open(self.a, 'w', encoding='utf-8') as f:
103+ f.write('one\ntwo\n')
104+ with codecs.open(self.b, 'w', encoding='utf-8') as f:
105+ f.write('one\ntoo\n')
106+
107+ def test_lp_1120322(self):
108+ # UnboundLocalError when the diff is multiple lines long.
109+ dv = DiffView()
110+ # This simply should not traceback.
111+ dv.show_diff(self.a, self.b)

Subscribers

People subscribed via source and target branches

to status/vote changes: