Merged revisions 57152-57220 via svnmerge from
authorGuido van Rossum <guido@python.org>
Mon, 20 Aug 2007 19:06:03 +0000 (19:06 +0000)
committerGuido van Rossum <guido@python.org>
Mon, 20 Aug 2007 19:06:03 +0000 (19:06 +0000)
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r57155 | brett.cannon | 2007-08-17 11:51:57 -0700 (Fri, 17 Aug 2007) | 2 lines

  Clarify the comment about setting the PYTHON variable for the Doc Makefile.
........
  r57156 | brett.cannon | 2007-08-17 11:59:58 -0700 (Fri, 17 Aug 2007) | 3 lines

  Remove news entry for test.test_support.guard_warnings_filter as it has been
  removed.
........
  r57158 | facundo.batista | 2007-08-17 12:16:44 -0700 (Fri, 17 Aug 2007) | 9 lines

  Added a flag (_send_traceback_header) to the SimpleXMLRPCServer class
  that allows sending back exception/stack trace information about
  internal server errors (this flag defaults to False to avoid sending
  such information unless explicitly enabled).  Added tests to verify
  behavior of this new feature (these tests are skipped on win32 because
  of problems with WSAEWOULDBLOCK). Renamed HTTPTestCase to
  SimpleServerTestCase. [GSoC - Alan McIntyre]
........
  r57160 | brett.cannon | 2007-08-17 13:16:15 -0700 (Fri, 17 Aug 2007) | 2 lines

  Make test_warnings re-entrant.
........
  r57175 | georg.brandl | 2007-08-17 23:05:56 -0700 (Fri, 17 Aug 2007) | 2 lines

  Fix PDB command descriptions.
........
  r57182 | brett.cannon | 2007-08-18 11:30:36 -0700 (Sat, 18 Aug 2007) | 3 lines

  Remove Mikael as the maintainer of BeOS at his request.  With no maintainer
  should the port be deprecated in 2.6?
........
  r57199 | georg.brandl | 2007-08-19 11:43:50 -0700 (Sun, 19 Aug 2007) | 2 lines

  Fix stray backticks.
........
  r57211 | hyeshik.chang | 2007-08-19 23:49:18 -0700 (Sun, 19 Aug 2007) | 2 lines

  Add cheot-ga-keut composed make-up sequence support in EUC-KR codec.
........
  r57216 | guido.van.rossum | 2007-08-20 08:18:04 -0700 (Mon, 20 Aug 2007) | 4 lines

  Add a hack (originally devised in a slightly different form by Thomas Wouters)
  to prevent spurious tracebacks when a daemon thread's cleanup happens to wake
  up when the world around it has already been destroyed.
........

Doc/library/formatter.rst
Doc/library/pdb.rst
Doc/tools/sphinx-build.py
Lib/SimpleXMLRPCServer.py
Lib/test/cjkencodings_test.py
Lib/test/test_codecencodings_kr.py
Lib/test/test_codecmaps_kr.py
Lib/test/test_warnings.py
Lib/test/test_xmlrpc.py
Lib/threading.py
Modules/cjkcodecs/_codecs_kr.c

index 2774a2bda67c640417bc08c572f6c8582c0ccf17..ba09b8e838a8c9045e047fc325712dc11a6e749e 100644 (file)
@@ -242,8 +242,8 @@ typically be provided by the application.
 .. method:: writer.new_font(font)
 
    Set the font style.  The value of *font* will be ``None``, indicating that the
-   device's default font should be used, or a tuple of the form ``(``*size*,
-   *italic*, *bold*, *teletype*``)``.  Size will be a string indicating the size of
+   device's default font should be used, or a tuple of the form ``(size,
+   italic, bold, teletype)``.  Size will be a string indicating the size of
    font that should be used; specific strings and their interpretation must be
    defined by the application.  The *italic*, *bold*, and *teletype* values are
    Boolean values specifying which of those font attributes should be used.
