]> granicus.if.org Git - python/commitdiff
Issue #18473: Fixed 2to3 and 3to2 compatible pickle mappings.
authorSerhiy Storchaka <storchaka@gmail.com>
Tue, 31 Mar 2015 10:17:10 +0000 (13:17 +0300)
committerSerhiy Storchaka <storchaka@gmail.com>
Tue, 31 Mar 2015 10:17:10 +0000 (13:17 +0300)
Fixed ambigious reverse mappings.  Added many new mappings.  Import mapping
is no longer applied to modules already mapped with full name mapping.

Added tests for compatible pickling and unpickling and for consistency of
_compat_pickle mappings.

1  2 
Lib/test/pickletester.py
Misc/NEWS
Modules/_pickle.c

index f8372e32e6117860a08d52c0f63c0739ea909e21,2c496d09592aac7ec70f90bcc01ae038835b5668..c95fb22ee3a27007cf70ac9f1db4506419f3f9bb
@@@ -1691,27 -1647,51 +1693,72 @@@ class AbstractPickleTests(unittest.Test
                      unpickled = self.loads(self.dumps(method, proto))
                      self.assertEqual(method(*args), unpickled(*args))
  
+     def test_compat_pickle(self):
+         tests = [
+             (range(1, 7), '__builtin__', 'xrange'),
+             (map(int, '123'), 'itertools', 'imap'),
+             (functools.reduce, '__builtin__', 'reduce'),
+             (dbm.whichdb, 'whichdb', 'whichdb'),
+             (Exception(), 'exceptions', 'Exception'),
+             (collections.UserDict(), 'UserDict', 'IterableUserDict'),
+             (collections.UserList(), 'UserList', 'UserList'),
+             (collections.defaultdict(), 'collections', 'defaultdict'),
+         ]
+         for val, mod, name in tests:
+             for proto in range(3):
+                 with self.subTest(type=type(val), proto=proto):
+                     pickled = self.dumps(val, proto)
+                     self.assertIn(('c%s\n%s' % (mod, name)).encode(), pickled)
+                     self.assertIs(type(self.loads(pickled)), type(val))
+     def test_compat_unpickle(self):
+         # xrange(1, 7)
+         pickled = b'\x80\x02c__builtin__\nxrange\nK\x01K\x07K\x01\x87R.'
+         unpickled = self.loads(pickled)
+         self.assertIs(type(unpickled), range)
+         self.assertEqual(unpickled, range(1, 7))
+         self.assertEqual(list(unpickled), [1, 2, 3, 4, 5, 6])
+         # reduce
+         pickled = b'\x80\x02c__builtin__\nreduce\n.'
+         self.assertIs(self.loads(pickled), functools.reduce)
+         # whichdb.whichdb
+         pickled = b'\x80\x02cwhichdb\nwhichdb\n.'
+         self.assertIs(self.loads(pickled), dbm.whichdb)
+         # Exception(), StandardError()
+         for name in (b'Exception', b'StandardError'):
+             pickled = (b'\x80\x02cexceptions\n' + name + b'\nU\x03ugh\x85R.')
+             unpickled = self.loads(pickled)
+             self.assertIs(type(unpickled), Exception)
+             self.assertEqual(str(unpickled), 'ugh')
+         # UserDict.UserDict({1: 2}), UserDict.IterableUserDict({1: 2})
+         for name in (b'UserDict', b'IterableUserDict'):
+             pickled = (b'\x80\x02(cUserDict\n' + name +
+                        b'\no}U\x04data}K\x01K\x02ssb.')
+             unpickled = self.loads(pickled)
+             self.assertIs(type(unpickled), collections.UserDict)
+             self.assertEqual(unpickled, collections.UserDict({1: 2}))
 +    def test_local_lookup_error(self):
 +        # Test that whichmodule() errors out cleanly when looking up
 +        # an assumed globally-reachable object fails.
 +        def f():
 +            pass
 +        # Since the function is local, lookup will fail
 +        for proto in range(0, pickle.HIGHEST_PROTOCOL + 1):
 +            with self.assertRaises((AttributeError, pickle.PicklingError)):
 +                pickletools.dis(self.dumps(f, proto))
 +        # Same without a __module__ attribute (exercises a different path
 +        # in _pickle.c).
 +        del f.__module__
 +        for proto in range(0, pickle.HIGHEST_PROTOCOL + 1):
 +            with self.assertRaises((AttributeError, pickle.PicklingError)):
 +                pickletools.dis(self.dumps(f, proto))
 +        # Yet a different path.
 +        f.__name__ = f.__qualname__
 +        for proto in range(0, pickle.HIGHEST_PROTOCOL + 1):
 +            with self.assertRaises((AttributeError, pickle.PicklingError)):
 +                pickletools.dis(self.dumps(f, proto))
 +
  
  class BigmemPickleTests(unittest.TestCase):
  
diff --cc Misc/NEWS
index b24ffb5120557ab74a22053e0df68fb9cc11755c,cd72813dad3fc2396ae7e826f0d82d6d1f61e502..5fb96f714177afdc0f014aa9be04b4368bfbea7b
+++ b/Misc/NEWS
@@@ -2,40 -2,10 +2,44 @@@
  Python News
  +++++++++++
  
 -What's New in Python 3.4.4rc1?
 -==============================
 +What's New in Python 3.5.0 alpha 4?
 +===================================
 +
 +Release date: XXX
 +
 +Core and Builtins
 +-----------------
 +
 +Library
 +-------
 +
++- Issue #18473: Fixed 2to3 and 3to2 compatible pickle mappings.  Fixed
++  ambigious reverse mappings.  Added many new mappings.  Import mapping is no
++  longer applied to modules already mapped with full name mapping.
++
 +- Issue #23485: select.select() is now retried automatically with the
 +  recomputed timeout when interrupted by a signal, except if the signal handler
 +  raises an exception. This change is part of the PEP 475.
 +
 +- Issue #23752: When built from an existing file descriptor, io.FileIO() now
 +  only calls fstat() once. Before fstat() was called twice, which was not
 +  necessary.
 +
 +Build
 +-----
 +
 +Tests
 +-----
 +
 +Tools/Demos
 +-----------
 +
  
 -Release date: tba
 +
 +What's New in Python 3.5.0 alpha 3?
 +===================================
 +
 +Release date: 2015-03-28
  
  Core and Builtins
  -----------------
Simple merge