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
 Unfortunately, cPickle cannot be supported, because it does not
 support extensions of this nature. """
 support extensions of this nature. """
 
 
-from types import *
-from copy_reg import dispatch_table
+import sys
 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
-    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):
 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()

+ 17 - 8
dtool/src/interrogate/interfaceMakerPythonNative.cxx

@@ -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";
-          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.
           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)) {
-// 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";
         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.

+ 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());
   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;

+ 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());
   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) {