index 804dd237ac9c7febc8cc45a127d5d77dac002811..d84c549b1a108b1498580915e976eb7cb909b1b4 100644 (file)
@@ -178,7 +178,7 @@ d(own)
 u(p)
    Move the current frame one level up in the stack trace (to an older frame).
 
-b(reak) [[*filename*:]*lineno*``|``*function*[, *condition*]]
+b(reak) [[*filename*:]\ *lineno* | *function*\ [, *condition*]]
    With a *lineno* argument, set a break there in the current file.  With a
    *function* argument, set a break at the first executable statement within that
    function. The line number may be prefixed with a filename and a colon, to
@@ -193,7 +193,7 @@ b(reak) [[*filename*:]*lineno*``|``*function*[, *condition*]]
    times that breakpoint has been hit, the current ignore count, and the associated
    condition if any.
 
-tbreak [[*filename*:]*lineno*``|``*function*[, *condition*]]
+tbreak [[*filename*:]\ *lineno* | *function*\ [, *condition*]]
    Temporary breakpoint, which is removed automatically when it is first hit.  The
    arguments are the same as break.
 
@@ -279,7 +279,7 @@ j(ump) *lineno*
    possible to jump into the middle of a :keyword:`for` loop or out of a
    :keyword:`finally` clause.
 
-l(ist) [*first*[, *last*]]
+l(ist) [*first*[, *last*]]
    List source code for the current file.  Without arguments, list 11 lines around
    the current line or continue the previous listing.  With one argument, list 11
    lines around at that line.  With two arguments, list the given range; if the
@@ -324,7 +324,7 @@ alias [*name* [command]]
 unalias *name*
    Deletes the specified alias.
 
-[!]*statement*
+[!]*statement*
    Execute the (one-line) *statement* in the context of the current stack frame.
    The exclamation point can be omitted unless the first word of the statement
    resembles a debugger command. To set a global variable, you can prefix the
index 8c9331e0efb3ce30ddd53648f9e65b5f481329c2..e19b10a04a86f3d5b91ac8a8cde7fdc45f363984 100644 (file)
@@ -13,9 +13,10 @@ if __name__ == '__main__':
 
     if sys.version_info[:3] < (2, 5, 0):
         print >>sys.stderr, """\
-Error: Sphinx needs to be executed with Python 2.5 or newer.
+Error: Sphinx needs to be executed with Python 2.5 or newer
 (If you run this from the Makefile, you can set the PYTHON variable
-to the path of an alternative interpreter executable.)
+to the path of an alternative interpreter executable, e.g.,
+``make html PYTHON=python2.5``).
 """
         sys.exit(1)
 
index 458d4278f8f4765c10f9d1d9de3ec862104b6536..5f6e9d0bdecf58d0cad7105b89c2cff3be4567e4 100644 (file)
@@ -104,6 +104,7 @@ import SocketServer
 import BaseHTTPServer
 import sys
 import os
+import traceback
 try:
     import fcntl
 except ImportError:
@@ -451,9 +452,16 @@ class SimpleXMLRPCRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
             response = self.server._marshaled_dispatch(
                     data, getattr(self, '_dispatch', None)
                 )
-        except: # This should only happen if the module is buggy
+        except Exception as e: # This should only happen if the module is buggy
             # internal error, report as HTTP server error
             self.send_response(500)
+
+            # Send information about the exception if requested
+            if hasattr(self.server, '_send_traceback_header') and \
+                    self.server._send_traceback_header:
+                self.send_header("X-exception", str(e))
+                self.send_header("X-traceback", traceback.format_exc())
+
             self.end_headers()
         else:
             # got a valid XML RPC response
