diff options
Diffstat (limited to 'lib/python2.7/test/test_xpickle.py')
-rw-r--r-- | lib/python2.7/test/test_xpickle.py | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/lib/python2.7/test/test_xpickle.py b/lib/python2.7/test/test_xpickle.py new file mode 100644 index 0000000..ac3a33f --- /dev/null +++ b/lib/python2.7/test/test_xpickle.py @@ -0,0 +1,264 @@ +# test_pickle dumps and loads pickles via pickle.py. +# test_cpickle does the same, but via the cPickle module. +# This test covers the other two cases, making pickles with one module and +# loading them via the other. It also tests backwards compatibility with +# previous version of Python by bouncing pickled objects through Python 2.4 +# and Python 2.5 running this file. + +import cPickle +import os +import os.path +import pickle +import subprocess +import sys +import types +import unittest + +from test import test_support + +# Most distro-supplied Pythons don't include the tests +# or test support files, and some don't include a way to get these back even if +# you're will to install extra packages (like Ubuntu). Doing things like this +# "provides" a pickletester module for older versions of Python that may be +# installed without it. Note that one other design for this involves messing +# with sys.path, which is less precise. +mod_path = os.path.abspath(os.path.join(os.path.dirname(__file__), + "pickletester.py")) +pickletester = types.ModuleType("test.pickletester") +exec compile(open(mod_path).read(), mod_path, 'exec') in pickletester.__dict__ +AbstractPickleTests = pickletester.AbstractPickleTests +if pickletester.__name__ in sys.modules: + raise RuntimeError("Did not expect to find test.pickletester loaded") +sys.modules[pickletester.__name__] = pickletester + + +class DumpCPickle_LoadPickle(AbstractPickleTests): + + error = KeyError + + def dumps(self, arg, proto=0, fast=False): + # Ignore fast + return cPickle.dumps(arg, proto) + + def loads(self, buf): + # Ignore fast + return pickle.loads(buf) + +class DumpPickle_LoadCPickle(AbstractPickleTests): + + error = cPickle.BadPickleGet + + def dumps(self, arg, proto=0, fast=False): + # Ignore fast + return pickle.dumps(arg, proto) + + def loads(self, buf): + # Ignore fast + return cPickle.loads(buf) + +def have_python_version(name): + """Check whether the given name is a valid Python binary and has + test.test_support. + + This respects your PATH. + + Args: + name: short string name of a Python binary such as "python2.4". + + Returns: + True if the name is valid, False otherwise. + """ + return os.system(name + " -c 'import test.test_support'") == 0 + + +class AbstractCompatTests(AbstractPickleTests): + + module = None + python = None + error = None + + def setUp(self): + self.assertTrue(self.python) + self.assertTrue(self.module) + self.assertTrue(self.error) + + def send_to_worker(self, python, obj, proto): + """Bounce a pickled object through another version of Python. + + This will pickle the object, send it to a child process where it will be + unpickled, then repickled and sent back to the parent process. + + Args: + python: the name of the Python binary to start. + obj: object to pickle. + proto: pickle protocol number to use. + + Returns: + The pickled data received from the child process. + """ + # Prevent the subprocess from picking up invalid .pyc files. + target = __file__ + if target[-1] in ("c", "o"): + target = target[:-1] + + data = self.module.dumps((proto, obj), proto) + worker = subprocess.Popen([python, target, "worker"], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + stdout, stderr = worker.communicate(data) + if worker.returncode != 0: + raise RuntimeError(stderr) + return stdout + + def dumps(self, arg, proto=0, fast=False): + return self.send_to_worker(self.python, arg, proto) + + def loads(self, input): + return self.module.loads(input) + + # These tests are disabled because they require some special setup + # on the worker that's hard to keep in sync. + def test_global_ext1(self): + pass + + def test_global_ext2(self): + pass + + def test_global_ext4(self): + pass + + # This is a cut-down version of pickletester's test_float. Backwards + # compatibility for the values in for_bin_protos was explicitly broken in + # r68903 to fix a bug. + def test_float(self): + for_bin_protos = [4.94e-324, 1e-310] + neg_for_bin_protos = [-x for x in for_bin_protos] + test_values = [0.0, 7e-308, 6.626e-34, 0.1, 0.5, + 3.14, 263.44582062374053, 6.022e23, 1e30] + test_proto0_values = test_values + [-x for x in test_values] + test_values = test_proto0_values + for_bin_protos + neg_for_bin_protos + + for value in test_proto0_values: + pickle = self.dumps(value, 0) + got = self.loads(pickle) + self.assertEqual(value, got) + + for proto in pickletester.protocols[1:]: + for value in test_values: + pickle = self.dumps(value, proto) + got = self.loads(pickle) + self.assertEqual(value, got) + + # Backwards compatibility was explicitly broken in r67934 to fix a bug. + def test_unicode_high_plane(self): + pass + + # This tests a fix that's in 2.7 only + def test_dynamic_class(self): + pass + + if test_support.have_unicode: + # This is a cut-down version of pickletester's test_unicode. Backwards + # compatibility was explicitly broken in r67934 to fix a bug. + def test_unicode(self): + endcases = [u'', u'<\\u>', u'<\\\u1234>', u'<\n>', u'<\\>'] + for proto in pickletester.protocols: + for u in endcases: + p = self.dumps(u, proto) + u2 = self.loads(p) + self.assertEqual(u2, u) + + +def run_compat_test(python_name): + return (test_support.is_resource_enabled("xpickle") and + have_python_version(python_name)) + + +# Test backwards compatibility with Python 2.4. +if not run_compat_test("python2.4"): + class CPicklePython24Compat(unittest.TestCase): + pass +else: + class CPicklePython24Compat(AbstractCompatTests): + + module = cPickle + python = "python2.4" + error = cPickle.BadPickleGet + + # Disable these tests for Python 2.4. Making them pass would require + # nontrivially monkeypatching the pickletester module in the worker. + def test_reduce_calls_base(self): + pass + + def test_reduce_ex_calls_base(self): + pass + +class PicklePython24Compat(CPicklePython24Compat): + + module = pickle + error = KeyError + + +# Test backwards compatibility with Python 2.5. +if not run_compat_test("python2.5"): + class CPicklePython25Compat(unittest.TestCase): + pass +else: + class CPicklePython25Compat(AbstractCompatTests): + + module = cPickle + python = "python2.5" + error = cPickle.BadPickleGet + +class PicklePython25Compat(CPicklePython25Compat): + + module = pickle + error = KeyError + + +# Test backwards compatibility with Python 2.6. +if not run_compat_test("python2.6"): + class CPicklePython26Compat(unittest.TestCase): + pass +else: + class CPicklePython26Compat(AbstractCompatTests): + + module = cPickle + python = "python2.6" + error = cPickle.BadPickleGet + +class PicklePython26Compat(CPicklePython26Compat): + + module = pickle + error = KeyError + + +def worker_main(in_stream, out_stream): + message = cPickle.load(in_stream) + protocol, obj = message + cPickle.dump(obj, out_stream, protocol) + + +def test_main(): + if not test_support.is_resource_enabled("xpickle"): + print >>sys.stderr, "test_xpickle -- skipping backwards compat tests." + print >>sys.stderr, "Use 'regrtest.py -u xpickle' to run them." + sys.stderr.flush() + + test_support.run_unittest( + DumpCPickle_LoadPickle, + DumpPickle_LoadCPickle, + CPicklePython24Compat, + CPicklePython25Compat, + CPicklePython26Compat, + PicklePython24Compat, + PicklePython25Compat, + PicklePython26Compat, + ) + +if __name__ == "__main__": + if "worker" in sys.argv: + worker_main(sys.stdin, sys.stdout) + else: + test_main() |