Merge lp:~gz/bzr/python_2.7_selftest_582113 into lp:bzr
- python_2.7_selftest_582113
- Merge into bzr.dev
Status: | Merged |
---|---|
Approved by: | John A Meinel |
Approved revision: | no longer in the source branch. |
Merged at revision: | 5372 |
Proposed branch: | lp:~gz/bzr/python_2.7_selftest_582113 |
Merge into: | lp:bzr |
Diff against target: |
228 lines (+40/-29) 3 files modified
bzrlib/tests/TestUtil.py (+7/-1) bzrlib/tests/__init__.py (+26/-24) bzrlib/tests/test_selftest.py (+7/-4) |
To merge this branch: | bzr merge lp:~gz/bzr/python_2.7_selftest_582113 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
John A Meinel | Approve | ||
Review via email: mp+30332@code.launchpad.net |
Commit message
Some python2.7 unittest fixes (_WriteLnDecorator, etc)
Description of the change
Get bzr selftest working on Python 2.7 by resolving some incompatibilities with the many changes to the unittest module (now a package).
Removes use of unittest.
Getting this branch up on babune is probably a precursor to deciding if it's practical to support Python 2.7 with the bzr 2.2 release, I'm tending towards 'no' currently as this was a pain.
I've not tested this all that thoroughly, so if something breaks for you, please yell.
* Okay, there are new test failures on Python 2.7 but for other reasons.
Barry Warsaw (barry) wrote : | # |
John A Meinel (jameinel) wrote : | # |
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Martin [gz] wrote:
> Martin [gz] has proposed merging lp:~gz/bzr/python_2.7_selftest_582113 into lp:bzr.
>
> Requested reviews:
> bzr-core (bzr-core)
> Related bugs:
> #582113 Tests don't run under Python 2.7 (unittest.
> https:/
>
>
> Get bzr selftest working on Python 2.7 by resolving some incompatibilities with the many changes to the unittest module (now a package).
>
> Removes use of unittest.
>
> Getting this branch up on babune is probably a precursor to deciding if it's practical to support Python 2.7 with the bzr 2.2 release, I'm tending towards 'no' currently as this was a pain.
>
> I've not tested this all that thoroughly, so if something breaks for you, please yell.
>
> * Okay, there are new test failures on Python 2.7 but for other reasons.
>
- - basic_tests = super(TestLoader, self).loadTests
+ basic_tests = super(TestLoader, self).loadTests
+ # GZ 2010-07-19: Python 2.7 unittest also uses load_tests but
with a
+ # different incompatible signature so have to avoid
+ **(sys.version_info > (2, 7) and {"use_load_tests": False}
or {}))
^- spell this out, this is pretty ugly as is.
kwargs = {}
if sys.version >= (2, 7):
# Python 2.7 unittest supports load_tests, but using an incompatible
# signature, so disable it
kwargs[
basic_tests = super(TestLoader, self).loadTests
**kwargs)
- - unittest.
verbosity)
+ testtools.
^- Losing the parameters seems iffy, but if you are sure it is correct.
...
- - self.printErrors()
- - self.stream.
- - self.stream.
+ # GZ 2010-07-19: Seems testtools has no printErrors method, and
though
+ # the parent class method is similar have to
duplicate
+ self._show_
+ self._show_
+ self.stream.
+ self.stream.
- - self.stream.
^- I'm happy to get rid of 'writeln()' though I wonder how much of
*unittest* expects it to be there. unittest.
seems to.
I'm just concerned that we are technically breaking compatibility in
ways we won't find until a test fails, or we get an exception, or some
other non-standard case.
self.separator2 => self.sep2 also seems to be an odd change. (Either way
this seems to be something that should be private)
At the least, shouldn't we pull this code block into our own helper as a
replacement for 'printErrors()' ?
...
@@ -878...
Vincent Ladeuil (vila) wrote : | # |
As a data point:
http://
This was with python2.7 from ppa:doko/toolchain
John A Meinel (jameinel) wrote : | # |
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Vincent Ladeuil wrote:
> As a data point:
>
> http://
>
> This was with python2.7 from ppa:doko/toolchain
>
Is this his code or trunk?
Looks like we got a unicode decoding exception which broke the subunit
toolchain...
John
=:->
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (Cygwin)
Comment: Using GnuPG with Mozilla - http://
iEYEARECAAYFAkx
4WQAoNS5a5qQPPC
=gyUh
-----END PGP SIGNATURE-----
Martin Packman (gz) wrote : | # |
> JAM and I were looking at this today, and started down the _WriteLnDecorator
> change you made (but you did it more thoroughly). I'm not really qualified to
> review the patch for bzr, but +1 on supporting Python 2.7 if you can do it
> without break promises for earlier Pythons.
I've filed a few more bugs with a python2.7 tag, most of these are also due to bazaar extending unittest, but might be relevent for a few other projects.
> ^- spell this out, this is pretty ugly as is.
It's a fair cop guv. In my defence, this code is due to be ripped out when a resolution for bug 607412 is decided on.
> ^- Losing the parameters seems iffy, but if you are sure it is correct.
This and the following couple of comments are this way because the testtools testresult classes are a parallel implementation, not unittest subclasses.
> ^- I'm happy to get rid of 'writeln()' though I wonder how much of
> *unittest* expects it to be there. unittest.
> seems to.
Only unittest classes we're no longer using expect a writeln method.
> self.separator2 => self.sep2 also seems to be an odd change. (Either way
> this seems to be something that should be private)
I presume the name change was done in testtools because the values are not strictly equivalent, unittest doesn't include the newline.
> At the least, shouldn't we pull this code block into our own helper as a
> replacement for 'printErrors()' ?
Yes, that's one option. I'd like testtools to improve here instead, its TextTestResult.
> ^- Do you have more info on this? loosing messages seems like a rather
> bad thing.
That's bug 607400 - filed after I wrote the code, which is why the lack of bug numbers, can add those in.
> As a data point:
>
> http://
>
> This was with python2.7 from ppa:doko/toolchain
Ack, wasn't expecting that fast a response, thanks! The problem there is it needs the fix for testtools bug 604187 which hasn't been merged yet - or the previous testtools release would work as well I think.
Vincent Ladeuil (vila) wrote : | # |
This is clearly going in the right direction but can't be landed as is so marking WIP.
Let's make sure we get the dependencies on testtools/subunit right too or it will be hard to review.
Martin Packman (gz) wrote : | # |
Addressed John's point about the ugly workaround spelling, and replaced a few more unittest.TestResult method calls I somehow missed, which maybe caused the babune problems.
Elsewhere have fixed another testtools bug I'm to blame for, and Jonathan Lange has released 0.9.5 but there may still be another issue there or in subunit that needs shaking out. Another babune run with that updated as well would be great.
John A Meinel (jameinel) wrote : | # |
Seems fine to me. I'm not sure what we need from testtools for python 2.7 support. Any chance you could clarify?
Martin Packman (gz) wrote : | # |
The bit of my last comment talking about testtools was mostly addressed to Vincent - trying to run this branch with 2.7 on babune had some python-
To answer you exact question, we don't need anything more from testtools for 2.7. Using their TextTestRunner avoids some unittest backwards compatibility problems, but there are still some other minor issues which I've filed bugs for.
John A Meinel (jameinel) wrote : | # |
sent to pqm by email
Martin Packman (gz) wrote : | # |
This was a prerequisite for the other two _python_2.7_ branches so was silently merged when the first of those was anyway.
Preview Diff
1 | === modified file 'bzrlib/tests/TestUtil.py' |
2 | --- bzrlib/tests/TestUtil.py 2010-02-17 17:11:16 +0000 |
3 | +++ bzrlib/tests/TestUtil.py 2010-08-05 18:13:49 +0000 |
4 | @@ -135,7 +135,13 @@ |
5 | >>> result.addTests([test, test]) |
6 | >>> return result |
7 | """ |
8 | - basic_tests = super(TestLoader, self).loadTestsFromModule(module) |
9 | + if sys.version_info < (2, 7): |
10 | + basic_tests = super(TestLoader, self).loadTestsFromModule(module) |
11 | + else: |
12 | + # GZ 2010-07-19: Python 2.7 unittest also uses load_tests but with |
13 | + # a different and incompatible signature |
14 | + basic_tests = super(TestLoader, self).loadTestsFromModule(module, |
15 | + use_load_tests=False) |
16 | load_tests = getattr(module, "load_tests", None) |
17 | if load_tests is not None: |
18 | return load_tests(basic_tests, module, self) |
19 | |
20 | === modified file 'bzrlib/tests/__init__.py' |
21 | --- bzrlib/tests/__init__.py 2010-08-05 05:41:34 +0000 |
22 | +++ bzrlib/tests/__init__.py 2010-08-05 18:13:49 +0000 |
23 | @@ -141,7 +141,7 @@ |
24 | SUBUNIT_SEEK_CUR = 1 |
25 | |
26 | |
27 | -class ExtendedTestResult(unittest._TextTestResult): |
28 | +class ExtendedTestResult(testtools.TextTestResult): |
29 | """Accepts, reports and accumulates the results of running tests. |
30 | |
31 | Compared to the unittest version this class adds support for |
32 | @@ -168,7 +168,7 @@ |
33 | :param bench_history: Optionally, a writable file object to accumulate |
34 | benchmark results. |
35 | """ |
36 | - unittest._TextTestResult.__init__(self, stream, descriptions, verbosity) |
37 | + testtools.TextTestResult.__init__(self, stream) |
38 | if bench_history is not None: |
39 | from bzrlib.version import _get_bzr_source_tree |
40 | src_tree = _get_bzr_source_tree() |
41 | @@ -201,11 +201,13 @@ |
42 | actionTaken = "Ran" |
43 | stopTime = time.time() |
44 | timeTaken = stopTime - self.startTime |
45 | - self.printErrors() |
46 | - self.stream.writeln(self.separator2) |
47 | - self.stream.writeln("%s %d test%s in %.3fs" % (actionTaken, |
48 | + # GZ 2010-07-19: Seems testtools has no printErrors method, and though |
49 | + # the parent class method is similar have to duplicate |
50 | + self._show_list('ERROR', self.errors) |
51 | + self._show_list('FAIL', self.failures) |
52 | + self.stream.write(self.sep2) |
53 | + self.stream.write("%s %d test%s in %.3fs\n\n" % (actionTaken, |
54 | run, run != 1 and "s" or "", timeTaken)) |
55 | - self.stream.writeln() |
56 | if not self.wasSuccessful(): |
57 | self.stream.write("FAILED (") |
58 | failed, errored = map(len, (self.failures, self.errors)) |
59 | @@ -218,20 +220,20 @@ |
60 | if failed or errored: self.stream.write(", ") |
61 | self.stream.write("known_failure_count=%d" % |
62 | self.known_failure_count) |
63 | - self.stream.writeln(")") |
64 | + self.stream.write(")\n") |
65 | else: |
66 | if self.known_failure_count: |
67 | - self.stream.writeln("OK (known_failures=%d)" % |
68 | + self.stream.write("OK (known_failures=%d)\n" % |
69 | self.known_failure_count) |
70 | else: |
71 | - self.stream.writeln("OK") |
72 | + self.stream.write("OK\n") |
73 | if self.skip_count > 0: |
74 | skipped = self.skip_count |
75 | - self.stream.writeln('%d test%s skipped' % |
76 | + self.stream.write('%d test%s skipped\n' % |
77 | (skipped, skipped != 1 and "s" or "")) |
78 | if self.unsupported: |
79 | for feature, count in sorted(self.unsupported.items()): |
80 | - self.stream.writeln("Missing feature '%s' skipped %d tests." % |
81 | + self.stream.write("Missing feature '%s' skipped %d tests.\n" % |
82 | (feature, count)) |
83 | if self._strict: |
84 | ok = self.wasStrictlySuccessful() |
85 | @@ -279,7 +281,7 @@ |
86 | return what |
87 | |
88 | def startTest(self, test): |
89 | - unittest.TestResult.startTest(self, test) |
90 | + super(ExtendedTestResult, self).startTest(test) |
91 | if self.count == 0: |
92 | self.startTests() |
93 | self.report_test_start(test) |
94 | @@ -323,7 +325,7 @@ |
95 | fails with an unexpected error. |
96 | """ |
97 | self._post_mortem() |
98 | - unittest.TestResult.addError(self, test, err) |
99 | + super(ExtendedTestResult, self).addError(test, err) |
100 | self.error_count += 1 |
101 | self.report_error(test, err) |
102 | if self.stop_early: |
103 | @@ -337,7 +339,7 @@ |
104 | fails because e.g. an assert() method failed. |
105 | """ |
106 | self._post_mortem() |
107 | - unittest.TestResult.addFailure(self, test, err) |
108 | + super(ExtendedTestResult, self).addFailure(test, err) |
109 | self.failure_count += 1 |
110 | self.report_failure(test, err) |
111 | if self.stop_early: |
112 | @@ -357,7 +359,7 @@ |
113 | test.id())) |
114 | self.report_success(test) |
115 | self._cleanupLogFile(test) |
116 | - unittest.TestResult.addSuccess(self, test) |
117 | + super(ExtendedTestResult, self).addSuccess(test) |
118 | test._log_contents = '' |
119 | |
120 | def addExpectedFailure(self, test, err): |
121 | @@ -551,40 +553,40 @@ |
122 | return '%s%s' % (indent, err[1]) |
123 | |
124 | def report_error(self, test, err): |
125 | - self.stream.writeln('ERROR %s\n%s' |
126 | + self.stream.write('ERROR %s\n%s\n' |
127 | % (self._testTimeString(test), |
128 | self._error_summary(err))) |
129 | |
130 | def report_failure(self, test, err): |
131 | - self.stream.writeln(' FAIL %s\n%s' |
132 | + self.stream.write(' FAIL %s\n%s\n' |
133 | % (self._testTimeString(test), |
134 | self._error_summary(err))) |
135 | |
136 | def report_known_failure(self, test, err): |
137 | - self.stream.writeln('XFAIL %s\n%s' |
138 | + self.stream.write('XFAIL %s\n%s\n' |
139 | % (self._testTimeString(test), |
140 | self._error_summary(err))) |
141 | |
142 | def report_success(self, test): |
143 | - self.stream.writeln(' OK %s' % self._testTimeString(test)) |
144 | + self.stream.write(' OK %s\n' % self._testTimeString(test)) |
145 | for bench_called, stats in getattr(test, '_benchcalls', []): |
146 | - self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called) |
147 | + self.stream.write('LSProf output for %s(%s, %s)\n' % bench_called) |
148 | stats.pprint(file=self.stream) |
149 | # flush the stream so that we get smooth output. This verbose mode is |
150 | # used to show the output in PQM. |
151 | self.stream.flush() |
152 | |
153 | def report_skip(self, test, reason): |
154 | - self.stream.writeln(' SKIP %s\n%s' |
155 | + self.stream.write(' SKIP %s\n%s\n' |
156 | % (self._testTimeString(test), reason)) |
157 | |
158 | def report_not_applicable(self, test, reason): |
159 | - self.stream.writeln(' N/A %s\n %s' |
160 | + self.stream.write(' N/A %s\n %s\n' |
161 | % (self._testTimeString(test), reason)) |
162 | |
163 | def report_unsupported(self, test, feature): |
164 | """test cannot be run because feature is missing.""" |
165 | - self.stream.writeln("NODEP %s\n The feature '%s' is not available." |
166 | + self.stream.write("NODEP %s\n The feature '%s' is not available.\n" |
167 | %(self._testTimeString(test), feature)) |
168 | |
169 | |
170 | @@ -619,7 +621,7 @@ |
171 | encode = codec.encode |
172 | stream = osutils.UnicodeOrBytesToBytesWriter(encode, stream) |
173 | stream.encoding = new_encoding |
174 | - self.stream = unittest._WritelnDecorator(stream) |
175 | + self.stream = stream |
176 | self.descriptions = descriptions |
177 | self.verbosity = verbosity |
178 | self._bench_history = bench_history |
179 | |
180 | === modified file 'bzrlib/tests/test_selftest.py' |
181 | --- bzrlib/tests/test_selftest.py 2010-07-23 18:45:31 +0000 |
182 | +++ bzrlib/tests/test_selftest.py 2010-08-05 18:13:49 +0000 |
183 | @@ -801,7 +801,7 @@ |
184 | self.requireFeature(test_lsprof.LSProfFeature) |
185 | result_stream = StringIO() |
186 | result = bzrlib.tests.VerboseTestResult( |
187 | - unittest._WritelnDecorator(result_stream), |
188 | + result_stream, |
189 | descriptions=0, |
190 | verbosity=2, |
191 | ) |
192 | @@ -862,7 +862,7 @@ |
193 | # verbose test output formatting |
194 | result_stream = StringIO() |
195 | result = bzrlib.tests.VerboseTestResult( |
196 | - unittest._WritelnDecorator(result_stream), |
197 | + result_stream, |
198 | descriptions=0, |
199 | verbosity=2, |
200 | ) |
201 | @@ -878,6 +878,9 @@ |
202 | output = result_stream.getvalue()[prefix:] |
203 | lines = output.splitlines() |
204 | self.assertContainsRe(lines[0], r'XFAIL *\d+ms$') |
205 | + if sys.version_info > (2, 7): |
206 | + self.expectFailure("_ExpectedFailure on 2.7 loses the message", |
207 | + self.assertNotEqual, lines[1], ' ') |
208 | self.assertEqual(lines[1], ' foo') |
209 | self.assertEqual(2, len(lines)) |
210 | |
211 | @@ -917,7 +920,7 @@ |
212 | # verbose test output formatting |
213 | result_stream = StringIO() |
214 | result = bzrlib.tests.VerboseTestResult( |
215 | - unittest._WritelnDecorator(result_stream), |
216 | + result_stream, |
217 | descriptions=0, |
218 | verbosity=2, |
219 | ) |
220 | @@ -1419,7 +1422,7 @@ |
221 | sample_test = TestTestCase("method_that_times_a_bit_twice") |
222 | output_stream = StringIO() |
223 | result = bzrlib.tests.VerboseTestResult( |
224 | - unittest._WritelnDecorator(output_stream), |
225 | + output_stream, |
226 | descriptions=0, |
227 | verbosity=2) |
228 | sample_test.run(result) |
JAM and I were looking at this today, and started down the _WriteLnDecorator change you made (but you did it more thoroughly). I'm not really qualified to review the patch for bzr, but +1 on supporting Python 2.7 if you can do it without break promises for earlier Pythons.