Fix broken pickling in Python 3 build

This commit is contained in:
rdb 2016-03-31 16:49:27 +02:00
parent ed9bed425f
commit 15b0ba45f9
4 changed files with 49 additions and 21 deletions

View File

@ -21,10 +21,14 @@ context between all objects written by that Pickler.
Unfortunately, cPickle cannot be supported, because it does not Unfortunately, cPickle cannot be supported, because it does not
support extensions of this nature. """ support extensions of this nature. """
from types import * import sys
from copy_reg import dispatch_table
from panda3d.core import BamWriter, BamReader from panda3d.core import BamWriter, BamReader
if sys.version_info >= (3, 0):
from copyreg import dispatch_table
else:
from copy_reg import dispatch_table
# A funny replacement for "import pickle" so we don't get confused # A funny replacement for "import pickle" so we don't get confused
# with the local pickle.py. # with the local pickle.py.
pickle = __import__('pickle') pickle = __import__('pickle')
@ -60,7 +64,7 @@ class Pickler(pickle.Pickler):
# Check for a class with a custom metaclass; treat as regular class # Check for a class with a custom metaclass; treat as regular class
try: try:
issc = issubclass(t, TypeType) issc = issubclass(t, type)
except TypeError: # t is not a class (old Boost; see SF #502085) except TypeError: # t is not a class (old Boost; see SF #502085)
issc = 0 issc = 0
if issc: if issc:
@ -91,12 +95,12 @@ class Pickler(pickle.Pickler):
(t.__name__, obj)) (t.__name__, obj))
# Check for string returned by reduce(), meaning "save as global" # Check for string returned by reduce(), meaning "save as global"
if type(rv) is StringType: if type(rv) is str:
self.save_global(obj, rv) self.save_global(obj, rv)
return return
# Assert that reduce() returned a tuple # Assert that reduce() returned a tuple
if type(rv) is not TupleType: if type(rv) is not tuple:
raise PicklingError("%s must return string or tuple" % reduce) raise PicklingError("%s must return string or tuple" % reduce)
# Assert that it returned an appropriately sized tuple # Assert that it returned an appropriately sized tuple
@ -131,21 +135,20 @@ class Unpickler(pickle.Unpickler):
value = func(*args) value = func(*args)
stack[-1] = value stack[-1] = value
#FIXME: how to replace in Python 3?
if sys.version_info < (3, 0):
pickle.Unpickler.dispatch[pickle.REDUCE] = load_reduce pickle.Unpickler.dispatch[pickle.REDUCE] = load_reduce
# Shorthands # Shorthands
from io import BytesIO
try:
from cStringIO import StringIO
except ImportError:
from io import StringIO
def dump(obj, file, protocol=None): def dump(obj, file, protocol=None):
Pickler(file, protocol).dump(obj) Pickler(file, protocol).dump(obj)
def dumps(obj, protocol=None): def dumps(obj, protocol=None):
file = StringIO() file = BytesIO()
Pickler(file, protocol).dump(obj) Pickler(file, protocol).dump(obj)
return file.getvalue() return file.getvalue()
@ -153,5 +156,5 @@ def load(file):
return Unpickler(file).load() return Unpickler(file).load()
def loads(str): def loads(str):
file = StringIO(str) file = BytesIO(str)
return Unpickler(file).load() return Unpickler(file).load()

View File

