Browse Source

Fix broken pickling in Python 3 build

rdb 9 years ago
parent
commit
15b0ba45f9

+ 16 - 13
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
+# Shorthands
+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()

+ 17 - 8
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.

+ 4 - 0
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;

+ 12 - 0
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) {