@@ -498,6 +506,12 @@ class SimpleXMLRPCServer(SocketServer.TCPServer,
 
     allow_reuse_address = True
 
+    # Warning: this is for debugging purposes only! Never set this to True in
+    # production code, as will be sending out sensitive information (exception
+    # and stack trace details) when exceptions are raised inside
+    # SimpleXMLRPCRequestHandler.do_POST
+    _send_traceback_header = False
+
     def __init__(self, addr, requestHandler=SimpleXMLRPCRequestHandler,
                  logRequests=True, allow_none=False, encoding=None, bind_and_activate=True):
         self.logRequests = logRequests
index d5873c01f40ee0bf1c18c9dde486a445ade9f4d0..72f4bdc67b8bd50d093cdc4873502717cc42ea80 100644 (file)
@@ -376,13 +376,20 @@ b"\x20\xb9\xae\xb9\xfd\xb0\xfa\x20\xb5\xbf\xc0\xfb\x20\xc5\xb8\xc0"
 b"\xcc\xc7\xce\x2c\x20\xb1\xd7\xb8\xae\xb0\xed\x20\xc0\xce\xc5\xcd"
 b"\xc7\xc1\xb8\xae\xc6\xc3\x0a\xc8\xaf\xb0\xe6\xc0\xba\x20\xc6\xc4"
 b"\xc0\xcc\xbd\xe3\xc0\xbb\x20\xbd\xba\xc5\xa9\xb8\xb3\xc6\xc3\xb0"
-b"\xfa\x20\xbf\xa9\xb7\xc1\x20\xba\xd0\xbe\xdf\xbf\xa1\xbc\xad\xbf"
+b"\xfa\x20\xbf\xa9\xb7\xaf\x20\xba\xd0\xbe\xdf\xbf\xa1\xbc\xad\xbf"
 b"\xcd\x20\xb4\xeb\xba\xce\xba\xd0\xc0\xc7\x20\xc7\xc3\xb7\xa7\xc6"
 b"\xfb\xbf\xa1\xbc\xad\xc0\xc7\x20\xba\xfc\xb8\xa5\x0a\xbe\xd6\xc7"
 b"\xc3\xb8\xae\xc4\xc9\xc0\xcc\xbc\xc7\x20\xb0\xb3\xb9\xdf\xc0\xbb"
 b"\x20\xc7\xd2\x20\xbc\xf6\x20\xc0\xd6\xb4\xc2\x20\xc0\xcc\xbb\xf3"
 b"\xc0\xfb\xc0\xce\x20\xbe\xf0\xbe\xee\xb7\xce\x20\xb8\xb8\xb5\xe9"
-b"\xbe\xee\xc1\xdd\xb4\xcf\xb4\xd9\x2e\x0a\x0a",
+b"\xbe\xee\xc1\xdd\xb4\xcf\xb4\xd9\x2e\x0a\x0a\xa1\xd9\xc3\xb9\xb0"
+b"\xa1\xb3\xa1\x3a\x20\xb3\xaf\xbe\xc6\xb6\xf3\x20\xa4\xd4\xa4\xb6"
+b"\xa4\xd0\xa4\xd4\xa4\xd4\xa4\xb6\xa4\xd0\xa4\xd4\xbe\xb1\x7e\x20"
+b"\xa4\xd4\xa4\xa4\xa4\xd2\xa4\xb7\xc5\xad\x21\x20\xa4\xd4\xa4\xa8"
+b"\xa4\xd1\xa4\xb7\xb1\xdd\xbe\xf8\xc0\xcc\x20\xc0\xfc\xa4\xd4\xa4"
+b"\xbe\xa4\xc8\xa4\xb2\xb4\xcf\xb4\xd9\x2e\x20\xa4\xd4\xa4\xb2\xa4"
+b"\xce\xa4\xaa\x2e\x20\xb1\xd7\xb7\xb1\xb0\xc5\x20\xa4\xd4\xa4\xb7"
+b"\xa4\xd1\xa4\xb4\xb4\xd9\x2e\x0a",
 b"\xe2\x97\x8e\x20\xed\x8c\x8c\xec\x9d\xb4\xec\x8d\xac\x28\x50\x79"
 b"\x74\x68\x6f\x6e\x29\xec\x9d\x80\x20\xeb\xb0\xb0\xec\x9a\xb0\xea"
 b"\xb8\xb0\x20\xec\x89\xbd\xea\xb3\xa0\x2c\x20\xea\xb0\x95\xeb\xa0"
@@ -404,7 +411,7 @@ b"\xb4\xed\x95\x91\x2c\x20\xea\xb7\xb8\xeb\xa6\xac\xea\xb3\xa0\x20"
 b"\xec\x9d\xb8\xed\x84\xb0\xed\x94\x84\xeb\xa6\xac\xed\x8c\x85\x0a"
 b"\xed\x99\x98\xea\xb2\xbd\xec\x9d\x80\x20\xed\x8c\x8c\xec\x9d\xb4"
 b"\xec\x8d\xac\xec\x9d\x84\x20\xec\x8a\xa4\xed\x81\xac\xeb\xa6\xbd"
-b"\xed\x8c\x85\xea\xb3\xbc\x20\xec\x97\xac\xeb\xa0\xa4\x20\xeb\xb6"
+b"\xed\x8c\x85\xea\xb3\xbc\x20\xec\x97\xac\xeb\x9f\xac\x20\xeb\xb6"
 b"\x84\xec\x95\xbc\xec\x97\x90\xec\x84\x9c\xec\x99\x80\x20\xeb\x8c"
 b"\x80\xeb\xb6\x80\xeb\xb6\x84\xec\x9d\x98\x20\xed\x94\x8c\xeb\x9e"
 b"\xab\xed\x8f\xbc\xec\x97\x90\xec\x84\x9c\xec\x9d\x98\x20\xeb\xb9"
@@ -413,7 +420,13 @@ b"\x80\xec\x9d\xb4\xec\x85\x98\x20\xea\xb0\x9c\xeb\xb0\x9c\xec\x9d"
 b"\x84\x20\xed\x95\xa0\x20\xec\x88\x98\x20\xec\x9e\x88\xeb\x8a\x94"
 b"\x20\xec\x9d\xb4\xec\x83\x81\xec\xa0\x81\xec\x9d\xb8\x20\xec\x96"
 b"\xb8\xec\x96\xb4\xeb\xa1\x9c\x20\xeb\xa7\x8c\xeb\x93\xa4\xec\x96"
-b"\xb4\xec\xa4\x8d\xeb\x8b\x88\xeb\x8b\xa4\x2e\x0a\x0a"),
+b"\xb4\xec\xa4\x8d\xeb\x8b\x88\xeb\x8b\xa4\x2e\x0a\x0a\xe2\x98\x86"
+b"\xec\xb2\xab\xea\xb0\x80\xeb\x81\x9d\x3a\x20\xeb\x82\xa0\xec\x95"
+b"\x84\xeb\x9d\xbc\x20\xec\x93\x94\xec\x93\x94\xec\x93\xa9\x7e\x20"
+b"\xeb\x8b\x81\xed\x81\xbc\x21\x20\xeb\x9c\xbd\xea\xb8\x88\xec\x97"
+b"\x86\xec\x9d\xb4\x20\xec\xa0\x84\xed\x99\xa5\xeb\x8b\x88\xeb\x8b"
+b"\xa4\x2e\x20\xeb\xb7\x81\x2e\x20\xea\xb7\xb8\xeb\x9f\xb0\xea\xb1"
+b"\xb0\x20\xec\x9d\x8e\xeb\x8b\xa4\x2e\x0a"),
 'gb18030': (
 b"\x50\x79\x74\x68\x6f\x6e\xa3\xa8\xc5\xc9\xc9\xad\xa3\xa9\xd3\xef"
 b"\xd1\xd4\xca\xc7\xd2\xbb\xd6\xd6\xb9\xa6\xc4\xdc\xc7\xbf\xb4\xf3"
index 86663c72d01d4526cf7717a027c930ea618bb0b2..18ed3934c344d0ae839d06a0fba21840e44b8526 100644 (file)
@@ -30,6 +30,24 @@ class Test_EUCKR(test_multibytecodec_support.TestBase, unittest.TestCase):
         (b"abc\x80\x80\xc1\xc4", "replace", "abc\ufffd\uc894"),
         (b"abc\x80\x80\xc1\xc4\xc8", "replace", "abc\ufffd\uc894\ufffd"),
         (b"abc\x80\x80\xc1\xc4", "ignore",  "abc\uc894"),
+
+        # composed make-up sequence errors
+        (b"\xa4\xd4", "strict", None),
+        (b"\xa4\xd4\xa4", "strict", None),
+        (b"\xa4\xd4\xa4\xb6", "strict", None),
+        (b"\xa4\xd4\xa4\xb6\xa4", "strict", None),
+        (b"\xa4\xd4\xa4\xb6\xa4\xd0", "strict", None),
+        (b"\xa4\xd4\xa4\xb6\xa4\xd0\xa4", "strict", None),
+        (b"\xa4\xd4\xa4\xb6\xa4\xd0\xa4\xd4", "strict", "\uc4d4"),
+        (b"\xa4\xd4\xa4\xb6\xa4\xd0\xa4\xd4x", "strict", "\uc4d4x"),
+        (b"a\xa4\xd4\xa4\xb6\xa4", "replace", "a\ufffd"),
+        (b"\xa4\xd4\xa3\xb6\xa4\xd0\xa4\xd4", "strict", None),
+        (b"\xa4\xd4\xa4\xb6\xa3\xd0\xa4\xd4", "strict", None),
+        (b"\xa4\xd4\xa4\xb6\xa4\xd0\xa3\xd4", "strict", None),
+        (b"\xa4\xd4\xa4\xff\xa4\xd0\xa4\xd4", "replace", "\ufffd"),
+        (b"\xa4\xd4\xa4\xb6\xa4\xff\xa4\xd4", "replace", "\ufffd"),
+        (b"\xa4\xd4\xa4\xb6\xa4\xd0\xa4\xff", "replace", "\ufffd"),
+        (b"\xc1\xc4", "strict", "\uc894"),
     )
 
 class Test_JOHAB(test_multibytecodec_support.TestBase, unittest.TestCase):
