Merge lp:~gz/brz/py3_crash_debug_trace into lp:brz
- py3_crash_debug_trace
- Merge into trunk
Proposed by
Martin Packman
Status: | Merged |
---|---|
Approved by: | Martin Packman |
Approved revision: | no longer in the source branch. |
Merge reported by: | The Breezy Bot |
Merged at revision: | not available |
Proposed branch: | lp:~gz/brz/py3_crash_debug_trace |
Merge into: | lp:brz |
Diff against target: |
568 lines (+115/-110) 7 files modified
breezy/crash.py (+1/-1) breezy/plugin.py (+4/-2) breezy/tests/blackbox/test_exceptions.py (+1/-2) breezy/tests/test_crash.py (+15/-24) breezy/tests/test_debug.py (+5/-4) breezy/tests/test_trace.py (+73/-67) breezy/trace.py (+16/-10) |
To merge this branch: | bzr merge lp:~gz/brz/py3_crash_debug_trace |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jelmer Vernooij | Approve | ||
Review via email: mp+325445@code.launchpad.net |
Commit message
Make tests pass on Python 3 for crash, debug, and trace modules
Description of the change
To post a comment you must log in.
Revision history for this message
Jelmer Vernooij (jelmer) : | # |
review:
Approve
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote : | # |
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote : | # |
Running landing tests failed
http://
Revision history for this message
Martin Packman (gz) wrote : | # |
Intermittent failure.
ERROR: breezy.
socket.error: [Errno 104] Connection reset by peer
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'breezy/crash.py' |
2 | --- breezy/crash.py 2017-05-22 00:56:52 +0000 |
3 | +++ breezy/crash.py 2017-06-10 22:21:19 +0000 |
4 | @@ -226,7 +226,7 @@ |
5 | |
6 | def _attach_log_tail(pr): |
7 | try: |
8 | - bzr_log = open(trace._get_bzr_log_filename(), 'rt') |
9 | + bzr_log = open(trace._get_brz_log_filename(), 'rt') |
10 | except (IOError, OSError) as e: |
11 | pr['BzrLogTail'] = repr(e) |
12 | return |
13 | |
14 | === modified file 'breezy/plugin.py' |
15 | --- breezy/plugin.py 2017-06-10 14:01:07 +0000 |
16 | +++ breezy/plugin.py 2017-06-10 22:21:19 +0000 |
17 | @@ -441,11 +441,13 @@ |
18 | return result |
19 | |
20 | |
21 | -def format_concise_plugin_list(): |
22 | +def format_concise_plugin_list(state=None): |
23 | """Return a string holding a concise list of plugins and their version. |
24 | """ |
25 | + if state is None: |
26 | + state = breezy.global_state |
27 | items = [] |
28 | - for name, a_plugin in sorted(plugins().items()): |
29 | + for name, a_plugin in sorted(state.plugins.items()): |
30 | items.append("%s[%s]" % |
31 | (name, a_plugin.__version__)) |
32 | return ', '.join(items) |
33 | |
34 | === modified file 'breezy/tests/blackbox/test_exceptions.py' |
35 | --- breezy/tests/blackbox/test_exceptions.py 2017-06-10 00:52:37 +0000 |
36 | +++ breezy/tests/blackbox/test_exceptions.py 2017-06-10 22:21:19 +0000 |
37 | @@ -40,8 +40,7 @@ |
38 | universal_newlines=True, |
39 | retcode=errors.EXIT_INTERNAL_ERROR) |
40 | self.assertEqual(4, errors.EXIT_INTERNAL_ERROR) |
41 | - self.assertContainsRe(err, |
42 | - r'exceptions\.AssertionError: always fails\n') |
43 | + self.assertContainsRe(err, r'\nAssertionError: always fails\n') |
44 | self.assertContainsRe(err, r'Bazaar has encountered an internal error') |
45 | |
46 | def test_undecodable_argv(self): |
47 | |
48 | === modified file 'breezy/tests/test_crash.py' |
49 | --- breezy/tests/test_crash.py 2017-05-22 00:56:52 +0000 |
50 | +++ breezy/tests/test_crash.py 2017-06-10 22:21:19 +0000 |
51 | @@ -19,6 +19,7 @@ |
52 | import os |
53 | import sys |
54 | |
55 | +import breezy |
56 | from .. import ( |
57 | config, |
58 | crash, |
59 | @@ -27,7 +28,7 @@ |
60 | tests, |
61 | ) |
62 | from ..sixish import ( |
63 | - BytesIO, |
64 | + StringIO, |
65 | ) |
66 | from . import features |
67 | |
68 | @@ -43,29 +44,23 @@ |
69 | self.assertEqual(crash_dir, config.crash_dir()) |
70 | |
71 | self.overrideAttr( |
72 | - plugin, |
73 | + breezy.global_state, |
74 | 'plugin_warnings', |
75 | {'example': ['Failed to load plugin foo']}) |
76 | |
77 | - stderr = BytesIO() |
78 | + stderr = StringIO() |
79 | |
80 | try: |
81 | raise AssertionError("my error") |
82 | except AssertionError as e: |
83 | - pass |
84 | - |
85 | - crash_filename = crash.report_bug_to_apport(sys.exc_info(), |
86 | - stderr) |
87 | + crash_filename = crash.report_bug_to_apport(sys.exc_info(), stderr) |
88 | |
89 | # message explaining the crash |
90 | self.assertContainsRe(stderr.getvalue(), |
91 | " apport-bug %s" % crash_filename) |
92 | |
93 | - crash_file = open(crash_filename) |
94 | - try: |
95 | + with open(crash_filename) as crash_file: |
96 | report = crash_file.read() |
97 | - finally: |
98 | - crash_file.close() |
99 | |
100 | self.assertContainsRe(report, |
101 | '(?m)^BzrVersion:') # should be in the traceback |
102 | @@ -83,31 +78,27 @@ |
103 | |
104 | class TestNonApportReporting(tests.TestCase): |
105 | """Reporting of crash-type bugs without apport. |
106 | - |
107 | + |
108 | This should work in all environments. |
109 | """ |
110 | |
111 | def setup_fake_plugins(self): |
112 | - def fake_plugins(): |
113 | - fake = plugin.PlugIn('fake_plugin', plugin) |
114 | - fake.version_info = lambda: (1, 2, 3) |
115 | - return {"fake_plugin": fake} |
116 | - self.overrideAttr(plugin, 'plugins', fake_plugins) |
117 | + fake = plugin.PlugIn('fake_plugin', plugin) |
118 | + fake.version_info = lambda: (1, 2, 3) |
119 | + fake_plugins = {"fake_plugin": fake} |
120 | + self.overrideAttr(breezy.global_state, 'plugins', fake_plugins) |
121 | |
122 | def test_report_bug_legacy(self): |
123 | self.setup_fake_plugins() |
124 | - err_file = BytesIO() |
125 | + err_file = StringIO() |
126 | try: |
127 | raise AssertionError("my error") |
128 | except AssertionError as e: |
129 | - pass |
130 | - crash.report_bug_legacy(sys.exc_info(), err_file) |
131 | + crash.report_bug_legacy(sys.exc_info(), err_file) |
132 | report = err_file.getvalue() |
133 | for needle in [ |
134 | - "brz: ERROR: exceptions.AssertionError: my error", |
135 | + "brz: ERROR: AssertionError: my error", |
136 | r"Traceback \(most recent call last\):", |
137 | r"plugins: fake_plugin\[1\.2\.3\]", |
138 | ]: |
139 | - self.assertContainsRe( |
140 | - report, |
141 | - needle) |
142 | + self.assertContainsRe(report, needle) |
143 | |
144 | === modified file 'breezy/tests/test_debug.py' |
145 | --- breezy/tests/test_debug.py 2017-05-22 00:56:52 +0000 |
146 | +++ breezy/tests/test_debug.py 2017-06-10 22:21:19 +0000 |
147 | @@ -27,17 +27,18 @@ |
148 | class TestDebugFlags(tests.TestCaseInTempDir): |
149 | |
150 | def test_set_no_debug_flags_from_config(self): |
151 | - self.assertDebugFlags([], '') |
152 | + self.assertDebugFlags([], b'') |
153 | |
154 | def test_set_single_debug_flags_from_config(self): |
155 | - self.assertDebugFlags(['hpss'], 'debug_flags = hpss\n') |
156 | + self.assertDebugFlags(['hpss'], b'debug_flags = hpss\n') |
157 | |
158 | def test_set_multiple_debug_flags_from_config(self): |
159 | - self.assertDebugFlags(['hpss', 'error'], 'debug_flags = hpss, error\n') |
160 | + self.assertDebugFlags( |
161 | + ['hpss', 'error'], b'debug_flags = hpss, error\n') |
162 | |
163 | def assertDebugFlags(self, expected_flags, conf_bytes): |
164 | conf = config.GlobalStack() |
165 | - conf.store._load_from_string('[DEFAULT]\n' + conf_bytes) |
166 | + conf.store._load_from_string(b'[DEFAULT]\n' + conf_bytes) |
167 | conf.store.save() |
168 | self.overrideAttr(debug, 'debug_flags', set()) |
169 | debug.set_debug_flags_from_config() |
170 | |
171 | === modified file 'breezy/tests/test_trace.py' |
172 | --- breezy/tests/test_trace.py 2017-05-22 00:56:52 +0000 |
173 | +++ breezy/tests/test_trace.py 2017-06-10 22:21:19 +0000 |
174 | @@ -31,7 +31,8 @@ |
175 | trace, |
176 | ) |
177 | from ..sixish import ( |
178 | - BytesIO, |
179 | + PY3, |
180 | + StringIO, |
181 | ) |
182 | from . import features, TestCaseInTempDir, TestCase |
183 | from ..trace import ( |
184 | @@ -46,7 +47,7 @@ |
185 | |
186 | def _format_exception(): |
187 | """Format an exception as it would normally be displayed to the user""" |
188 | - buf = BytesIO() |
189 | + buf = StringIO() |
190 | report_exception(sys.exc_info(), buf) |
191 | return buf.getvalue() |
192 | |
193 | @@ -61,10 +62,9 @@ |
194 | try: |
195 | raise NotImplementedError("time travel") |
196 | except NotImplementedError: |
197 | - pass |
198 | - err = _format_exception() |
199 | - self.assertEqualDiff(err.splitlines()[0], |
200 | - 'brz: ERROR: exceptions.NotImplementedError: time travel') |
201 | + err = _format_exception() |
202 | + self.assertContainsRe(err, |
203 | + '^brz: ERROR: NotImplementedError: time travel') |
204 | self.assertContainsRe(err, |
205 | 'Bazaar has encountered an internal error.') |
206 | |
207 | @@ -73,17 +73,14 @@ |
208 | raise KeyboardInterrupt() |
209 | except KeyboardInterrupt: |
210 | # XXX: Some risk that a *real* keyboard interrupt won't be seen |
211 | - pass |
212 | - msg = _format_exception() |
213 | - self.assertTrue(len(msg) > 0) |
214 | - self.assertEqualDiff(msg, 'brz: interrupted\n') |
215 | + msg = _format_exception() |
216 | + self.assertEqual(msg, 'brz: interrupted\n') |
217 | |
218 | def test_format_memory_error(self): |
219 | try: |
220 | raise MemoryError() |
221 | except MemoryError: |
222 | - pass |
223 | - msg = _format_exception() |
224 | + msg = _format_exception() |
225 | self.assertEqual(msg, |
226 | "brz: out of memory\nUse -Dmem_dump to dump memory to a file.\n") |
227 | |
228 | @@ -93,8 +90,7 @@ |
229 | try: |
230 | raise MemoryError() |
231 | except MemoryError: |
232 | - pass |
233 | - msg = _format_exception() |
234 | + msg = _format_exception() |
235 | self.assertStartsWith(msg, |
236 | "brz: out of memory\nMemory dumped to ") |
237 | |
238 | @@ -103,22 +99,21 @@ |
239 | os.rmdir('nosuchfile22222') |
240 | except OSError as e: |
241 | e_str = str(e) |
242 | - msg = _format_exception() |
243 | + msg = _format_exception() |
244 | # Linux seems to give "No such file" but Windows gives "The system |
245 | # cannot find the file specified". |
246 | self.assertEqual('brz: ERROR: %s\n' % (e_str,), msg) |
247 | |
248 | def test_format_io_error(self): |
249 | try: |
250 | - file('nosuchfile22222') |
251 | + open('nosuchfile22222') |
252 | except IOError: |
253 | - pass |
254 | - msg = _format_exception() |
255 | + msg = _format_exception() |
256 | # Even though Windows and Linux differ for 'os.rmdir', they both give |
257 | # 'No such file' for open() |
258 | # However it now gets translated so we can not test for a specific message |
259 | self.assertContainsRe(msg, |
260 | - r'^brz: ERROR: \[Errno .*\] .*nosuchfile') |
261 | + '^brz: ERROR: \\[Errno .*\\] .*nosuchfile') |
262 | |
263 | def test_format_pywintypes_error(self): |
264 | self.requireFeature(features.pywintypes) |
265 | @@ -126,63 +121,62 @@ |
266 | try: |
267 | win32file.RemoveDirectory('nosuchfile22222') |
268 | except pywintypes.error: |
269 | - pass |
270 | - msg = _format_exception() |
271 | + msg = _format_exception() |
272 | # GZ 2010-05-03: Formatting for pywintypes.error is basic, a 3-tuple |
273 | # with errno, function name, and locale error message |
274 | self.assertContainsRe(msg, |
275 | - r"^brz: ERROR: \(2, 'RemoveDirectory[AW]?', .*\)") |
276 | - |
277 | + "^brz: ERROR: \\(2, 'RemoveDirectory[AW]?', .*\\)") |
278 | + |
279 | def test_format_sockets_error(self): |
280 | try: |
281 | import socket |
282 | sock = socket.socket() |
283 | - sock.send("This should fail.") |
284 | + sock.send(b"This should fail.") |
285 | except socket.error: |
286 | - pass |
287 | - msg = _format_exception() |
288 | - |
289 | + msg = _format_exception() |
290 | + |
291 | self.assertNotContainsRe(msg, |
292 | - r"Traceback (most recent call last):") |
293 | + "Traceback \\(most recent call last\\):") |
294 | |
295 | def test_format_unicode_error(self): |
296 | try: |
297 | raise errors.BzrCommandError(u'argument foo\xb5 does not exist') |
298 | except errors.BzrCommandError: |
299 | - pass |
300 | - msg = _format_exception() |
301 | + msg = _format_exception() |
302 | + if PY3: |
303 | + expected = 'brz: ERROR: argument foo\xb5 does not exist\n' |
304 | + else: |
305 | + # GZ 2017-06-10: Pretty bogus, should encode per the output stream |
306 | + expected = 'brz: ERROR: argument foo\xc2\xb5 does not exist\n' |
307 | + self.assertEqual(msg, expected) |
308 | |
309 | def test_format_exception(self): |
310 | """Short formatting of brz exceptions""" |
311 | try: |
312 | raise errors.NotBranchError('wibble') |
313 | except errors.NotBranchError: |
314 | - pass |
315 | - msg = _format_exception() |
316 | - self.assertTrue(len(msg) > 0) |
317 | - self.assertEqualDiff(msg, 'brz: ERROR: Not a branch: \"wibble\".\n') |
318 | + msg = _format_exception() |
319 | + self.assertEqual(msg, 'brz: ERROR: Not a branch: \"wibble\".\n') |
320 | |
321 | def test_report_external_import_error(self): |
322 | """Short friendly message for missing system modules.""" |
323 | try: |
324 | import ImaginaryModule |
325 | except ImportError as e: |
326 | - pass |
327 | + msg = _format_exception() |
328 | else: |
329 | self.fail("somehow succeeded in importing %r" % ImaginaryModule) |
330 | - msg = _format_exception() |
331 | - self.assertEqual(msg, |
332 | - 'brz: ERROR: No module named ImaginaryModule\n' |
333 | - 'You may need to install this Python library separately.\n') |
334 | + self.assertContainsRe(msg, |
335 | + "^brz: ERROR: No module named '?ImaginaryModule'?\n" |
336 | + "You may need to install this Python library separately.\n$") |
337 | |
338 | def test_report_import_syntax_error(self): |
339 | try: |
340 | raise ImportError("syntax error") |
341 | except ImportError as e: |
342 | - pass |
343 | - msg = _format_exception() |
344 | + msg = _format_exception() |
345 | self.assertContainsRe(msg, |
346 | - r'Bazaar has encountered an internal error') |
347 | + 'Bazaar has encountered an internal error') |
348 | |
349 | def test_trace_unicode(self): |
350 | """Write Unicode to trace log""" |
351 | @@ -212,17 +206,18 @@ |
352 | else: |
353 | self.fail("expected error not raised") |
354 | |
355 | - def assertLogStartsWith(self, log, string): |
356 | - """Like assertStartsWith, but skips the log timestamp.""" |
357 | + def assertLogContainsLine(self, log, string): |
358 | + """Assert log contains a line including log timestamp.""" |
359 | + # Does not check absolute position in log as there may be kipple. |
360 | self.assertContainsRe(log, |
361 | - '^\\d+\\.\\d+ ' + re.escape(string)) |
362 | + '(?m)^\\d+\\.\\d+ ' + re.escape(string)) |
363 | |
364 | def test_mutter_callsite_1(self): |
365 | """mutter_callsite can capture 1 level of stack frame.""" |
366 | mutter_callsite(1, "foo %s", "a string") |
367 | log = self.get_log() |
368 | # begin with the message |
369 | - self.assertLogStartsWith(log, 'foo a string\nCalled from:\n') |
370 | + self.assertLogContainsLine(log, 'foo a string\nCalled from:\n') |
371 | # should show two frame: this frame and the one above |
372 | self.assertContainsRe(log, |
373 | 'test_trace\\.py", line \\d+, in test_mutter_callsite_1\n') |
374 | @@ -234,7 +229,7 @@ |
375 | mutter_callsite(2, "foo %s", "a string") |
376 | log = self.get_log() |
377 | # begin with the message |
378 | - self.assertLogStartsWith(log, 'foo a string\nCalled from:\n') |
379 | + self.assertLogContainsLine(log, 'foo a string\nCalled from:\n') |
380 | # should show two frame: this frame and the one above |
381 | self.assertContainsRe(log, |
382 | 'test_trace.py", line \d+, in test_mutter_callsite_2\n') |
383 | @@ -247,15 +242,15 @@ |
384 | # This test checks that mutter doesn't fail; the current behaviour |
385 | # is that it doesn't fail *and writes non-utf8*. |
386 | mutter(u'Writing a greek mu (\xb5) works in a unicode string') |
387 | - mutter('But fails in an ascii string \xb5') |
388 | - mutter('and in an ascii argument: %s', '\xb5') |
389 | + mutter(b'But fails in an ascii string \xb5') |
390 | + mutter(b'and in an ascii argument: %s', b'\xb5') |
391 | log = self.get_log() |
392 | self.assertContainsRe(log, 'Writing a greek mu') |
393 | self.assertContainsRe(log, "But fails in an ascii string") |
394 | # However, the log content object does unicode replacement on reading |
395 | # to let it get unicode back where good data has been written. So we |
396 | # have to do a replaceent here as well. |
397 | - self.assertContainsRe(log, "ascii argument: \xb5".decode('utf8', |
398 | + self.assertContainsRe(log, b"ascii argument: \xb5".decode('utf8', |
399 | 'replace')) |
400 | |
401 | def test_show_error(self): |
402 | @@ -303,10 +298,11 @@ |
403 | # as there's a timestamp at the front. |
404 | tmp1.seek(0) |
405 | self.assertContainsRe(tmp1.read(), |
406 | - r"\d+\.\d+ comment to file1\n\d+\.\d+ again to file1\n") |
407 | + b"\\d+\\.\\d+ comment to file1\n" |
408 | + b"\\d+\\.\\d+ again to file1\n") |
409 | tmp2.seek(0) |
410 | self.assertContainsRe(tmp2.read(), |
411 | - r"\d+\.\d+ comment to file2\n") |
412 | + b"\\d+\\.\\d+ comment to file2\n") |
413 | finally: |
414 | tmp1.close() |
415 | tmp2.close() |
416 | @@ -315,7 +311,7 @@ |
417 | # If _open_brz_log cannot open the file, then we should write the |
418 | # warning to stderr. Since this is normally happening before logging is |
419 | # set up. |
420 | - self.overrideAttr(sys, 'stderr', BytesIO()) |
421 | + self.overrideAttr(sys, 'stderr', StringIO()) |
422 | # Set the log file to something that cannot exist |
423 | self.overrideEnv('BRZ_LOG', '/no-such-dir/brz.log') |
424 | self.overrideAttr(trace, '_brz_log_filename') |
425 | @@ -378,33 +374,43 @@ |
426 | self.assertEqual(u" DEBUG \xa7\n", self.get_log()) |
427 | |
428 | def test_log_utf8_msg(self): |
429 | - logging.getLogger("brz").debug("\xc2\xa7") |
430 | + logging.getLogger("brz").debug(b"\xc2\xa7") |
431 | self.assertEqual(u" DEBUG \xa7\n", self.get_log()) |
432 | |
433 | def test_log_utf8_arg(self): |
434 | - logging.getLogger("brz").debug("%s", "\xc2\xa7") |
435 | - self.assertEqual(u" DEBUG \xa7\n", self.get_log()) |
436 | + logging.getLogger("brz").debug(b"%s", b"\xc2\xa7") |
437 | + if PY3: |
438 | + expected = u" DEBUG b'\\xc2\\xa7'\n" |
439 | + else: |
440 | + expected = u" DEBUG \xa7\n" |
441 | + self.assertEqual(expected, self.get_log()) |
442 | |
443 | def test_log_bytes_msg(self): |
444 | - logging.getLogger("brz").debug("\xa7") |
445 | + logging.getLogger("brz").debug(b"\xa7") |
446 | log = self.get_log() |
447 | self.assertContainsString(log, "UnicodeDecodeError: ") |
448 | - self.assertContainsString(log, |
449 | - "Logging record unformattable: '\\xa7' % ()\n") |
450 | + self.assertContainsRe(log, |
451 | + "Logging record unformattable: b?'\\\\xa7' % \\(\\)\n") |
452 | |
453 | def test_log_bytes_arg(self): |
454 | - logging.getLogger("brz").debug("%s", "\xa7") |
455 | + logging.getLogger("brz").debug(b"%s", b"\xa7") |
456 | log = self.get_log() |
457 | - self.assertContainsString(log, "UnicodeDecodeError: ") |
458 | - self.assertContainsString(log, |
459 | - "Logging record unformattable: '%s' % ('\\xa7',)\n") |
460 | + if PY3: |
461 | + self.assertEqual(u" DEBUG b'\\xa7'\n", self.get_log()) |
462 | + else: |
463 | + self.assertContainsString(log, "UnicodeDecodeError: ") |
464 | + self.assertContainsRe(log, |
465 | + "Logging record unformattable: ?'%s' % \\(b?'\\\\xa7',\\)\n") |
466 | |
467 | def test_log_mixed_strings(self): |
468 | - logging.getLogger("brz").debug(u"%s", "\xa7") |
469 | + logging.getLogger("brz").debug(u"%s", b"\xa7") |
470 | log = self.get_log() |
471 | - self.assertContainsString(log, "UnicodeDecodeError: ") |
472 | - self.assertContainsString(log, |
473 | - "Logging record unformattable: u'%s' % ('\\xa7',)\n") |
474 | + if PY3: |
475 | + self.assertEqual(u" DEBUG b'\\xa7'\n", self.get_log()) |
476 | + else: |
477 | + self.assertContainsString(log, "UnicodeDecodeError: ") |
478 | + self.assertContainsRe(log, |
479 | + "Logging record unformattable: u'%s' % \\('\\\\xa7',\\)\n") |
480 | |
481 | def test_log_repr_broken(self): |
482 | class BadRepr(object): |
483 | |
484 | === modified file 'breezy/trace.py' |
485 | --- breezy/trace.py 2017-05-22 00:56:52 +0000 |
486 | +++ breezy/trace.py 2017-06-10 22:21:19 +0000 |
487 | @@ -82,6 +82,8 @@ |
488 | |
489 | from .sixish import ( |
490 | BytesIO, |
491 | + PY3, |
492 | + StringIO, |
493 | text_type, |
494 | ) |
495 | |
496 | @@ -173,7 +175,7 @@ |
497 | :param fmt: The format string to pass to mutter. |
498 | :param args: A list of substitution variables. |
499 | """ |
500 | - outf = BytesIO() |
501 | + outf = StringIO() |
502 | if stacklevel is None: |
503 | limit = None |
504 | else: |
505 | @@ -252,9 +254,9 @@ |
506 | brz_log_file = _open_or_create_log_file(_brz_log_filename) |
507 | brz_log_file.write(b'\n') |
508 | if brz_log_file.tell() <= 2: |
509 | - brz_log_file.write("this is a debug log for diagnosing/reporting problems in brz\n") |
510 | - brz_log_file.write("you can delete or truncate this file, or include sections in\n") |
511 | - brz_log_file.write("bug reports to https://bugs.launchpad.net/brz/+filebug\n\n") |
512 | + brz_log_file.write(b"this is a debug log for diagnosing/reporting problems in brz\n") |
513 | + brz_log_file.write(b"you can delete or truncate this file, or include sections in\n") |
514 | + brz_log_file.write(b"bug reports to https://bugs.launchpad.net/brz/+filebug\n\n") |
515 | |
516 | return brz_log_file |
517 | |
518 | @@ -469,7 +471,7 @@ |
519 | """ |
520 | class_name = eclass.__name__ |
521 | module_name = eclass.__module__ |
522 | - if module_name in ("exceptions", "__main__") or ( |
523 | + if module_name in ("builtins", "exceptions", "__main__") or ( |
524 | unqualified_breezy_errors and module_name == "breezy.errors"): |
525 | return class_name |
526 | return "%s.%s" % (module_name, class_name) |
527 | @@ -521,8 +523,8 @@ |
528 | |
529 | def print_exception(exc_info, err_file): |
530 | exc_type, exc_object, exc_tb = exc_info |
531 | - err_file.write("brz: ERROR: %s.%s: %s\n" % ( |
532 | - exc_type.__module__, exc_type.__name__, exc_object)) |
533 | + err_file.write("brz: ERROR: %s: %s\n" % ( |
534 | + _qualified_exception_name(exc_type), exc_object)) |
535 | err_file.write('\n') |
536 | traceback.print_exception(exc_type, exc_object, exc_tb, file=err_file) |
537 | |
538 | @@ -539,7 +541,7 @@ |
539 | """ |
540 | err_file.write("brz: ERROR: %s\n" % (exc_info[1],)) |
541 | if advice: |
542 | - err_file.write("%s\n" % (advice,)) |
543 | + err_file.write("%s\n" % advice) |
544 | |
545 | |
546 | def report_bug(exc_info, err_file): |
547 | @@ -597,6 +599,10 @@ |
548 | |
549 | def emit(self, record): |
550 | try: |
551 | + if not isinstance(record.msg, text_type): |
552 | + msg = record.msg.decode("utf-8") |
553 | + if PY3: |
554 | + record.msg = msg |
555 | line = self.format(record) |
556 | if not isinstance(line, text_type): |
557 | line = line.decode("utf-8") |
558 | @@ -606,8 +612,8 @@ |
559 | # Try saving the details that would have been logged in some form |
560 | msg = args = "<Unformattable>" |
561 | try: |
562 | - msg = repr(record.msg).encode("ascii") |
563 | - args = repr(record.args).encode("ascii") |
564 | + msg = repr(record.msg).encode("ascii", "backslashescape") |
565 | + args = repr(record.args).encode("ascii", "backslashescape") |
566 | except Exception: |
567 | pass |
568 | # Using mutter() bypasses the logging module and writes directly |
Running landing tests failed 10.242. 247.184: 8080/job/ brz-dev/ 114/
http://