| # This script is called by test_xpickle as a subprocess to load and dump | |
| # pickles in a different Python version. | |
| import os | |
| import pickle | |
| import struct | |
| import sys | |
| # This allows the xpickle worker to import picklecommon.py, which it needs | |
| # since some of the pickle objects hold references to picklecommon.py. | |
| test_mod_path = os.path.abspath(os.path.join(os.path.dirname(__file__), | |
| 'picklecommon.py')) | |
| if sys.version_info >= (3, 5): | |
| import importlib.util | |
| spec = importlib.util.spec_from_file_location('test.picklecommon', test_mod_path) | |
| sys.modules['test'] = type(sys)('test') | |
| test_module = importlib.util.module_from_spec(spec) | |
| spec.loader.exec_module(test_module) | |
| sys.modules['test.picklecommon'] = test_module | |
| else: | |
| test_module = type(sys)('test.picklecommon') | |
| sys.modules['test.picklecommon'] = test_module | |
| sys.modules['test'] = type(sys)('test') | |
| with open(test_mod_path, 'rb') as f: | |
| sources = f.read() | |
| exec(sources, vars(test_module)) | |
| def read_exact(f, n): | |
| buf = b'' | |
| while len(buf) < n: | |
| chunk = f.read(n - len(buf)) | |
| if not chunk: | |
| raise EOFError | |
| buf += chunk | |
| return buf | |
| in_stream = getattr(sys.stdin, 'buffer', sys.stdin) | |
| out_stream = getattr(sys.stdout, 'buffer', sys.stdout) | |
| try: | |
| while True: | |
| size, = struct.unpack('!i', read_exact(in_stream, 4)) | |
| if not size: | |
| break | |
| data = read_exact(in_stream, size) | |
| protocol, = struct.unpack('!i', data[:4]) | |
| obj = pickle.loads(data[4:]) | |
| data = pickle.dumps(obj, protocol) | |
| out_stream.write(struct.pack('!i', len(data)) + data) | |
| out_stream.flush() | |
| except Exception as exc: | |
| # dump the exception to stdout and write to stderr, then exit | |
| try: | |
| data = pickle.dumps(exc) | |
| out_stream.write(struct.pack('!i', -len(data)) + data) | |
| out_stream.flush() | |
| except Exception: | |
| out_stream.write(struct.pack('!i', 0)) | |
| out_stream.flush() | |
| sys.stderr.write(repr(exc)) | |
| sys.stderr.flush() | |
| sys.exit(1) |