mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-28 07:48:37 -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(parent_classes, get_num_parent_classes, get_parent_class);
|
||||||
MAKE_SEQ_PROPERTY(child_classes, get_num_child_classes, get_child_class);
|
MAKE_SEQ_PROPERTY(child_classes, get_num_child_classes, get_child_class);
|
||||||
|
|
||||||
|
EXTENSION(PyObject *__reduce__() const);
|
||||||
|
EXTENSION(void __setstate__(PyObject *));
|
||||||
|
|
||||||
public:
|
public:
|
||||||
#ifdef HAVE_PYTHON
|
#ifdef HAVE_PYTHON
|
||||||
PyObject *get_python_type() const;
|
PyObject *get_python_type() const;
|
||||||
|
@ -32,4 +32,55 @@ make(PyTypeObject *tp) {
|
|||||||
return dtool_tp->_type;
|
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
|
#endif
|
||||||
|
@ -30,6 +30,9 @@ template<>
|
|||||||
class Extension<TypeHandle> : public ExtensionBase<TypeHandle> {
|
class Extension<TypeHandle> : public ExtensionBase<TypeHandle> {
|
||||||
public:
|
public:
|
||||||
static TypeHandle make(PyTypeObject *tp);
|
static TypeHandle make(PyTypeObject *tp);
|
||||||
|
|
||||||
|
PyObject *__reduce__() const;
|
||||||
|
void __setstate__(PyObject *);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // HAVE_PYTHON
|
#endif // HAVE_PYTHON
|
||||||
|
@ -67,6 +67,8 @@ set(P3DISPLAY_SOURCES
|
|||||||
)
|
)
|
||||||
|
|
||||||
set(P3DISPLAY_IGATEEXT
|
set(P3DISPLAY_IGATEEXT
|
||||||
|
graphicsPipeSelection_ext.cxx
|
||||||
|
graphicsPipeSelection_ext.h
|
||||||
graphicsStateGuardian_ext.cxx
|
graphicsStateGuardian_ext.cxx
|
||||||
graphicsStateGuardian_ext.h
|
graphicsStateGuardian_ext.h
|
||||||
graphicsWindow_ext.cxx
|
graphicsWindow_ext.cxx
|
||||||
|
@ -52,6 +52,8 @@ PUBLISHED:
|
|||||||
|
|
||||||
INLINE static GraphicsPipeSelection *get_global_ptr();
|
INLINE static GraphicsPipeSelection *get_global_ptr();
|
||||||
|
|
||||||
|
EXTENSION(PyObject *__reduce__() const);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef PT(GraphicsPipe) PipeConstructorFunc();
|
typedef PT(GraphicsPipe) PipeConstructorFunc();
|
||||||
bool add_pipe_type(TypeHandle type, PipeConstructorFunc *func);
|
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 "graphicsStateGuardian_ext.cxx"
|
||||||
#include "graphicsWindow_ext.cxx"
|
#include "graphicsWindow_ext.cxx"
|
||||||
#include "pythonGraphicsWindowProc.cxx"
|
#include "pythonGraphicsWindowProc.cxx"
|
||||||
|
@ -205,6 +205,9 @@ PUBLISHED:
|
|||||||
MAKE_PROPERTY2(parent_window, has_parent_window, get_parent_window,
|
MAKE_PROPERTY2(parent_window, has_parent_window, get_parent_window,
|
||||||
set_parent_window, clear_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 add_properties(const WindowProperties &other);
|
||||||
|
|
||||||
void output(std::ostream &out) const;
|
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
|
// Now iterate over the keyword arguments, which define the default values
|
||||||
// for the different properties.
|
// for the different properties.
|
||||||
if (kwds != nullptr) {
|
if (kwds != nullptr) {
|
||||||
PyTypeObject *type = Py_TYPE(self);
|
__setstate__(self, kwds);
|
||||||
PyObject *key, *value;
|
}
|
||||||
Py_ssize_t pos = 0;
|
}
|
||||||
|
|
||||||
while (PyDict_Next(kwds, &pos, &key, &value)) {
|
/**
|
||||||
// Look for a writable property on the type by this name.
|
* Returns the properties as a dictionary.
|
||||||
PyObject *descr = _PyType_Lookup(type, key);
|
*/
|
||||||
|
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) {
|
PyTypeObject *type = Py_TYPE(self);
|
||||||
if (Py_TYPE(descr)->tp_descr_set(descr, self, value) < 0) {
|
PyObject *state = PyDict_New();
|
||||||
return;
|
|
||||||
}
|
for (size_t i = 0; props[i] != nullptr; ++i) {
|
||||||
} else {
|
PyObject *key = PyUnicode_FromString(props[i]);
|
||||||
PyObject *key_repr = PyObject_Repr(key);
|
PyObject *descr = _PyType_Lookup(type, key);
|
||||||
PyErr_Format(PyExc_TypeError,
|
|
||||||
"%.100s is an invalid keyword argument for WindowProperties()",
|
if (descr != nullptr && Py_TYPE(descr)->tp_descr_get != nullptr) {
|
||||||
PyUnicode_AsUTF8(key_repr)
|
PyObject *value = Py_TYPE(descr)->tp_descr_get(descr, self, (PyObject *)type);
|
||||||
);
|
nassertr(value != nullptr, nullptr);
|
||||||
Py_DECREF(key_repr);
|
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;
|
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> {
|
class Extension<WindowProperties> : public ExtensionBase<WindowProperties> {
|
||||||
public:
|
public:
|
||||||
void __init__(PyObject *self, PyObject *args, PyObject *kwds);
|
void __init__(PyObject *self, PyObject *args, PyObject *kwds);
|
||||||
|
|
||||||
|
PyObject *__getstate__(PyObject *self) const;
|
||||||
|
void __setstate__(PyObject *self, PyObject *state);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // HAVE_PYTHON
|
#endif // HAVE_PYTHON
|
||||||
|
@ -36,6 +36,9 @@ PUBLISHED:
|
|||||||
INLINE size_t get_data_size() const;
|
INLINE size_t get_data_size() const;
|
||||||
INLINE void clear();
|
INLINE void clear();
|
||||||
|
|
||||||
|
EXTENSION(PyObject *__getstate__() const);
|
||||||
|
EXTENSION(void __setstate__(PyObject *state));
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::string read(size_t length);
|
std::string read(size_t length);
|
||||||
std::string readline();
|
std::string readline();
|
||||||
|
@ -74,4 +74,28 @@ get_data() const {
|
|||||||
return PyBytes_FromStringAndSize(_this->_data.data(), _this->_data.size());
|
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
|
#endif
|
||||||
|
@ -34,6 +34,9 @@ public:
|
|||||||
PyObject *readlines();
|
PyObject *readlines();
|
||||||
|
|
||||||
PyObject *get_data() const;
|
PyObject *get_data() const;
|
||||||
|
|
||||||
|
PyObject *__getstate__() const;
|
||||||
|
void __setstate__(PyObject *);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // HAVE_PYTHON
|
#endif // HAVE_PYTHON
|
||||||
|
@ -29,6 +29,7 @@ ConfigureFn(config_pythonCallbackObject) {
|
|||||||
|
|
||||||
#ifndef CPPPARSER
|
#ifndef CPPPARSER
|
||||||
extern struct Dtool_PyTypedObject Dtool_TypedObject;
|
extern struct Dtool_PyTypedObject Dtool_TypedObject;
|
||||||
|
extern struct Dtool_PyTypedObject Dtool_PythonCallbackObject;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -84,6 +85,14 @@ get_function() {
|
|||||||
return _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
|
* This method called when the callback is triggered; it *replaces* the
|
||||||
* original function. To continue performing the original function, you must
|
* 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
|
* 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 {
|
class PythonCallbackObject : public CallbackObject {
|
||||||
PUBLISHED:
|
PUBLISHED:
|
||||||
@ -34,6 +34,8 @@ PUBLISHED:
|
|||||||
void set_function(PyObject *function);
|
void set_function(PyObject *function);
|
||||||
PyObject *get_function();
|
PyObject *get_function();
|
||||||
|
|
||||||
|
PyObject *__reduce__() const;
|
||||||
|
|
||||||
MAKE_PROPERTY(function, get_function, set_function);
|
MAKE_PROPERTY(function, get_function, set_function);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user