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.
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 @@
         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 @@
             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 @@
 
 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,