Skip to content

Commit cb0ffba

Browse files
committed
Clarify python2/3 pickle issues.
1 parent 1ee89a1 commit cb0ffba

File tree

1 file changed

+70
-17
lines changed

1 file changed

+70
-17
lines changed

doc/python3.rst

Lines changed: 70 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -48,17 +48,16 @@ to :class:`~bson.binary.Binary`::
4848
{u'binary': Binary('this is a byte string', 0), u'_id': ObjectId('4f9086b1fba5222021000000')}
4949

5050

51-
Are there any issues migrating from Python 2 to Python 3?
52-
---------------------------------------------------------
51+
Why can't I share pickled ObjectIds between some versions of Python 2 and 3?
52+
----------------------------------------------------------------------------
5353

54-
There are some issues sharing pickled instances of
55-
:class:`~bson.objectid.ObjectId` between Python versions.
56-
:class:`~bson.objectid.ObjectId` instances are implemented
57-
internally as packed binary data (:class:`str` in Python 2,
58-
:class:`bytes` in Python 3).
54+
Instances of :class:`bytes` pickled in Python 3 versions older than 3.2.3
55+
can not be unpickled properly in Python 2. :class:`~bson.objectid.ObjectId`
56+
instances are implemented internally as packed binary data (:class:`str` in
57+
Python 2, :class:`bytes` in Python 3).
5958

6059
Changes have been made to allow unpickling in Python 3 of instances
61-
pickled in Python 2. You just have to use the encoding parameter
60+
pickled in Python 2. You just have to use the ``encoding`` parameter
6261
to pickle.loads::
6362

6463
Python 2.7.3 (default, Apr 12 2012, 10:35:17)
@@ -70,24 +69,78 @@ to pickle.loads::
7069
>>> oid
7170
ObjectId('4f919ba2fba5225b84000000')
7271
>>> pickle.dumps(oid)
73-
'ccopy_reg\n_reconstructor\np0\n(cbson.objectid\nObjectId\np1\nc__builtin__\nobject\np2\nNtp3\nRp4\nS\'O\\x91\\x9b\\xa2\\xfb\\xa5"[\\x84\\x00\\x00\\x00\'\np5\nb.'
72+
'ccopy_reg\n_reconstructor\np0\n(cbson.objectid\...'
7473

7574
Python 3.1.4 (default, Mar 21 2012, 14:34:01)
7675
[GCC 4.5.3] on linux2
7776
Type "help", "copyright", "credits" or "license" for more information.
7877
>>> import pickle
79-
>>> pickle.loads(b'ccopy_reg\n_reconstructor\np0\n(cbson.objectid\nObjectId\np1\nc__builtin__\nobject\np2\nNtp3\nRp4\nS\'O\\x91\\x9b\\xa2\\xfb\\xa5"[\\x84\\x00\\x00\\x00\'\np5\nb.', encoding='latin-1')
78+
>>> pickle.loads(b'ccopy_reg\n_reconstructor\np0\n(cbson.objectid\...', encoding='latin-1')
8079
ObjectId('4f919ba2fba5225b84000000')
8180

82-
Unfortunately there isn't currently a way to unpickle in Python 2
83-
instances of ObjectId pickled in Python 3. Python 2.4 and 2.5 will
84-
raise exceptions. Python 2.6 and 2.7 will decode the ObjectId to
85-
a garbage value. See the following links for an explanation and
86-
possible future work-arounds:
8781

88-
http://bugs.python.org/issue6784
82+
If you pickled the ObjectId using Python 3.2.3 or newer you can unpickle the
83+
instance in Python 2. You just have to use ``protocol <= 2``::
8984

90-
http://mail.python.org/pipermail/python-dev/2012-March/117536.html
85+
Python 3.2.3 (v3.2.3:3d0686d90f55, Apr 10 2012, 11:25:50)
86+
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
87+
Type "help", "copyright", "credits" or "license" for more information.
88+
>>> import pickle
89+
>>> from bson.objectid import ObjectId
90+
>>> oid = ObjectId()
91+
>>> oid
92+
ObjectId('4f96f20c430ee6bd06000000')
93+
>>> pickle.dumps(oid, protocol=2)
94+
b'\x80\x02cbson.objectid\nObjectId\nq\x00)\x81q\x01c_codecs\nencode\...'
95+
96+
Python 2.4.4 (#1, Oct 18 2006, 10:34:39)
97+
[GCC 4.0.1 (Apple Computer, Inc. build 5341)] on darwin
98+
Type "help", "copyright", "credits" or "license" for more information.
99+
>>> import pickle
100+
>>> pickle.loads('\x80\x02cbson.objectid\nObjectId\nq\x00)\x81q\x01c_codecs\nencode\...')
101+
ObjectId('4f96f20c430ee6bd06000000')
102+
103+
104+
Unfortunately this won't work if you pickled the ObjectId in a Python 3 version
105+
older than 3.2.3::
106+
107+
Python 3.2.2 (default, Mar 21 2012, 14:32:23)
108+
[GCC 4.5.3] on linux2
109+
Type "help", "copyright", "credits" or "license" for more information.
110+
>>> import pickle
111+
>>> from bson.objectid import ObjectId
112+
>>> oid = ObjectId()
113+
>>> pickle.dumps(oid, protocol=2)
114+
b'\x80\x02cbson.objectid\nObjectId\nq\x00)\x81q\x01c__builtin__\nbytes\...'
115+
116+
Python 2.4.6 (#1, Apr 12 2012, 14:48:24)
117+
[GCC 4.5.3] on linux3
118+
Type "help", "copyright", "credits" or "license" for more information.
119+
>>> import pickle
120+
>>> pickle.loads('\x80\x02cbson.objectid\nObjectId\nq\x00)\x81q\x01c__builtin__\nbytes\...')
121+
Traceback (most recent call last):
122+
File "<stdin>", line 1, in ?
123+
File "/usr/lib/python2.4/pickle.py", line 1394, in loads
124+
return Unpickler(file).load()
125+
File "/usr/lib/python2.4/pickle.py", line 872, in load
126+
dispatch[key](self)
127+
File "/usr/lib/python2.4/pickle.py", line 1104, in load_global
128+
klass = self.find_class(module, name)
129+
File "/usr/lib/python2.4/pickle.py", line 1140, in find_class
130+
klass = getattr(mod, name)
131+
AttributeError: 'module' object has no attribute 'bytes'
132+
133+
.. warning::
134+
135+
Unpickling in Python 2.6 or 2.7 an ObjectId pickled in a Python 3 version
136+
older than 3.2.3 will seem to succeed but the resulting ObjectId instance
137+
will contain garbage data.
138+
139+
>>> pickle.loads('\x80\x02cbson.objectid\nObjectId\nq\x00)\x81q\x01c__builtin__\nbytes\...)
140+
ObjectId('5b37392c203135302c203234362c2034352c203235312c203136352c2033342c203532...')
141+
142+
See `http://bugs.python.org/issue13505 <http://bugs.python.org/issue13505>`_
143+
for more information about this issue.
91144

92145

93146
Why do I get a syntax error importing pymongo after installing from source?

0 commit comments

Comments
 (0)