From f40fcb33d2e905b128daa24f7ce6f25fb5cd5d9e Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 16 May 2015 16:42:18 +0300 Subject: Issue #23637: Showing a warning no longer fails with UnicodeErrror. Formatting unicode warning in the file with the path containing non-ascii characters no longer fails with UnicodeErrror. --- Lib/test/test_warnings.py | 57 +++++++++++++++++++++++++++++++++++++++++++++++ Lib/warnings.py | 22 ++++++++++++++++-- Misc/NEWS | 4 ++++ 3 files changed, 81 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_warnings.py b/Lib/test/test_warnings.py index 7a9459a..11dc294 100644 --- a/Lib/test/test_warnings.py +++ b/Lib/test/test_warnings.py @@ -593,6 +593,63 @@ class WarningsDisplayTests(unittest.TestCase): self.assertEqual(expect, self.module.formatwarning(message, category, file_name, line_num, file_line)) + @test_support.requires_unicode + def test_formatwarning_unicode_msg(self): + message = u"msg" + category = Warning + file_name = os.path.splitext(warning_tests.__file__)[0] + '.py' + line_num = 3 + file_line = linecache.getline(file_name, line_num).strip() + format = "%s:%s: %s: %s\n %s\n" + expect = format % (file_name, line_num, category.__name__, message, + file_line) + self.assertEqual(expect, self.module.formatwarning(message, + category, file_name, line_num)) + # Test the 'line' argument. + file_line += " for the win!" + expect = format % (file_name, line_num, category.__name__, message, + file_line) + self.assertEqual(expect, self.module.formatwarning(message, + category, file_name, line_num, file_line)) + + @test_support.requires_unicode + @unittest.skipUnless(test_support.FS_NONASCII, 'need test_support.FS_NONASCII') + def test_formatwarning_unicode_msg_nonascii_filename(self): + message = u"msg" + category = Warning + unicode_file_name = test_support.FS_NONASCII + u'.py' + file_name = unicode_file_name.encode(sys.getfilesystemencoding()) + line_num = 3 + file_line = 'spam' + format = "%s:%s: %s: %s\n %s\n" + expect = format % (file_name, line_num, category.__name__, str(message), + file_line) + self.assertEqual(expect, self.module.formatwarning(message, + category, file_name, line_num, file_line)) + message = u"\xb5sg" + expect = format % (unicode_file_name, line_num, category.__name__, message, + file_line) + self.assertEqual(expect, self.module.formatwarning(message, + category, file_name, line_num, file_line)) + + @test_support.requires_unicode + def test_formatwarning_unicode_msg_nonascii_fileline(self): + message = u"msg" + category = Warning + file_name = 'file.py' + line_num = 3 + file_line = 'sp\xe4m' + format = "%s:%s: %s: %s\n %s\n" + expect = format % (file_name, line_num, category.__name__, str(message), + file_line) + self.assertEqual(expect, self.module.formatwarning(message, + category, file_name, line_num, file_line)) + message = u"\xb5sg" + expect = format % (file_name, line_num, category.__name__, message, + unicode(file_line, 'latin1')) + self.assertEqual(expect, self.module.formatwarning(message, + category, file_name, line_num, file_line)) + def test_showwarning(self): file_name = os.path.splitext(warning_tests.__file__)[0] + '.py' line_num = 3 diff --git a/Lib/warnings.py b/Lib/warnings.py index fbec94b..b0d53aa 100644 --- a/Lib/warnings.py +++ b/Lib/warnings.py @@ -31,7 +31,7 @@ def _show_warning(message, category, filename, lineno, file=None, line=None): return try: file.write(formatwarning(message, category, filename, lineno, line)) - except IOError: + except (IOError, UnicodeError): pass # the file (probably stderr) is invalid - this warning gets lost. # Keep a working version around in case the deprecation of the old API is # triggered. @@ -39,11 +39,29 @@ showwarning = _show_warning def formatwarning(message, category, filename, lineno, line=None): """Function to format a warning the standard way.""" - s = "%s:%s: %s: %s\n" % (filename, lineno, category.__name__, message) + try: + unicodetype = unicode + except NameError: + unicodetype = () + try: + message = str(message) + except UnicodeEncodeError: + pass + s = "%s: %s: %s\n" % (lineno, category.__name__, message) line = linecache.getline(filename, lineno) if line is None else line if line: line = line.strip() + if isinstance(s, unicodetype) and isinstance(line, str): + line = unicode(line, 'latin1') s += " %s\n" % line + if isinstance(s, unicodetype) and isinstance(filename, str): + enc = sys.getfilesystemencoding() + if enc: + try: + filename = unicode(filename, enc) + except UnicodeDecodeError: + pass + s = "%s:%s" % (filename, s) return s def filterwarnings(action, message="", category=Warning, module="", lineno=0, diff --git a/Misc/NEWS b/Misc/NEWS index dbaddd8..8a8e8d2 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,10 @@ Core and Builtins Library ------- +- Issue #23637: Showing a warning no longer fails with UnicodeErrror. + Formatting unicode warning in the file with the path containing non-ascii + characters no longer fails with UnicodeErrror. + - Issue #24134: Reverted issue #24134 changes. -- cgit v0.12