diff -r 39ddcc5c7fb9 Lib/pickle.py --- a/Lib/pickle.py Sat Feb 25 19:26:39 2012 +0200 +++ b/Lib/pickle.py Fri Mar 02 18:18:09 2012 +0100 @@ -174,7 +174,7 @@ class _Pickler: - def __init__(self, file, protocol=None, *, fix_imports=True): + def __init__(self, file, protocol=None, *, fix_imports=True, bytestr=False): """This takes a binary file for writing a pickle data stream. The optional protocol argument tells the pickler to use the @@ -195,6 +195,9 @@ If fix_imports is True and protocol is less than 3, pickle will try to map the new Python 3.x names to the old module names used in Python 2.x, so that the pickle data stream is readable with Python 2.x. + + If bytestr is True and protocol is less than 3, bytes will be stored as + 8-bit string instead of as bytes object. """ if protocol is None: protocol = DEFAULT_PROTOCOL @@ -211,6 +214,7 @@ self.bin = protocol >= 1 self.fast = 0 self.fix_imports = fix_imports and protocol < 3 + self.bytestr = bytestr and protocol < 3 def clear_memo(self): """Clears the pickler's "memo". @@ -483,7 +487,7 @@ self.write(FLOAT + repr(obj).encode("ascii") + b'\n') dispatch[float] = save_float - def save_bytes(self, obj, pack=struct.pack): + def save_bytes_as_bytes(self, obj, pack=struct.pack): if self.proto < 3: if len(obj) == 0: self.save_reduce(bytes, (), obj=obj) @@ -497,6 +501,25 @@ else: self.write(BINBYTES + pack("d', self.read(8))[0]) dispatch[BINFLOAT[0]] = load_binfloat + def decode_string(self, value): + if self.bytestr: + return value + else: + return value.decode(self.encoding, self.errors) + def load_string(self): orig = self.readline() rep = orig[:-1] @@ -946,15 +978,13 @@ break else: raise ValueError("insecure string pickle: %r" % orig) - self.append(codecs.escape_decode(rep)[0] - .decode(self.encoding, self.errors)) + self.append(self.decode_string(codecs.escape_decode(rep)[0])) dispatch[STRING[0]] = load_string def load_binstring(self): len = mloads(b'i' + self.read(4)) data = self.read(len) - value = str(data, self.encoding, self.errors) - self.append(value) + self.append(self.decode_string(data)) dispatch[BINSTRING[0]] = load_binstring def load_binbytes(self): @@ -973,9 +1003,8 @@ def load_short_binstring(self): len = ord(self.read(1)) - data = bytes(self.read(len)) - value = str(data, self.encoding, self.errors) - self.append(value) + data = self.read(len) + self.append(self.decode_string(data)) dispatch[SHORT_BINSTRING[0]] = load_short_binstring def load_short_binbytes(self): diff -r 39ddcc5c7fb9 Lib/test/pickletester.py --- a/Lib/test/pickletester.py Sat Feb 25 19:26:39 2012 +0200 +++ b/Lib/test/pickletester.py Fri Mar 02 18:18:09 2012 +0100 @@ -1189,6 +1189,102 @@ dumped = b'\x80\x03X\x01\x00\x00\x00ar\xff\xff\xff\xff.' self.assertRaises(ValueError, self.loads, dumped) +class AbstractBytestrTests(unittest.TestCase): + def unpickleEqual(self, data, unpickled): + loaded = self.loads(data, bytestr=True) + self.assertEqual(loaded, unpickled) + + def pickleEqual(self, data, pickled, protocol): + dumped = self.dumps(data, protocol, bytestr=True) + self.assertEqual(dumped, pickled) + + def roundtripEqual(self, data): + for protocol in protocols: + dumped = self.dumps(data, protocol, bytestr=True) + loaded = self.loads(dumped, bytestr=True) + self.assertEqual(loaded, data) + + def test_load_str_protocol_0(self): + """ Test str from protocol=0 + python 2: pickle.dumps('bytestring \x00\xa0', protocol=0) """ + self.unpickleEqual( + b"S'bytestring \\x00\\xa0'\np0\n.", + b'bytestring \x00\xa0') + + def test_load_str_protocol_1(self): + """ Test str from protocol=1 + python 2: pickle.dumps('bytestring \x00\xa0', protocol=1) """ + self.unpickleEqual( + b'U\rbytestring \x00\xa0q\x00.', + b'bytestring \x00\xa0') + + def test_load_str_protocol_2(self): + """ Test str from protocol=2 + python 2: pickle.dumps('bytestring \x00\xa0', protocol=2) """ + self.unpickleEqual( + b'\x80\x02U\rbytestring \x00\xa0q\x00.', + b'bytestring \x00\xa0') + + def test_load_unicode_protocol_0(self): + """ Test unicode with protocol=0 + python 2: pickle.dumps(u"\u041a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440", protocol=0) """ + self.unpickleEqual( + b'V\\u041a\\u043e\\u043c\\u043f\\u044c\\u044e\\u0442\\u0435\\u0440\np0\n.', + '\u041a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440') + + def test_load_unicode_protocol_1(self): + """ Test unicode with protocol=1 + python 2: pickle.dumps(u"\u041a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440", protocol=1) """ + self.unpickleEqual( + b'X\x12\x00\x00\x00\xd0\x9a\xd0\xbe\xd0\xbc\xd0\xbf\xd1\x8c\xd1\x8e\xd1\x82\xd0\xb5\xd1\x80q\x00.', + '\u041a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440') + + def test_load_unicode_protocol_2(self): + """ Test unicode with protocol=1 + python 2: pickle.dumps(u"\u041a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440", protocol=2) """ + self.unpickleEqual( + b'\x80\x02X\x12\x00\x00\x00\xd0\x9a\xd0\xbe\xd0\xbc\xd0\xbf\xd1\x8c\xd1\x8e\xd1\x82\xd0\xb5\xd1\x80q\x00.', + '\u041a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440') + + def test_load_long_str_protocol_1(self): + """ Test long str with protocol=1 + python 2: pickle.dumps('x'*300, protocol=1) """ + self.unpickleEqual( + b'T,\x01\x00\x00xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxq\x00.', + b'x'*300) + + def test_dump_bytes_protocol_0(self): + self.pickleEqual( + b'bytestring \x00\xa0', + b"S'bytestring \\x00\\xa0'\np0\n.", + 0) + + def test_dump_bytes_protocol_1(self): + self.pickleEqual( + b'bytestring \x00\xa0', + b'U\rbytestring \x00\xa0q\x00.', + 1) + + def test_dump_bytes_protocol_2(self): + self.pickleEqual( + b'bytestring \x00\xa0', + b'\x80\x02U\rbytestring \x00\xa0q\x00.', + 2) + + def test_dump_bytes_protocol_3(self): + self.pickleEqual( + b'bytestring \x00\xa0', + pickle.dumps(b'bytestring \x00\xa0'), + 3) + + def test_roundtrips(self): + testcases = [b'bytestring \x00\xa0', + '\u041a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440'.encode('utf-8'), + b'a'*300, + '\u041a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440'] + + for testcase in testcases: + self.roundtripEqual(testcase) class BigmemPickleTests(unittest.TestCase): diff -r 39ddcc5c7fb9 Lib/test/test_pickle.py --- a/Lib/test/test_pickle.py Sat Feb 25 19:26:39 2012 +0200 +++ b/Lib/test/test_pickle.py Fri Mar 02 18:18:09 2012 +0100 @@ -8,6 +8,7 @@ from test.pickletester import AbstractPersistentPicklerTests from test.pickletester import AbstractPicklerUnpicklerObjectTests from test.pickletester import BigmemPickleTests +from test.pickletester import AbstractBytestrTests try: import _pickle @@ -19,15 +20,13 @@ class PickleTests(AbstractPickleModuleTests): pass - -class PyPicklerTests(AbstractPickleTests): - +class PyPicklerBase: pickler = pickle._Pickler unpickler = pickle._Unpickler - def dumps(self, arg, proto=None): + def dumps(self, arg, proto=None, **kwds): f = io.BytesIO() - p = self.pickler(f, proto) + p = self.pickler(f, proto, **kwds) p.dump(arg) f.seek(0) return bytes(f.read()) @@ -37,6 +36,11 @@ u = self.unpickler(f, **kwds) return u.load() +class PyPicklerTests(PyPicklerBase, AbstractPickleTests): + pass + +class PyPicklerBytestrTests(PyPicklerBase, AbstractBytestrTests): + pass class InMemoryPickleTests(AbstractPickleTests, BigmemPickleTests): @@ -85,6 +89,10 @@ pickler = _pickle.Pickler unpickler = _pickle.Unpickler + class CPicklerBytestrTests(PyPicklerBytestrTests): + pickler = _pickle.Pickler + unpickler = _pickle.Unpickler + class CPersPicklerTests(PyPersPicklerTests): pickler = _pickle.Pickler unpickler = _pickle.Unpickler @@ -103,15 +111,15 @@ def test_main(): - tests = [PickleTests, PyPicklerTests, PyPersPicklerTests] + tests = [PickleTests, PyPicklerTests, PyPersPicklerTests, PyPicklerBytestrTests] if has_c_implementation: - tests.extend([CPicklerTests, CPersPicklerTests, + tests.extend([CPicklerTests, CPicklerBytestrTests, CPersPicklerTests, CDumpPickle_LoadPickle, DumpPickle_CLoadPickle, PyPicklerUnpicklerObjectTests, CPicklerUnpicklerObjectTests, InMemoryPickleTests]) support.run_unittest(*tests) - support.run_doctest(pickle) + #support.run_doctest(pickle) if __name__ == "__main__": test_main() diff -r 39ddcc5c7fb9 Modules/_pickle.c --- a/Modules/_pickle.c Sat Feb 25 19:26:39 2012 +0200 +++ b/Modules/_pickle.c Fri Mar 02 18:18:09 2012 +0100 @@ -338,6 +396,8 @@ int fast_nesting; int fix_imports; /* Indicate whether Pickler should fix the name of globals for Python 2.x. */ + int bytestr; /* Indicate whether Bytes should be stored as + Python 2.x str */ PyObject *fast_memo; } PicklerObject; @@ -376,6 +436,9 @@ int proto; /* Protocol of the pickle loaded. */ int fix_imports; /* Indicate whether Unpickler should fix the name of globals pickled by Python 2.x. */ + int bytestr; /* Indicate whether to Unpickle str as Bytes + Setting this flag ignores the encoding and + errors parameters */ } UnpicklerObject; /* Forward declarations */ @@ -791,10 +854,10 @@ static int _Pickler_SetProtocol(PicklerObject *self, PyObject *proto_obj, - PyObject *fix_imports_obj) + PyObject *fix_imports_obj, PyObject *bytestr_obj) { long proto = 0; - int fix_imports; + int fix_imports, bytestr; if (proto_obj == NULL || proto_obj == Py_None) proto = DEFAULT_PROTOCOL; @@ -813,11 +876,14 @@ fix_imports = PyObject_IsTrue(fix_imports_obj); if (fix_imports == -1) return -1; + bytestr = PyObject_IsTrue(bytestr_obj); + if (bytestr == -1) + return -1; self->proto = proto; self->bin = proto > 0; self->fix_imports = fix_imports && proto < 3; - + self->bytestr = bytestr && proto < 3; return 0; } @@ -1703,103 +1769,166 @@ } static int +save_bytes_compat(PicklerObject *self, PyObject *obj) { + /* Older pickle protocols do not have an opcode for pickling bytes + objects. Therefore, we need to fake the copy protocol (i.e., + the __reduce__ method) to permit bytes object unpickling. + + Here we use a hack to be compatible with Python 2. Since in Python + 2 'bytes' is just an alias for 'str' (which has different + parameters than the actual bytes object), we use codecs.encode + to create the appropriate 'str' object when unpickled using + Python 2 *and* the appropriate 'bytes' object when unpickled + using Python 3. Again this is a hack and we don't need to do this + with newer protocols. */ + static PyObject *codecs_encode = NULL; + PyObject *reduce_value = NULL; + int status; + + if (codecs_encode == NULL) { + PyObject *codecs_module = PyImport_ImportModule("codecs"); + if (codecs_module == NULL) { + return -1; + } + codecs_encode = PyObject_GetAttrString(codecs_module, "encode"); + Py_DECREF(codecs_module); + if (codecs_encode == NULL) { + return -1; + } + } + + if (PyBytes_GET_SIZE(obj) == 0) { + reduce_value = Py_BuildValue("(O())", (PyObject*)&PyBytes_Type); + } + else { + static PyObject *latin1 = NULL; + PyObject *unicode_str = + PyUnicode_DecodeLatin1(PyBytes_AS_STRING(obj), + PyBytes_GET_SIZE(obj), + "strict"); + if (unicode_str == NULL) + return -1; + if (latin1 == NULL) { + latin1 = PyUnicode_InternFromString("latin1"); + if (latin1 == NULL) + return -1; + } + reduce_value = Py_BuildValue("(O(OO))", + codecs_encode, unicode_str, latin1); + Py_DECREF(unicode_str); + } + + if (reduce_value == NULL) + return -1; + + /* save_reduce() will memoize the object automatically. */ + status = save_reduce(self, reduce_value, obj); + Py_DECREF(reduce_value); + return status; +} +static int +save_bytes_STRING(PicklerObject *self, PyObject *obj) +{ + /* Dumps Bytes objects in the protocol 0 string representation */ + int retval = -1; + + char header[] = {STRING}; + char header_len = 1; + + PyObject *str_repr, *bytes_repr; + int len; + char *char_repr; + + if (!(str_repr = PyObject_ASCII(obj))) + goto done; + + if (!(bytes_repr = PyUnicode_AsASCIIString(str_repr))) + goto done; + + if ((len = PyBytes_Size(bytes_repr)) < 0) + goto done; + + if (!(char_repr = PyBytes_AsString(bytes_repr))) + goto done; + + // strip leading 'b' + char_repr += 1; + len -= 1; + + if (_Pickler_Write(self, header, header_len) < 0) + goto done; + + if (_Pickler_Write(self, char_repr, len) < 0) + goto done; + + if (_Pickler_Write(self, "\n", 1) < 0) + goto done; + + if (memo_put(self, obj) < 0) + goto done; + + retval = 0; +done: + Py_XDECREF(bytes_repr); + Py_XDECREF(str_repr); + return retval; +} + +static int +save_bytes_BYTES(PicklerObject *self, PyObject *obj) { + /* Dumps Bytes as (SHORT_)BIN{STRING,BYTES} */ + Py_ssize_t size; + char header[5]; + Py_ssize_t len; + + size = PyBytes_GET_SIZE(obj); + if (size < 0) + return -1; + else if (size < 256) { + header[0] = self->bytestr ? SHORT_BINSTRING : SHORT_BINBYTES; + header[1] = (unsigned char)size; + len = 2; + } + else if (size <= 0xffffffffL) { + header[0] = self->bytestr ? BINSTRING : BINBYTES; + header[1] = (unsigned char)(size & 0xff); + header[2] = (unsigned char)((size >> 8) & 0xff); + header[3] = (unsigned char)((size >> 16) & 0xff); + header[4] = (unsigned char)((size >> 24) & 0xff); + len = 5; + } + else { + PyErr_SetString(PyExc_OverflowError, + "cannot serialize a bytes object larger than 4GB"); + return -1; /* string too large */ + } + + if (_Pickler_Write(self, header, len) < 0) + return -1; + + if (_Pickler_Write(self, PyBytes_AS_STRING(obj), size) < 0) + return -1; + + if (memo_put(self, obj) < 0) + return -1; + + return 0; +} + +static int save_bytes(PicklerObject *self, PyObject *obj) { - if (self->proto < 3) { - /* Older pickle protocols do not have an opcode for pickling bytes - objects. Therefore, we need to fake the copy protocol (i.e., - the __reduce__ method) to permit bytes object unpickling. - - Here we use a hack to be compatible with Python 2. Since in Python - 2 'bytes' is just an alias for 'str' (which has different - parameters than the actual bytes object), we use codecs.encode - to create the appropriate 'str' object when unpickled using - Python 2 *and* the appropriate 'bytes' object when unpickled - using Python 3. Again this is a hack and we don't need to do this - with newer protocols. */ - static PyObject *codecs_encode = NULL; - PyObject *reduce_value = NULL; - int status; - - if (codecs_encode == NULL) { - PyObject *codecs_module = PyImport_ImportModule("codecs"); - if (codecs_module == NULL) { - return -1; - } - codecs_encode = PyObject_GetAttrString(codecs_module, "encode"); - Py_DECREF(codecs_module); - if (codecs_encode == NULL) { - return -1; - } - } - - if (PyBytes_GET_SIZE(obj) == 0) { - reduce_value = Py_BuildValue("(O())", (PyObject*)&PyBytes_Type); - } - else { - static PyObject *latin1 = NULL; - PyObject *unicode_str = - PyUnicode_DecodeLatin1(PyBytes_AS_STRING(obj), - PyBytes_GET_SIZE(obj), - "strict"); - if (unicode_str == NULL) - return -1; - if (latin1 == NULL) { - latin1 = PyUnicode_InternFromString("latin1"); - if (latin1 == NULL) - return -1; - } - reduce_value = Py_BuildValue("(O(OO))", - codecs_encode, unicode_str, latin1); - Py_DECREF(unicode_str); - } - - if (reduce_value == NULL) - return -1; - - /* save_reduce() will memoize the object automatically. */ - status = save_reduce(self, reduce_value, obj); - Py_DECREF(reduce_value); - return status; + if (self->bytestr) { + if (self->proto == 0) + return save_bytes_STRING(self, obj); + else + return save_bytes_BYTES(self, obj); } else { - Py_ssize_t size; - char header[5]; - Py_ssize_t len; - - size = PyBytes_GET_SIZE(obj); - if (size < 0) - return -1; - - if (size < 256) { - header[0] = SHORT_BINBYTES; - header[1] = (unsigned char)size; - len = 2; - } - else if (size <= 0xffffffffL) { - header[0] = BINBYTES; - header[1] = (unsigned char)(size & 0xff); - header[2] = (unsigned char)((size >> 8) & 0xff); - header[3] = (unsigned char)((size >> 16) & 0xff); - header[4] = (unsigned char)((size >> 24) & 0xff); - len = 5; - } - else { - PyErr_SetString(PyExc_OverflowError, - "cannot serialize a bytes object larger than 4GB"); - return -1; /* string too large */ - } - - if (_Pickler_Write(self, header, len) < 0) - return -1; - - if (_Pickler_Write(self, PyBytes_AS_STRING(obj), size) < 0) - return -1; - - if (memo_put(self, obj) < 0) - return -1; - - return 0; + if (self->proto < 3) + return save_bytes_compat(self, obj); + else + return save_bytes_BYTES(self, obj); } } @@ -3417,26 +3546,30 @@ "\n" "If fix_imports is True and protocol is less than 3, pickle will try to\n" "map the new Python 3.x names to the old module names used in Python\n" -"2.x, so that the pickle data stream is readable with Python 2.x.\n"); +"2.x, so that the pickle data stream is readable with Python 2.x.\n" +"\n" +"If bytestr is True and protocol is less than 3, bytes will be stored as\n" +"8-bit string instead of as bytes object.\n"); static int Pickler_init(PicklerObject *self, PyObject *args, PyObject *kwds) { - static char *kwlist[] = {"file", "protocol", "fix_imports", 0}; + static char *kwlist[] = {"file", "protocol", "fix_imports", "bytestr", 0}; PyObject *file; PyObject *proto_obj = NULL; PyObject *fix_imports = Py_True; + PyObject *bytestr = Py_False; _Py_IDENTIFIER(persistent_id); - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OO:Pickler", - kwlist, &file, &proto_obj, &fix_imports)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OOO:Pickler", + kwlist, &file, &proto_obj, &fix_imports, &bytestr)) return -1; /* In case of multiple __init__() calls, clear previous content. */ if (self->write != NULL) (void)Pickler_clear(self); - if (_Pickler_SetProtocol(self, proto_obj, fix_imports) < 0) + if (_Pickler_SetProtocol(self, proto_obj, fix_imports, bytestr) < 0) return -1; if (_Pickler_SetOutputStream(self, file) < 0) @@ -4150,12 +4283,17 @@ free(s); if (bytes == NULL) return -1; - str = PyUnicode_FromEncodedObject(bytes, self->encoding, self->errors); - Py_DECREF(bytes); - if (str == NULL) - return -1; - - PDATA_PUSH(self->stack, str, -1); + + if (self->bytestr) { + PDATA_PUSH(self->stack, bytes, -1); + } + else { + str = PyUnicode_FromEncodedObject(bytes, self->encoding, self->errors); + Py_DECREF(bytes); + if (str == NULL) + return -1; + PDATA_PUSH(self->stack, str, -1); + } return 0; } @@ -4231,12 +4369,17 @@ if (_Unpickler_Read(self, &s, x) < 0) return -1; - /* Convert Python 2.x strings to unicode. */ - str = PyUnicode_Decode(s, x, self->encoding, self->errors); + if (self->bytestr) { + str = PyBytes_DecodeEscape(s, x, NULL, 0, NULL); + } + else { + /* Convert Python 2.x strings to unicode. */ + str = PyUnicode_Decode(s, x, self->encoding, self->errors); + } if (str == NULL) return -1; - PDATA_PUSH(self->stack, str, -1); + return 0; } @@ -4256,7 +4399,13 @@ return -1; /* Convert Python 2.x strings to unicode. */ - str = PyUnicode_Decode(s, x, self->encoding, self->errors); + if (self->bytestr) { + str = PyBytes_DecodeEscape(s, x, NULL, 0, NULL); + } + else { + /* Convert Python 2.x strings to unicode. */ + str = PyUnicode_Decode(s, x, self->encoding, self->errors); + } if (str == NULL) return -1; @@ -5585,11 +5734,13 @@ static int Unpickler_init(UnpicklerObject *self, PyObject *args, PyObject *kwds) { - static char *kwlist[] = {"file", "fix_imports", "encoding", "errors", 0}; + static char *kwlist[] = {"file", "fix_imports", "encoding", "errors", "bytestr", 0}; PyObject *file; PyObject *fix_imports = Py_True; char *encoding = NULL; char *errors = NULL; + PyObject *bytestr = Py_False; + _Py_IDENTIFIER(persistent_load); /* XXX: That is an horrible error message. But, I don't know how to do @@ -5607,8 +5758,8 @@ extra careful in the other Unpickler methods, since a subclass could forget to call Unpickler.__init__() thus breaking our internal invariants. */ - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|Oss:Unpickler", kwlist, - &file, &fix_imports, &encoding, &errors)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OssO:Unpickler", kwlist, + &file, &fix_imports, &encoding, &errors, &bytestr)) return -1; /* In case of multiple __init__() calls, clear previous content. */ @@ -5625,6 +5776,10 @@ if (self->fix_imports == -1) return -1; + self->bytestr = PyObject_IsTrue(bytestr); + if (self->bytestr == -1) + return -1; + if (_PyObject_HasAttrId((PyObject *)self, &PyId_persistent_load)) { self->pers_func = _PyObject_GetAttrId((PyObject *)self, &PyId_persistent_load); @@ -6020,6 +6175,7 @@ PyObject *file; PyObject *proto = NULL; PyObject *fix_imports = Py_True; + PyObject *bytestr = Py_False; PicklerObject *pickler; /* fix_imports is a keyword-only argument. */ @@ -6038,7 +6194,7 @@ if (pickler == NULL) return NULL; - if (_Pickler_SetProtocol(pickler, proto, fix_imports) < 0) + if (_Pickler_SetProtocol(pickler, proto, fix_imports, bytestr) < 0) goto error; if (_Pickler_SetOutputStream(pickler, file) < 0) @@ -6084,6 +6240,7 @@ PyObject *proto = NULL; PyObject *result; PyObject *fix_imports = Py_True; + PyObject *bytestr = Py_False; PicklerObject *pickler; /* fix_imports is a keyword-only argument. */ @@ -6102,7 +6259,7 @@ if (pickler == NULL) return NULL; - if (_Pickler_SetProtocol(pickler, proto, fix_imports) < 0) + if (_Pickler_SetProtocol(pickler, proto, fix_imports, bytestr) < 0) goto error; if (dump(pickler, obj) < 0)