]> granicus.if.org Git - python/commitdiff
Fix issue #19834: Support unpickling of exceptions pickled by Python 2.
authorWalter Doerwald <walter@livinglogic.de>
Mon, 2 Dec 2013 10:41:01 +0000 (11:41 +0100)
committerWalter Doerwald <walter@livinglogic.de>
Mon, 2 Dec 2013 10:41:01 +0000 (11:41 +0100)
Lib/_compat_pickle.py
Lib/test/pickletester.py

index 700c80cd57447a740f0e4cef797d08e4187c52bf..978c01e8ef4fed75b2940ccac8858b73f8c8f184 100644 (file)
@@ -76,6 +76,62 @@ NAME_MAPPING = {
     ('itertools', 'ifilterfalse'): ('itertools', 'filterfalse'),
 }
 
+PYTHON2_EXCEPTIONS = (
+    "ArithmeticError",
+    "AssertionError",
+    "AttributeError",
+    "BaseException",
+    "BufferError",
+    "BytesWarning",
+    "DeprecationWarning",
+    "EOFError",
+    "EnvironmentError",
+    "Exception",
+    "FloatingPointError",
+    "FutureWarning",
+    "GeneratorExit",
+    "IOError",
+    "ImportError",
+    "ImportWarning",
+    "IndentationError",
+    "IndexError",
+    "KeyError",
+    "KeyboardInterrupt",
+    "LookupError",
+    "MemoryError",
+    "NameError",
+    "NotImplementedError",
+    "OSError",
+    "OverflowError",
+    "PendingDeprecationWarning",
+    "ReferenceError",
+    "RuntimeError",
+    "RuntimeWarning",
+    # StandardError is gone in Python 3, so we map it to Exception
+    "StopIteration",
+    "SyntaxError",
+    "SyntaxWarning",
+    "SystemError",
+    "SystemExit",
+    "TabError",
+    "TypeError",
+    "UnboundLocalError",
+    "UnicodeDecodeError",
+    "UnicodeEncodeError",
+    "UnicodeError",
+    "UnicodeTranslateError",
+    "UnicodeWarning",
+    "UserWarning",
+    "ValueError",
+    "Warning",
+    "ZeroDivisionError",
+)
+
+for excname in PYTHON2_EXCEPTIONS:
+    NAME_MAPPING[("exceptions", excname)] = ("builtins", excname)
+
+NAME_MAPPING[("exceptions", "StandardError")] = ("builtins", "Exception")
+
 # Same, but for 3.x to 2.x
 REVERSE_IMPORT_MAPPING = dict((v, k) for (k, v) in IMPORT_MAPPING.items())
 REVERSE_NAME_MAPPING = dict((v, k) for (k, v) in NAME_MAPPING.items())
index 86d668ef6f012de02c053d0a9cdb98b2fd8e78ae..5ce46ddf49ecd3f22958ce4f8c6bd6ae626cf7e8 100644 (file)
@@ -407,6 +407,71 @@ DATA5 = (b'\x80\x02cCookie\nSimpleCookie\nq\x00)\x81q\x01U\x03key'
 # set([3]) pickled from 2.x with protocol 2
 DATA6 = b'\x80\x02c__builtin__\nset\nq\x00]q\x01K\x03a\x85q\x02Rq\x03.'
 
+python2_exceptions_without_args = (
+    ArithmeticError,
+    AssertionError,
+    AttributeError,
+    BaseException,
+    BufferError,
+    BytesWarning,
+    DeprecationWarning,
+    EOFError,
+    EnvironmentError,
+    Exception,
+    FloatingPointError,
+    FutureWarning,
+    GeneratorExit,
+    IOError,
+    ImportError,
+    ImportWarning,
+    IndentationError,
+    IndexError,
+    KeyError,
+    KeyboardInterrupt,
+    LookupError,
+    MemoryError,
+    NameError,
+    NotImplementedError,
+    OSError,
+    OverflowError,
+    PendingDeprecationWarning,
+    ReferenceError,
+    RuntimeError,
+    RuntimeWarning,
+    # StandardError is gone in Python 3, we map it to Exception
+    StopIteration,
+    SyntaxError,
+    SyntaxWarning,
+    SystemError,
+    SystemExit,
+    TabError,
+    TypeError,
+    UnboundLocalError,
+    UnicodeError,
+    UnicodeWarning,
+    UserWarning,
+    ValueError,
+    Warning,
+    ZeroDivisionError,
+)
+
+exception_pickle = b'\x80\x02cexceptions\n?\nq\x00)Rq\x01.'
+
+# Exception objects without arguments pickled from 2.x with protocol 2
+DATA7 = {
+    exception :
+    exception_pickle.replace(b'?', exception.__name__.encode("ascii"))
+    for exception in python2_exceptions_without_args
+}
+
+# StandardError is mapped to Exception, test that separately
+DATA8 = exception_pickle.replace(b'?', b'StandardError')
+
+# UnicodeEncodeError object pickled from 2.x with protocol 2
+DATA9 = (b'\x80\x02cexceptions\nUnicodeEncodeError\n'
+         b'q\x00(U\x05asciiq\x01X\x03\x00\x00\x00fooq\x02K\x00K\x01'
+         b'U\x03badq\x03tq\x04Rq\x05.')
+
 
 def create_data():
     c = C()
@@ -1160,6 +1225,21 @@ class AbstractPickleTests(unittest.TestCase):
         self.assertEqual(list(loaded.keys()), ["key"])
         self.assertEqual(loaded["key"].value, "Set-Cookie: key=value")
 
+        for (exc, data) in DATA7.items():
+            loaded = self.loads(data)
+            self.assertIs(type(loaded), exc)
+
+        loaded = self.loads(DATA8)
+        self.assertIs(type(loaded), Exception)
+
+        loaded = self.loads(DATA9)
+        self.assertIs(type(loaded), UnicodeEncodeError)
+        self.assertEqual(loaded.object, "foo")
+        self.assertEqual(loaded.encoding, "ascii")
+        self.assertEqual(loaded.start, 0)
+        self.assertEqual(loaded.end, 1)
+        self.assertEqual(loaded.reason, "bad")
+
     def test_pickle_to_2x(self):
         # Pickle non-trivial data with protocol 2, expecting that it yields
         # the same result as Python 2.x did.