Merge lp:~parthm/bzr/603461-ensure-no-var-named-message-2.2 into lp:bzr/2.2

Proposed by Parth Malwankar
Status: Merged
Approved by: Andrew Bennetts
Approved revision: no longer in the source branch.
Merged at revision: 5058
Proposed branch: lp:~parthm/bzr/603461-ensure-no-var-named-message-2.2
Merge into: lp:bzr/2.2
Diff against target: 119 lines (+42/-9)
3 files modified
NEWS (+9/-0)
bzrlib/errors.py (+5/-8)
bzrlib/tests/test_errors.py (+28/-1)
To merge this branch: bzr merge lp:~parthm/bzr/603461-ensure-no-var-named-message-2.2
Reviewer Review Type Date Requested Status
Andrew Bennetts Approve
Vincent Ladeuil Approve
Review via email: mp+29837@code.launchpad.net

Commit message

test to ensure that errors.BzrError subclasses don't use "message" as arg name for __init__ and _fmt (#603461)

Description of the change

This fix adds a test case to prevent bugs like bug #603461 i.e. use of "message" as format variable name in BzrError subclasses is a problem on some Python versions.

The test case checks subclasses of errors.BzrError for two things:
1. __init__ should not have argument named "message"
2. _fmt should not use "message" as a format variable name.

The patch also fixes existing _fmt strings that had "message" variable names in them.

One potentially breaking change could be the use of "message" as __init__ argument in LockError. I have changed this to "msg" and tests for bzr are passing. bzrlib does not use LockError with explicit argument name. A grep of some plugins (bzr-svn, bzr-grep, bzrtools) shows that LockError is not used directly. So I think it should be a safe change. If someone more familiar with use of LockError feels thats not the case I can special case it in the test case.

To post a comment you must log in.
Revision history for this message
Vincent Ladeuil (vila) wrote :

This sounds fine, thanks !

review: Approve
Revision history for this message
Andrew Bennetts (spiv) wrote :

 review needs-fixing

This is pretty neat!

The test should be using BzrError.__subclasses__() though, rather than digging
through bzrlib.errors.__dict__. This will be simpler, and find subclasses in
modules other than bzrlib.errors. (This can happen when plugins define errors,
and also the coding guide says that new errors can be defined in modules other
than bzrlib.errors)

-Andrew.

review: Needs Fixing
Revision history for this message
Parth Malwankar (parthm) wrote :

> The test should be using BzrError.__subclasses__() though, rather than digging

__subclasses__ is much better. I have updated the patch. Thanks for the review.

Revision history for this message
Andrew Bennetts (spiv) wrote :

