mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-26 22:53:16 -04:00
Add pickle support to a variety of classes
This commit is contained in:
parent
650b958217
commit
eaf8cb79d5
@ -137,6 +137,9 @@ PUBLISHED:
|
||||
MAKE_SEQ_PROPERTY(parent_classes, get_num_parent_classes, get_parent_class);
|
||||
MAKE_SEQ_PROPERTY(child_classes, get_num_child_classes, get_child_class);
|
||||
|
||||
EXTENSION(PyObject *__reduce__() const);
|
||||
EXTENSION(void __setstate__(PyObject *));
|
||||
|
||||
public:
|
||||
#ifdef HAVE_PYTHON
|
||||
PyObject *get_python_type() const;
|
||||
|
@ -32,4 +32,55 @@ make(PyTypeObject *tp) {
|
||||
return dtool_tp->_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements pickle support.
|
||||
*/
|
||||
PyObject *Extension<TypeHandle>::
|
||||
__reduce__() const {
|
||||
extern struct Dtool_PyTypedObject Dtool_TypeHandle;
|
||||
extern struct Dtool_PyTypedObject Dtool_TypeRegistry;
|
||||
|
||||
if (!*_this) {
|
||||
PyObject *func = PyObject_GetAttrString((PyObject *)&Dtool_TypeHandle, "none");
|
||||
return Py_BuildValue("N()", func);
|
||||
}
|
||||
|
||||
// If we have a Python binding registered for it, that's the preferred method,
|
||||
// since it ensures that the appropriate module gets loaded by pickle.
|
||||
PyObject *py_type = _this->get_python_type();
|
||||
if (py_type != nullptr && *_this == ((Dtool_PyTypedObject *)py_type)->_type) {
|
||||
PyObject *func = PyObject_GetAttrString((PyObject *)&Dtool_TypeHandle, "make");
|
||||
return Py_BuildValue("N(O)", func, py_type);
|
||||
}
|
||||
|
||||
// Fall back to the __setstate__ mechanism.
|
||||
std::string name = _this->get_name();
|
||||
Py_ssize_t num_parents = _this->get_num_parent_classes();
|
||||
PyObject *parents = PyTuple_New(num_parents);
|
||||
for (Py_ssize_t i = 0; i < num_parents; ++i) {
|
||||
PyObject *parent = DTool_CreatePyInstance(new TypeHandle(_this->get_parent_class(i)), Dtool_TypeHandle, true, false);
|
||||
PyTuple_SET_ITEM(parents, i, parent);
|
||||
}
|
||||
return Py_BuildValue("O()(s#N)", (PyObject *)&Dtool_TypeHandle, name.c_str(), name.size(), parents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements pickle support.
|
||||
*/
|
||||
void Extension<TypeHandle>::
|
||||
__setstate__(PyObject *state) {
|
||||
Py_ssize_t len;
|
||||
const char *name_str = PyUnicode_AsUTF8AndSize(PyTuple_GET_ITEM(state, 0), &len);
|
||||
PyObject *parents = PyTuple_GET_ITEM(state, 1);
|
||||
|
||||
TypeRegistry *type_registry = TypeRegistry::ptr();
|
||||
*_this = type_registry->register_dynamic_type(std::string(name_str, len));
|
||||
|
||||
Py_ssize_t num_parents = PyTuple_GET_SIZE(parents);
|
||||
for (Py_ssize_t i = 0; i < num_parents; ++i) {
|
||||
TypeHandle *parent = (TypeHandle *)DtoolInstance_VOID_PTR(PyTuple_GET_ITEM(parents, i));
|
||||
type_registry->record_derivation(*_this, *parent);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -30,6 +30,9 @@ template<>
|
||||
class Extension<TypeHandle> : public ExtensionBase<TypeHandle> {
|
||||
public:
|
||||
static TypeHandle make(PyTypeObject *tp);
|
||||
|
||||
PyObject *__reduce__() const;
|
||||
void __setstate__(PyObject *);
|
||||
};
|
||||
|
||||
#endif // HAVE_PYTHON
|
||||
|
@ -67,6 +67,8 @@ set(P3DISPLAY_SOURCES
|
||||
)
|
||||
|
||||
set(P3DISPLAY_IGATEEXT
|
||||
graphicsPipeSelection_ext.cxx
|
||||
graphicsPipeSelection_ext.h
|
||||
graphicsStateGuardian_ext.cxx
|
||||
graphicsStateGuardian_ext.h
|
||||
graphicsWindow_ext.cxx
|
||||
|
@ -52,6 +52,8 @@ PUBLISHED:
|
||||
|
||||
INLINE static GraphicsPipeSelection *get_global_ptr();
|
||||
|
||||
EXTENSION(PyObject *__reduce__() const);
|
||||
|
||||
public:
|
||||
typedef PT(GraphicsPipe) PipeConstructorFunc();
|
||||
bool add_pipe_type(TypeHandle type, PipeConstructorFunc *func);
|
||||
|
31
panda/src/display/graphicsPipeSelection_ext.cxx
Normal file
31
panda/src/display/graphicsPipeSelection_ext.cxx
Normal file
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* PANDA 3D SOFTWARE
|
||||
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
*
|
||||
* All use of this software is subject to the terms of the revised BSD
|
||||
* license. You should have received a copy of this license along
|
||||
* with this source code in a file named "LICENSE."
|
||||
*
|
||||
* @file graphicsPipeSelection_ext.cxx
|
||||
* @author rdb
|
||||
* @date 2021-12-10
|
||||
*/
|
||||
|
||||
#include "graphicsPipeSelection_ext.h"
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
|
||||
#include "pythonLoaderFileType.h"
|
||||
|
||||
extern struct Dtool_PyTypedObject Dtool_GraphicsPipeSelection;
|
||||
|
||||
/**
|
||||
* Implements pickle support.
|
||||
*/
|
||||
PyObject *Extension<GraphicsPipeSelection>::
|
||||
__reduce__() const {
|
||||
PyObject *func = PyObject_GetAttrString((PyObject *)&Dtool_GraphicsPipeSelection, "get_global_ptr");
|
||||
return Py_BuildValue("N()", func);
|
||||
}
|
||||
|
||||
#endif
|
37
panda/src/display/graphicsPipeSelection_ext.h
Normal file
37
panda/src/display/graphicsPipeSelection_ext.h
Normal file
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* PANDA 3D SOFTWARE
|
||||
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
*
|
||||
* All use of this software is subject to the terms of the revised BSD
|
||||
* license. You should have received a copy of this license along
|
||||
* with this source code in a file named "LICENSE."
|
||||
*
|
||||
* @file graphicsPipeSelection_ext.h
|
||||
* @author rdb
|
||||
* @date 2021-12-10
|
||||
*/
|
||||
|
||||
#ifndef GRAPHICSPIPESELECTION_EXT_H
|
||||
#define GRAPHICSPIPESELECTION_EXT_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
|
||||
#include "extension.h"
|
||||
#include "graphicsPipeSelection.h"
|
||||
#include "py_panda.h"
|
||||
|
||||
/**
|
||||
* This class defines the extension methods for GraphicsPipeSelection, which are called
|
||||
* instead of any C++ methods with the same prototype.
|
||||
*/
|
||||
template<>
|
||||
class Extension<GraphicsPipeSelection> : public ExtensionBase<GraphicsPipeSelection> {
|
||||
public:
|
||||
PyObject *__reduce__() const;
|
||||
};
|
||||
|
||||
#endif // HAVE_PYTHON
|
||||
|
||||
#endif // GRAPHICSPIPESELECTION_EXT_H
|
@ -1,3 +1,4 @@
|
||||
#include "graphicsPipeSelection_ext.cxx"
|
||||
#include "graphicsStateGuardian_ext.cxx"
|
||||
#include "graphicsWindow_ext.cxx"
|
||||
#include "pythonGraphicsWindowProc.cxx"
|
||||
|
@ -205,6 +205,9 @@ PUBLISHED:
|
||||
MAKE_PROPERTY2(parent_window, has_parent_window, get_parent_window,
|
||||
set_parent_window, clear_parent_window);
|
||||
|
||||
EXTENSION(PyObject *__getstate__(PyObject *self) const);
|
||||
EXTENSION(void __setstate__(PyObject *self, PyObject *state));
|
||||
|
||||
void add_properties(const WindowProperties &other);
|
||||
|
||||
void output(std::ostream &out) const;
|
||||
|
@ -50,27 +50,63 @@ __init__(PyObject *self, PyObject *args, PyObject *kwds) {
|
||||
// Now iterate over the keyword arguments, which define the default values
|
||||
// for the different properties.
|
||||
if (kwds != nullptr) {
|
||||
PyTypeObject *type = Py_TYPE(self);
|
||||
PyObject *key, *value;
|
||||
Py_ssize_t pos = 0;
|
||||
__setstate__(self, kwds);
|
||||
}
|
||||
}
|
||||
|
||||
while (PyDict_Next(kwds, &pos, &key, &value)) {
|
||||
// Look for a writable property on the type by this name.
|
||||
PyObject *descr = _PyType_Lookup(type, key);
|
||||
/**
|
||||
* Returns the properties as a dictionary.
|
||||
*/
|
||||
PyObject *Extension<WindowProperties>::
|
||||
__getstate__(PyObject *self) const {
|
||||
static const char *props[] = {"origin", "size", "title", "undecorated", "fixed_size", "fullscreen", "foreground", "minimized", "maximized", "raw_mice", "open", "cursor_hidden", "icon_filename", "cursor_filename", "z_order", "mouse_mode", "parent_window", nullptr};
|
||||
|
||||
if (descr != nullptr && Py_TYPE(descr)->tp_descr_set != nullptr) {
|
||||
if (Py_TYPE(descr)->tp_descr_set(descr, self, value) < 0) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
PyObject *key_repr = PyObject_Repr(key);
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.100s is an invalid keyword argument for WindowProperties()",
|
||||
PyUnicode_AsUTF8(key_repr)
|
||||
);
|
||||
Py_DECREF(key_repr);
|
||||
PyTypeObject *type = Py_TYPE(self);
|
||||
PyObject *state = PyDict_New();
|
||||
|
||||
for (size_t i = 0; props[i] != nullptr; ++i) {
|
||||
PyObject *key = PyUnicode_FromString(props[i]);
|
||||
PyObject *descr = _PyType_Lookup(type, key);
|
||||
|
||||
if (descr != nullptr && Py_TYPE(descr)->tp_descr_get != nullptr) {
|
||||
PyObject *value = Py_TYPE(descr)->tp_descr_get(descr, self, (PyObject *)type);
|
||||
nassertr(value != nullptr, nullptr);
|
||||
if (value != Py_None) {
|
||||
PyDict_SetItem(state, key, value);
|
||||
}
|
||||
Py_DECREF(value);
|
||||
}
|
||||
Py_DECREF(key);
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void Extension<WindowProperties>::
|
||||
__setstate__(PyObject *self, PyObject *props) {
|
||||
PyTypeObject *type = Py_TYPE(self);
|
||||
PyObject *key, *value;
|
||||
Py_ssize_t pos = 0;
|
||||
|
||||
while (PyDict_Next(props, &pos, &key, &value)) {
|
||||
// Look for a writable property on the type by this name.
|
||||
PyObject *descr = _PyType_Lookup(type, key);
|
||||
|
||||
if (descr != nullptr && Py_TYPE(descr)->tp_descr_set != nullptr) {
|
||||
if (Py_TYPE(descr)->tp_descr_set(descr, self, value) < 0) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
PyObject *key_repr = PyObject_Repr(key);
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.100s is an invalid keyword argument for WindowProperties()",
|
||||
PyUnicode_AsUTF8(key_repr)
|
||||
);
|
||||
Py_DECREF(key_repr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,9 @@ template<>
|
||||
class Extension<WindowProperties> : public ExtensionBase<WindowProperties> {
|
||||
public:
|
||||
void __init__(PyObject *self, PyObject *args, PyObject *kwds);
|
||||
|
||||
PyObject *__getstate__(PyObject *self) const;
|
||||
void __setstate__(PyObject *self, PyObject *state);
|
||||
};
|
||||
|
||||
#endif // HAVE_PYTHON
|
||||
|
@ -36,6 +36,9 @@ PUBLISHED:
|
||||
INLINE size_t get_data_size() const;
|
||||
INLINE void clear();
|
||||
|
||||
EXTENSION(PyObject *__getstate__() const);
|
||||
EXTENSION(void __setstate__(PyObject *state));
|
||||
|
||||
public:
|
||||
std::string read(size_t length);
|
||||
std::string readline();
|
||||
|
@ -74,4 +74,28 @@ get_data() const {
|
||||
return PyBytes_FromStringAndSize(_this->_data.data(), _this->_data.size());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
PyObject *Extension<Ramfile>::
|
||||
__getstate__() const {
|
||||
PyObject *state = PyTuple_New(2);
|
||||
PyTuple_SET_ITEM(state, 0, get_data());
|
||||
PyTuple_SET_ITEM(state, 1, PyLong_FromSize_t(_this->tell()));
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void Extension<Ramfile>::
|
||||
__setstate__(PyObject *state) {
|
||||
char *str;
|
||||
Py_ssize_t len;
|
||||
if (PyBytes_AsStringAndSize(PyTuple_GET_ITEM(state, 0), &str, &len) >= 0) {
|
||||
_this->_data = std::string(str, len);
|
||||
}
|
||||
_this->seek(PyLong_AsSize_t(PyTuple_GET_ITEM(state, 1)));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -34,6 +34,9 @@ public:
|
||||
PyObject *readlines();
|
||||
|
||||
PyObject *get_data() const;
|
||||
|
||||
PyObject *__getstate__() const;
|
||||
void __setstate__(PyObject *);
|
||||
};
|
||||
|
||||
#endif // HAVE_PYTHON
|
||||
|
@ -29,6 +29,7 @@ ConfigureFn(config_pythonCallbackObject) {
|
||||
|
||||
#ifndef CPPPARSER
|
||||
extern struct Dtool_PyTypedObject Dtool_TypedObject;
|
||||
extern struct Dtool_PyTypedObject Dtool_PythonCallbackObject;
|
||||
#endif
|
||||
|
||||
/**
|
||||
@ -84,6 +85,14 @@ get_function() {
|
||||
return _function;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements pickle support.
|
||||
*/
|
||||
PyObject *PythonCallbackObject::
|
||||
__reduce__() const {
|
||||
return Py_BuildValue("O(O)", (PyObject *)&Dtool_PythonCallbackObject, _function);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method called when the callback is triggered; it *replaces* the
|
||||
* original function. To continue performing the original function, you must
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
/**
|
||||
* This is a specialization on CallbackObject to allow a callback to directly
|
||||
* call an arbitarary Python function. Powerful! But use with caution.
|
||||
* call an arbitrary Python function. Powerful! But use with caution.
|
||||
*/
|
||||
class PythonCallbackObject : public CallbackObject {
|
||||
PUBLISHED:
|
||||
@ -34,6 +34,8 @@ PUBLISHED:
|
||||
void set_function(PyObject *function);
|
||||
PyObject *get_function();
|
||||
|
||||
PyObject *__reduce__() const;
|
||||
|
||||
MAKE_PROPERTY(function, get_function, set_function);
|
||||
|
||||
public:
|
||||
|
Loading…
x
Reference in New Issue
Block a user