index 4a97611d7a6404cd1d7679de3172d86c5a35b87e..f9c97e5b490c640662ba31020718d1b2248f14c7 100644 (file)
@@ -20,6 +20,10 @@ class TestEUCKRMap(test_multibytecodec_support.TestBase_Mapping,
     encoding = 'euc_kr'
     mapfileurl = 'http://people.freebsd.org/~perky/i18n/EUC-KR.TXT'
 
+    # A4D4 HANGUL FILLER indicates the begin of 8-bytes make-up sequence.
+    pass_enctest = [(b'\xa4\xd4', '\u3164')]
+    pass_dectest = [(b'\xa4\xd4', '\u3164')]
+
 
 class TestJOHABMap(test_multibytecodec_support.TestBase_Mapping,
                    unittest.TestCase):
index 54d5dd2dbdbb268d9a7fdf60d1663ce3e79282be..6889e3f04849b339e218993c4520e98358cd5958 100644 (file)
@@ -1,5 +1,6 @@
 import warnings
 import os
+import sys
 import unittest
 from test import test_support
 
@@ -101,6 +102,10 @@ def test_main(verbose=None):
     # to test_main (regrtest -R).
     if '__warningregistry__' in globals():
         del globals()['__warningregistry__']
+    if hasattr(warning_tests, '__warningregistry__'):
+        del warning_tests.__warningregistry__
+    if hasattr(sys, '__warningregistry__'):
+        del sys.__warningregistry__
     test_support.run_unittest(TestModule)
 
 if __name__ == "__main__":
index 4a15de53a55a58f92f91348d172d4de47a2312a6..7dfabcf415ff98018c6501840fe818258f76f39d 100644 (file)
@@ -6,6 +6,7 @@ import unittest
 import xmlrpclib
 import SimpleXMLRPCServer
 import threading
+import mimetools
 from test import test_support
 
 alist = [{'astring': 'foo@bar.baz.spam',
@@ -249,11 +250,9 @@ def http_server(evt, numrequests):
             '''This is the div function'''
             return x // y
 
-
-    serv = SimpleXMLRPCServer.SimpleXMLRPCServer(("localhost", 0),
-                    logRequests=False, bind_and_activate=False)
-
     try:
+        serv = SimpleXMLRPCServer.SimpleXMLRPCServer(("localhost", 0),
+                        logRequests=False, bind_and_activate=False)
         serv.socket.settimeout(3)
         serv.server_bind()
         global PORT
@@ -278,11 +277,15 @@ def http_server(evt, numrequests):
         evt.set()
 
 
-class HTTPTestCase(unittest.TestCase):
+class SimpleServerTestCase(unittest.TestCase):
     def setUp(self):
+        # enable traceback reporting
+        SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = True
+
         self.evt = threading.Event()
-        # start server thread to handle just one request
-        threading.Thread(target=http_server, args=(self.evt,2)).start()
+        # start server thread to handle requests
+        serv_args = (self.evt, 2)
+        threading.Thread(target=http_server, args=serv_args).start()
 
         # wait for port to be assigned to server
         n = 1000
@@ -296,6 +299,9 @@ class HTTPTestCase(unittest.TestCase):
         # wait on the server thread to terminate
         self.evt.wait()
 
+        # disable traceback reporting
+        SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = False
+
     def test_simple1(self):
         p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
         self.assertEqual(p.pow(6,8), 6**8)
@@ -331,6 +337,82 @@ class HTTPTestCase(unittest.TestCase):
         self.assertEqual(div_result, 127//42)
 
 
+# This is a contrived way to make a failure occur on the server side
+# in order to test the _send_traceback_header flag on the server
+class FailingMessageClass(mimetools.Message):
+    def __getitem__(self, key):
+        key = key.lower()
+        if key == 'content-length':
+            return 'I am broken'
+        return mimetools.Message.__getitem__(self, key)
+
+
+class FailingServerTestCase(unittest.TestCase):
+    def setUp(self):
+        self.evt = threading.Event()
+        # start server thread to handle requests
+        serv_args = (self.evt, 2)
+        threading.Thread(target=http_server, args=serv_args).start()
+
+        # wait for port to be assigned to server
+        n = 1000
+        while n > 0 and PORT is None:
+            time.sleep(0.001)
+            n -= 1
+
+        time.sleep(0.5)
+
+    def tearDown(self):
+        # wait on the server thread to terminate
+        self.evt.wait()
+        # reset flag
+        SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = False
+        # reset message class
+        SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.MessageClass = mimetools.Message
+
+    def test_basic(self):
+        # check that flag is false by default
+        flagval = SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header
+        self.assertEqual(flagval, False)
+
+        # test a call that won't fail just as a smoke test
+        p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
+        self.assertEqual(p.pow(6,8), 6**8)
+
+    def test_fail_no_info(self):
+        # use the broken message class
+        SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.MessageClass = FailingMessageClass
+
+        try:
+            p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
+            p.pow(6,8)
+        except xmlrpclib.ProtocolError as e:
+            # The two server-side error headers shouldn't be sent back in this case
+            self.assertTrue(e.headers.get("X-exception") is None)
+            self.assertTrue(e.headers.get("X-traceback") is None)
+        else:
+            self.fail('ProtocolError not raised')
+
+    def test_fail_with_info(self):
+        # use the broken message class
+        SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.MessageClass = FailingMessageClass
+
+        # Check that errors in the server send back exception/traceback
+        # info when flag is set
+        SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = True
+
+        try:
+            p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
+            p.pow(6,8)
+        except xmlrpclib.ProtocolError as e:
+            # We should get error info in the response
+            expected_err = "invalid literal for int() with base 10: 'I am broken'"
+            self.assertEqual(e.headers.get("x-exception"), expected_err)
+            self.assertTrue(e.headers.get("x-traceback") is not None)
+        else:
+            self.fail('ProtocolError not raised')
+
+
 def test_main():
     xmlrpc_tests = [XMLRPCTestCase, HelperTestCase, DateTimeTestCase,
          BinaryTestCase, FaultTestCase]
@@ -340,7 +422,8 @@ def test_main():
     # run on Windows. This only happens on the first test to run, but it
     # fails every time and so these tests are skipped on win32 platforms.
     if sys.platform != 'win32':
-        xmlrpc_tests.append(HTTPTestCase)
+        xmlrpc_tests.append(SimpleServerTestCase)
+        xmlrpc_tests.append(FailingServerTestCase)
 
     test_support.run_unittest(*xmlrpc_tests)
 
index cae2f77c8ea58dc1e4c2481505c2476469b994b4..4ba7252f1227462531f7b3f0a674f39b5d4183b8 100644 (file)
@@ -445,6 +445,26 @@ class Thread(_Verbose):
             self.__target(*self.__args, **self.__kwargs)
 
     def __bootstrap(self):
+        # Wrapper around the real bootstrap code that ignores
+        # exceptions during interpreter cleanup.  Those typically
+        # happen when a daemon thread wakes up at an unfortunate
+        # moment, finds the world around it destroyed, and raises some
+        # random exception *** while trying to report the exception in
+        # __bootstrap_inner() below ***.  Those random exceptions
+        # don't help anybody, and they confuse users, so we suppress
+        # them.  We suppress them only when it appears that the world
+        # indeed has already been destroyed, so that exceptions in
+        # __bootstrap_inner() during normal business hours are properly
+        # reported.  Also, we only suppress them for daemonic threads;
+        # if a non-daemonic encounters this, something else is wrong.
+        try:
+            self.__bootstrap_inner()
+        except:
+            if self.__daemonic and _sys is None:
+                return
+            raise
+
+    def __bootstrap_inner(self):
         try:
             self.__started = True
             _active_limbo_lock.acquire()
index 2a95bbe9ba80cecf81dced109b4287822aab28ca..161967e91243de303ed669ec45e35f49d363186d 100644 (file)
  * EUC-KR codec
  */
 
+#define EUCKR_JAMO_FIRSTBYTE   0xA4
+#define EUCKR_JAMO_FILLER      0xD4
+
+static const unsigned char u2cgk_choseong[19] = {
+       0xa1, 0xa2, 0xa4, 0xa7, 0xa8, 0xa9, 0xb1, 0xb2,
+       0xb3, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb,
+       0xbc, 0xbd, 0xbe
+};
+static const unsigned char u2cgk_jungseong[21] = {
+       0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6,
+       0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce,
+       0xcf, 0xd0, 0xd1, 0xd2, 0xd3
+};
+static const unsigned char u2cgk_jongseong[28] = {
+       0xd4, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+       0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0,
+       0xb1, 0xb2, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xba,
+       0xbb, 0xbc, 0xbd, 0xbe
+};
+
 ENCODER(euc_kr)
 {
        while (inleft > 0) {
@@ -28,17 +48,57 @@ ENCODER(euc_kr)
                TRYMAP_ENC(cp949, code, c);
                else return 1;
 
-               if (code & 0x8000) /* MSB set: CP949 */
-                       return 1;
+               if ((code & 0x8000) == 0) {
+                       /* KS X 1001 coded character */
+                       OUT1((code >> 8) | 0x80)
+                       OUT2((code & 0xFF) | 0x80)
+                       NEXT(1, 2)
+               }
+               else {  /* Mapping is found in CP949 extension,
+                        * but we encode it in KS X 1001:1998 Annex 3,
+                        * make-up sequence for EUC-KR. */
 
-               OUT1((code >> 8) | 0x80)
-               OUT2((code & 0xFF) | 0x80)
-               NEXT(1, 2)
+                       REQUIRE_OUTBUF(8)
+
+                       /* syllable composition precedence */
+                       OUT1(EUCKR_JAMO_FIRSTBYTE)
+                       OUT2(EUCKR_JAMO_FILLER)
+
+                       /* All codepoints in CP949 extension are in unicode
+                        * Hangul Syllable area. */
+                       assert(0xac00 <= c && c <= 0xd7a3);
+                       c -= 0xac00;
+
+                       OUT3(EUCKR_JAMO_FIRSTBYTE)
+                       OUT4(u2cgk_choseong[c / 588])
+                       NEXT_OUT(4)
+
+                       OUT1(EUCKR_JAMO_FIRSTBYTE)
+                       OUT2(u2cgk_jungseong[(c / 28) % 21])
+                       OUT3(EUCKR_JAMO_FIRSTBYTE)
+                       OUT4(u2cgk_jongseong[c % 28])
+                       NEXT(1, 4)
+               }
        }
 
        return 0;
 }
 
+#define NONE   127
+
+static const unsigned char cgk2u_choseong[] = { /* [A1, BE] */
+          0,    1, NONE,    2, NONE, NONE,    3,    4,
+          5, NONE, NONE, NONE, NONE, NONE, NONE, NONE,
+          6,    7,    8, NONE,    9,   10,   11,   12,
+         13,   14,   15,   16,   17,   18
+};
+static const unsigned char cgk2u_jongseong[] = { /* [A1, BE] */
+          1,    2,    3,    4,    5,    6,    7, NONE,
+          8,    9,   10,   11,   12,   13,   14,   15,
+         16,   17, NONE,   18,   19,   20,   21,   22,
+       NONE,   23,   24,   25,   26,   27
+};
+
 DECODER(euc_kr)
 {
        while (inleft > 0) {
@@ -54,13 +114,50 @@ DECODER(euc_kr)
 
                REQUIRE_INBUF(2)
 
-               TRYMAP_DEC(ksx1001, **outbuf, c ^ 0x80, IN2 ^ 0x80) {
+               if (c == EUCKR_JAMO_FIRSTBYTE &&
+                   IN2 == EUCKR_JAMO_FILLER) {
+                       /* KS X 1001:1998 Annex 3 make-up sequence */
+                       DBCHAR cho, jung, jong;
+
+                       REQUIRE_INBUF(8)
+                       if ((*inbuf)[2] != EUCKR_JAMO_FIRSTBYTE ||
+                           (*inbuf)[4] != EUCKR_JAMO_FIRSTBYTE ||
+                           (*inbuf)[6] != EUCKR_JAMO_FIRSTBYTE)
+                               return 8;
+
+                       c = (*inbuf)[3];
+                       if (0xa1 <= c && c <= 0xbe)
+                               cho = cgk2u_choseong[c - 0xa1];
+                       else
+                               cho = NONE;
+
+                       c = (*inbuf)[5];
+                       jung = (0xbf <= c && c <= 0xd3) ? c - 0xbf : NONE;
+
+                       c = (*inbuf)[7];
+                       if (c == EUCKR_JAMO_FILLER)
+                               jong = 0;
+                       else if (0xa1 <= c && c <= 0xbe)
+                               jong = cgk2u_jongseong[c - 0xa1];
+                       else
+                               jong = NONE;
+
+                       if (cho == NONE || jung == NONE || jong == NONE)
+                               return 8;
+
+                       OUT1(0xac00 + cho*588 + jung*28 + jong);
+                       NEXT(8, 1)
+               }
+               else TRYMAP_DEC(ksx1001, **outbuf, c ^ 0x80, IN2 ^ 0x80) {
                        NEXT(2, 1)
-               } else return 2;
+               }
+               else
+                       return 2;
        }
 
        return 0;
 }
+#undef NONE
 
 
 /*