Oh, I forgot to mention (I was in hurry, sorry), __subclasses__ is new in Python 2.5 :(

So this test should skip if BzrError.__subclasses__ does not exist.

The only other change I'd suggest is this perhaps should be mentioned in API Changes in NEWS.

Apart from those two things this looks good to land for me.

Revision history for this message
Parth Malwankar (parthm) wrote :

> Oh, I forgot to mention (I was in hurry, sorry), __subclasses__ is new in
> Python 2.5 :(
>
> So this test should skip if BzrError.__subclasses__ does not exist.
>
> The only other change I'd suggest is this perhaps should be mentioned in API
> Changes in NEWS.
>

The test now skips if __subclasses__ is not present.
Also, added the NEWS entry regarding compatibility. Thanks.

> Apart from those two things this looks good to land for me.

Revision history for this message
Andrew Bennetts (spiv) :
review: Approve
Revision history for this message
Parth Malwankar (parthm) wrote :

sent to pqm by email

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'NEWS'
2--- NEWS 2010-07-13 16:17:52 +0000
3+++ NEWS 2010-07-14 09:56:42 +0000
4@@ -14,6 +14,12 @@
5 Compatibility Breaks
6 ********************
7
8+* BzrError subclasses no longer support the name "message" to be used
9+ as an argument for __init__ or in _fmt format specification as this
10+ breaks in some Python versions. errors.LockError.__init__ argument
11+ is now named "msg" instead of earlier "message".
12+ (Parth Malwankar, #603461)
13+
14 New Features
15 ************
16
17@@ -42,6 +48,9 @@
18 Testing
19 *******
20
21+* Unit test added to ensure that "message" is not uses as a format variable
22+ name in BzrError subclasses as this conflicts with some Python versions.
23+ (Parth Malwankar, #603461)
24
25 bzr 2.2b4
26 #########
27
28=== modified file 'bzrlib/errors.py'
29--- bzrlib/errors.py 2010-07-09 16:16:11 +0000
30+++ bzrlib/errors.py 2010-07-14 09:56:42 +0000
31@@ -947,11 +947,8 @@
32 # original exception is available as e.original_error
33 #
34 # New code should prefer to raise specific subclasses
35- def __init__(self, message):
36- # Python 2.5 uses a slot for StandardError.message,
37- # so use a different variable name. We now work around this in
38- # BzrError.__str__, but this member name is kept for compatability.
39- self.msg = message
40+ def __init__(self, msg):
41+ self.msg = msg
42
43
44 class LockActive(LockError):
45@@ -1378,12 +1375,12 @@
46
47 class WeaveParentMismatch(WeaveError):
48
49- _fmt = "Parents are mismatched between two revisions. %(message)s"
50+ _fmt = "Parents are mismatched between two revisions. %(msg)s"
51
52
53 class WeaveInvalidChecksum(WeaveError):
54
55- _fmt = "Text did not match it's checksum: %(message)s"
56+ _fmt = "Text did not match it's checksum: %(msg)s"
57
58
59 class WeaveTextDiffers(WeaveError):
60@@ -1437,7 +1434,7 @@
61
62 class VersionedFileInvalidChecksum(VersionedFileError):
63
64- _fmt = "Text did not match its checksum: %(message)s"
65+ _fmt = "Text did not match its checksum: %(msg)s"
66
67
68 class KnitError(InternalBzrError):
69
70=== modified file 'bzrlib/tests/test_errors.py'
71--- bzrlib/tests/test_errors.py 2010-07-09 16:16:11 +0000
72+++ bzrlib/tests/test_errors.py 2010-07-14 09:56:42 +0000
73@@ -16,6 +16,8 @@
74
75 """Tests for the formatting and construction of errors."""
76
77+import inspect
78+import re
79 import socket
80 import sys
81
82@@ -26,11 +28,36 @@
83 symbol_versioning,
84 urlutils,
85 )
86-from bzrlib.tests import TestCase, TestCaseWithTransport
87+from bzrlib.tests import TestCase, TestCaseWithTransport, TestSkipped
88
89
90 class TestErrors(TestCaseWithTransport):
91
92+ def test_no_arg_named_message(self):
93+ """Ensure the __init__ and _fmt in errors do not have "message" arg.
94+
95+ This test fails if __init__ or _fmt in errors has an argument
96+ named "message" as this can cause errors in some Python versions.
97+ Python 2.5 uses a slot for StandardError.message.
98+ See bug #603461
99+ """
100+ fmt_pattern = re.compile("%\(message\)[sir]")
101+ subclasses_present = getattr(errors.BzrError, '__subclasses__', None)
102+ if not subclasses_present:
103+ raise TestSkipped('__subclasses__ attribute required for classes. '
104+ 'Requires Python 2.5 or later.')
105+ for c in errors.BzrError.__subclasses__():
106+ init = getattr(c, '__init__', None)
107+ fmt = getattr(c, '_fmt', None)
108+ if init:
109+ args = inspect.getargspec(init)[0]
110+ self.assertFalse('message' in args,
111+ ('Argument name "message" not allowed for '
112+ '"errors.%s.__init__"' % c.__name__))
113+ if fmt and fmt_pattern.search(fmt):
114+ self.assertFalse(True, ('"message" not allowed in '
115+ '"errors.%s._fmt"' % c.__name__))
116+
117 def test_bad_filename_encoding(self):
118 error = errors.BadFilenameEncoding('bad/filen\xe5me', 'UTF-8')
119 self.assertEqualDiff(

Subscribers

People subscribed via source and target branches