summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWalter Doerwald <walter@livinglogic.de>2013-12-02 10:41:01 (GMT)
committerWalter Doerwald <walter@livinglogic.de>2013-12-02 10:41:01 (GMT)
commit9d1dbca5e2f6f75577ad4ea29514a4eabc38e913 (patch)
tree211fab21bb2ee5641253dbf0d735251f068073ab
parent708a3182c931ff1b6e8a420f87929d143822de28 (diff)
downloadcpython-9d1dbca5e2f6f75577ad4ea29514a4eabc38e913.zip
cpython-9d1dbca5e2f6f75577ad4ea29514a4eabc38e913.tar.gz
cpython-9d1dbca5e2f6f75577ad4ea29514a4eabc38e913.tar.bz2
Fix issue #19834: Support unpickling of exceptions pickled by Python 2.
-rw-r--r--Lib/_compat_pickle.py56
-rw-r--r--Lib/test/pickletester.py80
2 files changed, 136 insertions, 0 deletions
diff --git a/Lib/_compat_pickle.py b/Lib/_compat_pickle.py
index 700c80c..978c01e 100644
--- a/Lib/_compat_pickle.py
+++ b/Lib/_compat_pickle.py
@@ -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())
diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py
index 86d668e..5ce46dd 100644
--- a/Lib/test/pickletester.py
+++ b/Lib/test/pickletester.py
@@ -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.