From 15b0ba45f90a3987afe9b8ea1dce83f92bef7106 Mon Sep 17 00:00:00 2001 From: rdb Date: Thu, 31 Mar 2016 16:49:27 +0200 Subject: [PATCH] Fix broken pickling in Python 3 build --- direct/src/stdpy/pickle.py | 29 ++++++++++--------- .../interfaceMakerPythonNative.cxx | 25 +++++++++++----- panda/src/pgraph/nodePath_ext.cxx | 4 +++ panda/src/putil/typedWritable_ext.cxx | 12 ++++++++ 4 files changed, 49 insertions(+), 21 deletions(-) diff --git a/direct/src/stdpy/pickle.py b/direct/src/stdpy/pickle.py index 57e7c2521c..027888e281 100644 --- a/direct/src/stdpy/pickle.py +++ b/direct/src/stdpy/pickle.py @@ -21,10 +21,14 @@ context between all objects written by that Pickler. Unfortunately, cPickle cannot be supported, because it does not support extensions of this nature. """ -from types import * -from copy_reg import dispatch_table +import sys 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 # with the local pickle.py. pickle = __import__('pickle') @@ -60,7 +64,7 @@ class Pickler(pickle.Pickler): # Check for a class with a custom metaclass; treat as regular class try: - issc = issubclass(t, TypeType) + issc = issubclass(t, type) except TypeError: # t is not a class (old Boost; see SF #502085) issc = 0 if issc: @@ -91,12 +95,12 @@ class Pickler(pickle.Pickler): (t.__name__, obj)) # 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) return # 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) # Assert that it returned an appropriately sized tuple @@ -131,21 +135,20 @@ class Unpickler(pickle.Unpickler): value = func(*args) stack[-1] = value - pickle.Unpickler.dispatch[pickle.REDUCE] = load_reduce + + #FIXME: how to replace in Python 3? + if sys.version_info < (3, 0): + pickle.Unpickler.dispatch[pickle.REDUCE] = load_reduce # Shorthands - -try: - from cStringIO import StringIO -except ImportError: - from io import StringIO +from io import BytesIO def dump(obj, file, protocol=None): Pickler(file, protocol).dump(obj) def dumps(obj, protocol=None): - file = StringIO() + file = BytesIO() Pickler(file, protocol).dump(obj) return file.getvalue() @@ -153,5 +156,5 @@ def load(file): return Unpickler(file).load() def loads(str): - file = StringIO(str) + file = BytesIO(str) return Unpickler(file).load() diff --git a/dtool/src/interrogate/interfaceMakerPythonNative.cxx b/dtool/src/interrogate/interfaceMakerPythonNative.cxx index 5ab6f54768..c07e6af50f 100644 --- a/dtool/src/interrogate/interfaceMakerPythonNative.cxx +++ b/dtool/src/interrogate/interfaceMakerPythonNative.cxx @@ -4703,9 +4703,18 @@ write_function_instance(ostream &out, FunctionRemap *remap, if (args_type == AT_single_arg) { out << "#if PY_MAJOR_VERSION >= 3\n"; - indent(out, indent_level) - << param_name << "_str = PyUnicode_AsUTF8AndSize(arg, &" - << param_name << "_len);\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) + << param_name << "_str = PyUnicode_AsUTF8AndSize(arg, &" + << param_name << "_len);\n"; + } out << "#else\n"; // NB. PyString_AsStringAndSize also accepts a PyUnicode. indent(out, indent_level) << "if (PyString_AsStringAndSize(arg, &" << param_name << "_str, &" << param_name << "_len) == -1) {\n"; @@ -4720,11 +4729,11 @@ write_function_instance(ostream &out, FunctionRemap *remap, + "_str, &" + param_name + "_len"; } -// if (TypeManager::is_const_ptr_to_basic_string_char(orig_type)) { -// pexpr_string = "&std::string(" + param_name + "_str, " + param_name + -// "_len)"; } else { - pexpr_string = param_name + "_str, " + param_name + "_len"; -// } + //if (TypeManager::is_const_ptr_to_basic_string_char(orig_type)) { + // pexpr_string = "&std::string(" + param_name + "_str, " + param_name + "_len)"; + //} else { + pexpr_string = param_name + "_str, " + param_name + "_len"; + //} expected_params += "str"; } // Remember to clear the TypeError that any of the above methods raise. diff --git a/panda/src/pgraph/nodePath_ext.cxx b/panda/src/pgraph/nodePath_ext.cxx index c13ec6326d..656802b8f0 100644 --- a/panda/src/pgraph/nodePath_ext.cxx +++ b/panda/src/pgraph/nodePath_ext.cxx @@ -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()); +#endif Py_DECREF(func); Py_DECREF(this_class); return result; diff --git a/panda/src/putil/typedWritable_ext.cxx b/panda/src/putil/typedWritable_ext.cxx index afa7f986c8..224686ed3e 100644 --- a/panda/src/putil/typedWritable_ext.cxx +++ b/panda/src/putil/typedWritable_ext.cxx @@ -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()); +#endif Py_DECREF(func); Py_DECREF(this_class); return result; @@ -212,10 +216,18 @@ py_decode_TypedWritable_from_bam_stream_persist(PyObject *pickler, PyObject *thi PyObject *result; 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); +#endif Py_DECREF(py_reader); } 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()); +#endif } if (result == NULL) {