@ -4703,9 +4703,18 @@ write_function_instance(ostream &out, FunctionRemap *remap,
if (args_type == AT_single_arg) { if (args_type == AT_single_arg) {
out << "#if PY_MAJOR_VERSION >= 3\n"; out << "#if PY_MAJOR_VERSION >= 3\n";
// As a special hack to fix pickling in Python 3, if the method name
// starts with py_decode_, we take a bytes object instead of a str.
if (remap->_cppfunc->get_local_name().substr(0, 10) == "py_decode_") {
indent(out, indent_level) << "if (PyBytes_AsStringAndSize(arg, &"
<< param_name << "_str, &" << param_name << "_len) == -1) {\n";
indent(out, indent_level + 2) << param_name << "_str = NULL;\n";
indent(out, indent_level) << "}\n";
} else {
indent(out, indent_level) indent(out, indent_level)
<< param_name << "_str = PyUnicode_AsUTF8AndSize(arg, &" << param_name << "_str = PyUnicode_AsUTF8AndSize(arg, &"
<< param_name << "_len);\n"; << param_name << "_len);\n";
}
out << "#else\n"; // NB. PyString_AsStringAndSize also accepts a PyUnicode. out << "#else\n"; // NB. PyString_AsStringAndSize also accepts a PyUnicode.
indent(out, indent_level) << "if (PyString_AsStringAndSize(arg, &" indent(out, indent_level) << "if (PyString_AsStringAndSize(arg, &"
<< param_name << "_str, &" << param_name << "_len) == -1) {\n"; << param_name << "_str, &" << param_name << "_len) == -1) {\n";
@ -4720,11 +4729,11 @@ write_function_instance(ostream &out, FunctionRemap *remap,
+ "_str, &" + param_name + "_len"; + "_str, &" + param_name + "_len";
} }
// if (TypeManager::is_const_ptr_to_basic_string_char(orig_type)) { //if (TypeManager::is_const_ptr_to_basic_string_char(orig_type)) {
// pexpr_string = "&std::string(" + param_name + "_str, " + param_name + // pexpr_string = "&std::string(" + param_name + "_str, " + param_name + "_len)";
// "_len)"; } else { //} else {
pexpr_string = param_name + "_str, " + param_name + "_len"; pexpr_string = param_name + "_str, " + param_name + "_len";
// } //}
expected_params += "str"; expected_params += "str";
} }
// Remember to clear the TypeError that any of the above methods raise. // Remember to clear the TypeError that any of the above methods raise.

View File

@ -156,7 +156,11 @@ __reduce_persist__(PyObject *self, PyObject *pickler) const {
} }
} }
#if PY_MAJOR_VERSION >= 3
PyObject *result = Py_BuildValue("(O(y#))", func, bam_stream.data(), (Py_ssize_t) bam_stream.size());
#else
PyObject *result = Py_BuildValue("(O(s#))", func, bam_stream.data(), (Py_ssize_t) bam_stream.size()); PyObject *result = Py_BuildValue("(O(s#))", func, bam_stream.data(), (Py_ssize_t) bam_stream.size());
#endif
Py_DECREF(func); Py_DECREF(func);
Py_DECREF(this_class); Py_DECREF(this_class);
return result; return result;

View File

@ -110,7 +110,11 @@ __reduce_persist__(PyObject *self, PyObject *pickler) const {
} }
} }
#if PY_MAJOR_VERSION >= 3
PyObject *result = Py_BuildValue("(O(Oy#))", func, this_class, bam_stream.data(), (Py_ssize_t) bam_stream.size());
#else
PyObject *result = Py_BuildValue("(O(Os#))", func, this_class, bam_stream.data(), (Py_ssize_t) bam_stream.size()); PyObject *result = Py_BuildValue("(O(Os#))", func, this_class, bam_stream.data(), (Py_ssize_t) bam_stream.size());
#endif
Py_DECREF(func); Py_DECREF(func);
Py_DECREF(this_class); Py_DECREF(this_class);
return result; return result;
@ -212,10 +216,18 @@ py_decode_TypedWritable_from_bam_stream_persist(PyObject *pickler, PyObject *thi
PyObject *result; PyObject *result;
if (py_reader != NULL){ if (py_reader != NULL){
#if PY_MAJOR_VERSION >= 3
result = PyObject_CallFunction(func, (char *)"(y#O)", data.data(), (Py_ssize_t) data.size(), py_reader);
#else
result = PyObject_CallFunction(func, (char *)"(s#O)", data.data(), (Py_ssize_t) data.size(), py_reader); result = PyObject_CallFunction(func, (char *)"(s#O)", data.data(), (Py_ssize_t) data.size(), py_reader);
#endif
Py_DECREF(py_reader); Py_DECREF(py_reader);
} else { } else {
#if PY_MAJOR_VERSION >= 3
result = PyObject_CallFunction(func, (char *)"(y#)", data.data(), (Py_ssize_t) data.size());
#else
result = PyObject_CallFunction(func, (char *)"(s#)", data.data(), (Py_ssize_t) data.size()); result = PyObject_CallFunction(func, (char *)"(s#)", data.data(), (Py_ssize_t) data.size());
#endif
} }
if (result == NULL) { if (result == NULL) {