1 # test_pickle dumps and loads pickles via pickle.py.
2 # test_cpickle does the same, but via the cPickle module.
3 # This test covers the other two cases, making pickles with one module and
4 # loading them via the other. It also tests backwards compatibility with
5 # previous version of Python by bouncing pickled objects through Python 2.4
6 # and Python 2.5 running this file.
17 from test
import test_support
19 # Most distro-supplied Pythons don't include the tests
20 # or test support files, and some don't include a way to get these back even if
21 # you're will to install extra packages (like Ubuntu). Doing things like this
22 # "provides" a pickletester module for older versions of Python that may be
23 # installed without it. Note that one other design for this involves messing
24 # with sys.path, which is less precise.
25 mod_path
= os
.path
.abspath(os
.path
.join(os
.path
.dirname(__file__
),
27 pickletester
= types
.ModuleType("test.pickletester")
28 exec compile(open(mod_path
).read(), mod_path
, 'exec') in pickletester
.__dict
__
29 AbstractPickleTests
= pickletester
.AbstractPickleTests
30 if pickletester
.__name
__ in sys
.modules
:
31 raise RuntimeError("Did not expect to find test.pickletester loaded")
32 sys
.modules
[pickletester
.__name
__] = pickletester
35 class DumpCPickle_LoadPickle(AbstractPickleTests
):
39 def dumps(self
, arg
, proto
=0, fast
=False):
41 return cPickle
.dumps(arg
, proto
)
45 return pickle
.loads(buf
)
47 class DumpPickle_LoadCPickle(AbstractPickleTests
):
49 error
= cPickle
.BadPickleGet
51 def dumps(self
, arg
, proto
=0, fast
=False):
53 return pickle
.dumps(arg
, proto
)
57 return cPickle
.loads(buf
)
59 def have_python_version(name
):
60 """Check whether the given name is a valid Python binary.
62 This respects your PATH.
65 name: short string name of a Python binary such as "python2.4".
68 True if the name is valid, False otherwise.
70 return os
.system(name
+ " -c 'import sys; sys.exit()'") == 0
73 class AbstractCompatTests(AbstractPickleTests
):
80 self
.assertTrue(self
.python
)
81 self
.assertTrue(self
.module
)
82 self
.assertTrue(self
.error
)
84 def send_to_worker(self
, python
, obj
, proto
):
85 """Bounce a pickled object through another version of Python.
87 This will pickle the object, send it to a child process where it will be
88 unpickled, then repickled and sent back to the parent process.
91 python: the name of the Python binary to start.
92 obj: object to pickle.
93 proto: pickle protocol number to use.
96 The pickled data received from the child process.
98 # Prevent the subprocess from picking up invalid .pyc files.
100 if target
[-1] in ("c", "o"):
103 data
= self
.module
.dumps((proto
, obj
), proto
)
104 worker
= subprocess
.Popen([python
, target
, "worker"],
105 stdin
=subprocess
.PIPE
,
106 stdout
=subprocess
.PIPE
,
107 stderr
=subprocess
.PIPE
)
108 stdout
, stderr
= worker
.communicate(data
)
109 if worker
.returncode
!= 0:
110 raise RuntimeError(stderr
)
113 def dumps(self
, arg
, proto
=0, fast
=False):
114 return self
.send_to_worker(self
.python
, arg
, proto
)
116 def loads(self
, input):
117 return self
.module
.loads(input)
119 # These tests are disabled because they require some special setup
120 # on the worker that's hard to keep in sync.
121 def test_global_ext1(self
):
124 def test_global_ext2(self
):
127 def test_global_ext4(self
):
130 # This is a cut-down version of pickletester's test_float. Backwards
131 # compatibility for the values in for_bin_protos was explicitly broken in
132 # r68903 to fix a bug.
133 def test_float(self
):
134 for_bin_protos
= [4.94e-324, 1e-310]
135 neg_for_bin_protos
= [-x
for x
in for_bin_protos
]
136 test_values
= [0.0, 7e-308, 6.626e-34, 0.1, 0.5,
137 3.14, 263.44582062374053, 6.022e23
, 1e30
]
138 test_proto0_values
= test_values
+ [-x
for x
in test_values
]
139 test_values
= test_proto0_values
+ for_bin_protos
+ neg_for_bin_protos
141 for value
in test_proto0_values
:
142 pickle
= self
.dumps(value
, 0)
143 got
= self
.loads(pickle
)
144 self
.assertEqual(value
, got
)
146 for proto
in pickletester
.protocols
[1:]:
147 for value
in test_values
:
148 pickle
= self
.dumps(value
, proto
)
149 got
= self
.loads(pickle
)
150 self
.assertEqual(value
, got
)
152 # Backwards compatibility was explicitly broken in r67934 to fix a bug.
153 def test_unicode_high_plane(self
):
156 if test_support
.have_unicode
:
157 # This is a cut-down version of pickletester's test_unicode. Backwards
158 # compatibility was explicitly broken in r67934 to fix a bug.
159 def test_unicode(self
):
160 endcases
= [u
'', u
'<\\u>', u
'<\\\u1234>', u
'<\n>', u
'<\\>']
161 for proto
in pickletester
.protocols
:
163 p
= self
.dumps(u
, proto
)
165 self
.assertEqual(u2
, u
)
168 def run_compat_test(python_name
):
169 return (test_support
.is_resource_enabled("xpickle") and
170 have_python_version(python_name
))
173 # Test backwards compatibility with Python 2.4.
174 if not run_compat_test("python2.4"):
175 class CPicklePython24Compat(unittest
.TestCase
):
178 class CPicklePython24Compat(AbstractCompatTests
):
182 error
= cPickle
.BadPickleGet
184 # Disable these tests for Python 2.4. Making them pass would require
185 # nontrivially monkeypatching the pickletester module in the worker.
186 def test_reduce_calls_base(self
):
189 def test_reduce_ex_calls_base(self
):
192 class PicklePython24Compat(CPicklePython24Compat
):
198 # Test backwards compatibility with Python 2.5.
199 if not run_compat_test("python2.5"):
200 class CPicklePython25Compat(unittest
.TestCase
):
203 class CPicklePython25Compat(AbstractCompatTests
):
207 error
= cPickle
.BadPickleGet
209 class PicklePython25Compat(CPicklePython25Compat
):
215 # Test backwards compatibility with Python 2.6.
216 if not run_compat_test("python2.6"):
217 class CPicklePython26Compat(unittest
.TestCase
):
220 class CPicklePython26Compat(AbstractCompatTests
):
224 error
= cPickle
.BadPickleGet
226 class PicklePython26Compat(CPicklePython26Compat
):
232 def worker_main(in_stream
, out_stream
):
233 message
= cPickle
.load(in_stream
)
234 protocol
, obj
= message
235 cPickle
.dump(obj
, out_stream
, protocol
)
239 if not test_support
.is_resource_enabled("xpickle"):
240 print >>sys
.stderr
, "test_xpickle -- skipping backwards compat tests."
241 print >>sys
.stderr
, "Use 'regrtest.py -u xpickle' to run them."
244 test_support
.run_unittest(
245 DumpCPickle_LoadPickle
,
246 DumpPickle_LoadCPickle
,
247 CPicklePython24Compat
,
248 CPicklePython25Compat
,
249 CPicklePython26Compat
,
250 PicklePython24Compat
,
251 PicklePython25Compat
,
252 PicklePython26Compat
,
255 if __name__
== "__main__":
256 if "worker" in sys
.argv
:
257 worker_main(sys
.stdin
, sys
.stdout
)