mirror of https://github.com/KLayout/klayout.git
Fixed a segfault on help(pya.Box)
Needed to refactor the class hierarchy of the Python classes. Basically the module specific base class was removed as it does not provide any benefit. The object layout of the PyObject specialization was modified such that the payload is attached to the end. This is compatible with the hidden extensions which Python adds to normal objects.
This commit is contained in:
parent
aca209c095
commit
5fe0aca9c7
|
|
@ -291,7 +291,7 @@ tl::Variant python2c_func<tl::Variant>::operator() (PyObject *rval)
|
|||
const gsi::ClassBase *cls = PythonModule::cls_for_type (Py_TYPE (rval));
|
||||
if (cls) {
|
||||
|
||||
PYAObjectBase *p = (PYAObjectBase *) rval;
|
||||
PYAObjectBase *p = PYAObjectBase::from_pyobject (rval);
|
||||
|
||||
// employ the tl::Variant binding capabilities of the Expression binding to derive the
|
||||
// variant value.
|
||||
|
|
@ -359,9 +359,8 @@ object_to_python (void *obj, PYAObjectBase *self, const gsi::ArgType &atype)
|
|||
* object turns into a non-const one. This may be confusing but provides a certain level
|
||||
* of "constness", at least until there is another non-const reference for that object.
|
||||
*/
|
||||
void correct_constness (PyObject *obj, bool const_required)
|
||||
void correct_constness (PYAObjectBase *p, bool const_required)
|
||||
{
|
||||
PYAObjectBase *p = (PYAObjectBase *) obj;
|
||||
if (p->const_ref () && ! const_required) {
|
||||
// promote to non-const object
|
||||
p->set_const_ref (false);
|
||||
|
|
@ -421,20 +420,21 @@ object_to_python (void *obj, PYAObjectBase *self, const gsi::ClassBase *cls, boo
|
|||
tl_assert (type != NULL);
|
||||
|
||||
// create a instance and copy the value
|
||||
PYAObjectBase *new_object = (PYAObjectBase *) type->tp_alloc (type, 0);
|
||||
new (new_object) PYAObjectBase (clsact);
|
||||
PyObject *new_pyobject = type->tp_alloc (type, 0);
|
||||
PYAObjectBase *new_object = PYAObjectBase::from_pyobject_unsafe (new_pyobject);
|
||||
new (new_object) PYAObjectBase (clsact, new_pyobject);
|
||||
clsact->assign (new_object->obj (), obj);
|
||||
return new_object;
|
||||
return new_pyobject;
|
||||
|
||||
} else if (pya_object) {
|
||||
|
||||
// we have a that is located in C++ space but is supposed to get attached
|
||||
// a Python object. If it already has, we simply return a reference to this
|
||||
Py_INCREF (pya_object);
|
||||
Py_INCREF (pya_object->py_object ());
|
||||
|
||||
correct_constness (pya_object, is_const);
|
||||
|
||||
return pya_object;
|
||||
return pya_object->py_object ();
|
||||
|
||||
} else {
|
||||
|
||||
|
|
@ -442,10 +442,11 @@ object_to_python (void *obj, PYAObjectBase *self, const gsi::ClassBase *cls, boo
|
|||
tl_assert (type != NULL);
|
||||
|
||||
// create a instance and copy the value
|
||||
PYAObjectBase *new_object = (PYAObjectBase *) type->tp_alloc (type, 0);
|
||||
new (new_object) PYAObjectBase (clsact);
|
||||
PyObject *new_pyobject = type->tp_alloc (type, 0);
|
||||
PYAObjectBase *new_object = PYAObjectBase::from_pyobject_unsafe (new_pyobject);
|
||||
new (new_object) PYAObjectBase (clsact, new_pyobject);
|
||||
new_object->set (obj, pass_obj, is_const, can_destroy);
|
||||
return new_object;
|
||||
return new_pyobject;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -352,7 +352,7 @@ template <class T> struct python2c_func<T &>
|
|||
tl_assert (cls_decl != 0);
|
||||
tl_assert (is_derived_from (cls_decl, typeid (T)));
|
||||
|
||||
PYAObjectBase *p = (PYAObjectBase *) (rval);
|
||||
PYAObjectBase *p = PYAObjectBase::from_pyobject (rval);
|
||||
return *((T *)p->obj ());
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ struct get_boxed_value_func
|
|||
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Passing an object to pointer or reference requires a boxed type (pya.%s)")), bt->name ()));
|
||||
}
|
||||
|
||||
PYAObjectBase *p = (PYAObjectBase *) arg;
|
||||
PYAObjectBase *p = PYAObjectBase::from_pyobject (arg);
|
||||
gsi::Value *bo = reinterpret_cast<gsi::Value *> (p->obj ());
|
||||
if (bo) {
|
||||
*ret = bo->value ().template morph<R> ().native_ptr ();
|
||||
|
|
@ -389,7 +389,7 @@ struct writer<gsi::ObjectType>
|
|||
|
||||
if (cls_decl->is_derived_from (atype.cls ())) {
|
||||
|
||||
PYAObjectBase *p = (PYAObjectBase *) (arg);
|
||||
PYAObjectBase *p = PYAObjectBase::from_pyobject (arg);
|
||||
|
||||
if (cls_decl->adapted_type_info ()) {
|
||||
// resolved adapted type
|
||||
|
|
@ -400,7 +400,7 @@ struct writer<gsi::ObjectType>
|
|||
|
||||
} else if (cls_decl->can_convert_to (atype.cls ())) {
|
||||
|
||||
PYAObjectBase *p = (PYAObjectBase *) (arg);
|
||||
PYAObjectBase *p = PYAObjectBase::from_pyobject (arg);
|
||||
|
||||
// We can convert objects for cref and cptr, but ownership over these objects is not transferred.
|
||||
// Hence we have to keep them on the heap.
|
||||
|
|
@ -421,7 +421,7 @@ struct writer<gsi::ObjectType>
|
|||
|
||||
if (cls_decl->is_derived_from (atype.cls ())) {
|
||||
|
||||
PYAObjectBase *p = (PYAObjectBase *) (arg);
|
||||
PYAObjectBase *p = PYAObjectBase::from_pyobject (arg);
|
||||
|
||||
if (cls_decl->adapted_type_info ()) {
|
||||
// resolved adapted type
|
||||
|
|
@ -432,7 +432,7 @@ struct writer<gsi::ObjectType>
|
|||
|
||||
} else if (cls_decl->can_convert_to (atype.cls ())) {
|
||||
|
||||
PYAObjectBase *p = (PYAObjectBase *) (arg);
|
||||
PYAObjectBase *p = PYAObjectBase::from_pyobject (arg);
|
||||
aa->write<void *> (atype.cls ()->create_obj_from (cls_decl, p->obj ()));
|
||||
|
||||
} else {
|
||||
|
|
@ -471,7 +471,7 @@ push_arg (const gsi::ArgType &atype, gsi::SerialArgs &aserial, PyObject *arg, tl
|
|||
template <class R>
|
||||
struct reader
|
||||
{
|
||||
void operator() (gsi::SerialArgs *rr, PythonRef *ret, PyObject * /*self*/, const gsi::ArgType &arg, tl::Heap *heap)
|
||||
void operator() (gsi::SerialArgs *rr, PythonRef *ret, PYAObjectBase * /*self*/, const gsi::ArgType &arg, tl::Heap *heap)
|
||||
{
|
||||
if (arg.is_ref ()) {
|
||||
*ret = c2python (rr->template read<R &> (*heap));
|
||||
|
|
@ -506,7 +506,7 @@ struct reader
|
|||
template <>
|
||||
struct reader<void *>
|
||||
{
|
||||
void operator() (gsi::SerialArgs *rr, PythonRef *ret, PyObject * /*self*/, const gsi::ArgType &arg, tl::Heap *heap)
|
||||
void operator() (gsi::SerialArgs *rr, PythonRef *ret, PYAObjectBase * /*self*/, const gsi::ArgType &arg, tl::Heap *heap)
|
||||
{
|
||||
tl_assert (! arg.is_cref ());
|
||||
tl_assert (! arg.is_ref ());
|
||||
|
|
|
|||
|
|
@ -575,9 +575,9 @@ static std::string extract_python_name (const std::string &name)
|
|||
static void
|
||||
pya_object_deallocate (PyObject *self)
|
||||
{
|
||||
PYAObjectBase *p = (PYAObjectBase *) self;
|
||||
PYAObjectBase *p = PYAObjectBase::from_pyobject (self);
|
||||
p->~PYAObjectBase ();
|
||||
Py_TYPE (self)->tp_free ((PyObject*)self);
|
||||
Py_TYPE (self)->tp_free (self);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -602,9 +602,10 @@ static PyObject *
|
|||
pya_object_new (PyTypeObject *type, PyObject * /*args*/, PyObject * /*kwds*/)
|
||||
{
|
||||
// create the object
|
||||
PYAObjectBase *self = (PYAObjectBase *) type->tp_alloc (type, 0);
|
||||
new (self) PYAObjectBase (PythonModule::cls_for_type (type));
|
||||
return (PyObject *) self;
|
||||
PyObject *self_pyobject = type->tp_alloc (type, 0);
|
||||
PYAObjectBase *self = PYAObjectBase::from_pyobject_unsafe (self_pyobject);
|
||||
new (self) PYAObjectBase (PythonModule::cls_for_type (type), self_pyobject);
|
||||
return self_pyobject;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
|
@ -619,7 +620,7 @@ method_name_from_id (int mid, PyObject *self)
|
|||
const gsi::ClassBase *cls_decl = 0;
|
||||
|
||||
if (! PyType_Check (self)) {
|
||||
PYAObjectBase *p = (PYAObjectBase *) self;
|
||||
PYAObjectBase *p = PYAObjectBase::from_pyobject (self);
|
||||
cls_decl = p->cls_decl ();
|
||||
} else {
|
||||
cls_decl = PythonModule::cls_for_type ((PyTypeObject *) self);
|
||||
|
|
@ -652,7 +653,7 @@ property_name_from_id (int mid, PyObject *self)
|
|||
const gsi::ClassBase *cls_decl = 0;
|
||||
|
||||
if (! PyType_Check (self)) {
|
||||
PYAObjectBase *p = (PYAObjectBase *) self;
|
||||
PYAObjectBase *p = PYAObjectBase::from_pyobject (self);
|
||||
cls_decl = p->cls_decl ();
|
||||
} else {
|
||||
cls_decl = PythonModule::cls_for_type ((PyTypeObject *) self);
|
||||
|
|
@ -684,7 +685,7 @@ get_return_value (PYAObjectBase *self, gsi::SerialArgs &retlist, const gsi::Meth
|
|||
if (meth->ret_type ().is_iter ()) {
|
||||
|
||||
gsi::IterAdaptorAbstractBase *iter = (gsi::IterAdaptorAbstractBase *) retlist.read<gsi::IterAdaptorAbstractBase *> (heap);
|
||||
ret = (PyObject *) PYAIteratorObject::create (self, iter, &meth->ret_type ());
|
||||
ret = (PyObject *) PYAIteratorObject::create (self ? self->py_object () : 0, iter, &meth->ret_type ());
|
||||
|
||||
} else {
|
||||
|
||||
|
|
@ -702,7 +703,7 @@ match_method (int mid, PyObject *self, PyObject *args, bool strict)
|
|||
|
||||
PYAObjectBase *p = 0;
|
||||
if (! PyType_Check (self)) {
|
||||
p = (PYAObjectBase *) self;
|
||||
p = PYAObjectBase::from_pyobject (self);
|
||||
cls_decl = p->cls_decl ();
|
||||
} else {
|
||||
cls_decl = PythonModule::cls_for_type ((PyTypeObject *) self);
|
||||
|
|
@ -869,10 +870,11 @@ object_dup (PyObject *self, PyObject *args)
|
|||
throw tl::Exception (tl::to_string (tr ("No copy constructor provided for class '%s'")), cls_decl_self->name ());
|
||||
}
|
||||
|
||||
PYAObjectBase *new_object = (PYAObjectBase *) Py_TYPE (self)->tp_alloc (Py_TYPE (self), 0);
|
||||
PyObject *new_object = Py_TYPE (self)->tp_alloc (Py_TYPE (self), 0);
|
||||
PythonRef obj (new_object);
|
||||
new (new_object) PYAObjectBase (cls_decl_self);
|
||||
new_object->set (cls_decl_self->clone (((PYAObjectBase *) self)->obj ()), true, false, false);
|
||||
PYAObjectBase *new_pya_base = PYAObjectBase::from_pyobject_unsafe (new_object);
|
||||
new (new_pya_base) PYAObjectBase (cls_decl_self, new_object);
|
||||
new_pya_base->set (cls_decl_self->clone (PYAObjectBase::from_pyobject (self)->obj ()), true, false, false);
|
||||
|
||||
return obj.release ();
|
||||
}
|
||||
|
|
@ -901,7 +903,7 @@ object_assign (PyObject *self, PyObject *args)
|
|||
throw tl::Exception (tl::to_string (tr ("No assignment provided for class '%s'")), cls_decl_self->name ());
|
||||
}
|
||||
|
||||
cls_decl_self->assign (((PYAObjectBase *) self)->obj (), ((PYAObjectBase *) src)->obj ());
|
||||
cls_decl_self->assign ((PYAObjectBase::from_pyobject (self))->obj (), (PYAObjectBase::from_pyobject (src))->obj ());
|
||||
|
||||
Py_INCREF (self);
|
||||
return self;
|
||||
|
|
@ -997,7 +999,7 @@ object_create (PyObject *self, PyObject *args)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
((PYAObjectBase *) self)->obj ();
|
||||
(PYAObjectBase::from_pyobject (self))->obj ();
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
|
@ -1011,7 +1013,7 @@ object_release (PyObject *self, PyObject *args)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
((PYAObjectBase *) self)->release ();
|
||||
(PYAObjectBase::from_pyobject (self))->release ();
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
|
@ -1025,7 +1027,7 @@ object_keep (PyObject *self, PyObject *args)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
((PYAObjectBase *) self)->keep ();
|
||||
(PYAObjectBase::from_pyobject (self))->keep ();
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
|
@ -1039,7 +1041,7 @@ object_destroy (PyObject *self, PyObject *args)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
((PYAObjectBase *) self)->destroy ();
|
||||
(PYAObjectBase::from_pyobject (self))->destroy ();
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
|
@ -1053,7 +1055,7 @@ object_destroyed (PyObject *self, PyObject *args)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
return c2python (((PYAObjectBase *) self)->destroyed ());
|
||||
return c2python (PYAObjectBase::from_pyobject (self)->destroyed ());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1066,7 +1068,7 @@ object_is_const (PyObject *self, PyObject *args)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
return c2python (((PYAObjectBase *) self)->const_ref ());
|
||||
return c2python (PYAObjectBase::from_pyobject (self)->const_ref ());
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
|
|
@ -1112,7 +1114,7 @@ method_adaptor (int mid, PyObject *self, PyObject *args)
|
|||
PYAObjectBase *p = 0;
|
||||
if (! PyType_Check (self)) {
|
||||
// non-static method
|
||||
p = (PYAObjectBase *) self;
|
||||
p = PYAObjectBase::from_pyobject (self);
|
||||
}
|
||||
|
||||
tl::Heap heap;
|
||||
|
|
@ -1666,7 +1668,7 @@ method_init_adaptor (int mid, PyObject *self, PyObject *args)
|
|||
{
|
||||
PYA_TRY
|
||||
|
||||
PYAObjectBase *p = (PYAObjectBase *) self;
|
||||
PYAObjectBase *p = PYAObjectBase::from_pyobject (self);
|
||||
|
||||
// delete any object which we may have already
|
||||
if (p->is_attached ()) {
|
||||
|
|
@ -1888,7 +1890,7 @@ property_getter_impl (int mid, PyObject *self)
|
|||
|
||||
PYAObjectBase *p = 0;
|
||||
if (! PyType_Check (self)) {
|
||||
p = (PYAObjectBase *) self;
|
||||
p = PYAObjectBase::from_pyobject (self);
|
||||
cls_decl = p->cls_decl ();
|
||||
} else {
|
||||
cls_decl = PythonModule::cls_for_type ((PyTypeObject *) self);
|
||||
|
|
@ -1969,7 +1971,7 @@ property_setter_impl (int mid, PyObject *self, PyObject *value)
|
|||
|
||||
PYAObjectBase *p = 0;
|
||||
if (! PyType_Check (self)) {
|
||||
p = (PYAObjectBase *) self;
|
||||
p = PYAObjectBase::from_pyobject (self);
|
||||
cls_decl = p->cls_decl ();
|
||||
} else {
|
||||
cls_decl = PythonModule::cls_for_type ((PyTypeObject *) self);
|
||||
|
|
@ -2156,7 +2158,6 @@ PythonModule::~PythonModule ()
|
|||
// the Python objects were probably deleted by Python itself as it exited -
|
||||
// don't try to delete them again.
|
||||
mp_module.release ();
|
||||
mp_base_class.release ();
|
||||
|
||||
while (!m_methods_heap.empty ()) {
|
||||
delete m_methods_heap.back ();
|
||||
|
|
@ -2339,36 +2340,6 @@ PythonModule::make_classes (const char *mod_name)
|
|||
|
||||
PyObject_SetAttrString (module, "__doc__", PythonRef (c2python (m_mod_description)).get ());
|
||||
|
||||
// Create a (built-in) base class for all objects exposed by this module
|
||||
|
||||
m_base_class_name = m_mod_name + ".__Base";
|
||||
|
||||
PyTypeObject *base_class = (PyTypeObject *) PyType_Type.tp_alloc (&PyType_Type, 0);
|
||||
tl_assert (base_class != NULL);
|
||||
mp_base_class = PythonRef ((PyObject *) base_class);
|
||||
|
||||
base_class->tp_base = &PyBaseObject_Type;
|
||||
base_class->tp_name = m_base_class_name.c_str ();
|
||||
base_class->tp_basicsize = sizeof (PYAObjectBase);
|
||||
base_class->tp_init = &pya_object_init;
|
||||
base_class->tp_new = &pya_object_new;
|
||||
base_class->tp_dealloc = (destructor) &pya_object_deallocate;
|
||||
base_class->tp_setattro = PyObject_GenericSetAttr;
|
||||
base_class->tp_getattro = PyObject_GenericGetAttr;
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
base_class->tp_flags = Py_TPFLAGS_HEAPTYPE | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES;
|
||||
#else
|
||||
base_class->tp_flags = Py_TPFLAGS_HEAPTYPE | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
|
||||
#endif
|
||||
|
||||
if (PyType_Ready (base_class) < 0) {
|
||||
check_error ();
|
||||
return;
|
||||
}
|
||||
|
||||
PyModule_AddObject (module, "__Base", (PyObject *) base_class);
|
||||
|
||||
|
||||
// Build a class for descriptors for static attributes
|
||||
PYAStaticAttributeDescriptorObject::make_class (module);
|
||||
|
||||
|
|
@ -2434,15 +2405,17 @@ PythonModule::make_classes (const char *mod_name)
|
|||
|
||||
m_classes.push_back (c.operator-> ());
|
||||
|
||||
PythonRef bases (PyTuple_New (1));
|
||||
PyObject *base = mp_base_class.get ();
|
||||
PythonRef bases;
|
||||
if (c->base () != 0) {
|
||||
bases = PythonRef (PyTuple_New (1));
|
||||
PyTypeObject *pt = PythonClassClientData::py_type (*c->base ());
|
||||
tl_assert (pt != 0);
|
||||
base = (PyObject *) pt;
|
||||
PyObject *base = (PyObject *) pt;
|
||||
Py_INCREF (base);
|
||||
PyTuple_SetItem (bases.get (), 0, base);
|
||||
} else {
|
||||
bases = PythonRef (PyTuple_New (0));
|
||||
}
|
||||
Py_INCREF (base);
|
||||
PyTuple_SetItem (bases.get (), 0, base);
|
||||
|
||||
PythonRef dict (PyDict_New ());
|
||||
PyDict_SetItemString (dict.get (), "__module__", PythonRef (c2python (m_mod_name)).get ());
|
||||
|
|
@ -2459,9 +2432,18 @@ PythonModule::make_classes (const char *mod_name)
|
|||
check_error ();
|
||||
tl_assert (false);
|
||||
}
|
||||
|
||||
// Customize
|
||||
type->tp_basicsize += sizeof (PYAObjectBase);
|
||||
type->tp_init = &pya_object_init;
|
||||
type->tp_new = &pya_object_new;
|
||||
type->tp_dealloc = (destructor) &pya_object_deallocate;
|
||||
type->tp_setattro = PyObject_GenericSetAttr;
|
||||
type->tp_getattro = PyObject_GenericGetAttr;
|
||||
|
||||
PythonClassClientData::initialize (*c, type);
|
||||
|
||||
tl_assert (cls_for_type (type) == c.operator-> ()); // @@@
|
||||
tl_assert (cls_for_type (type) == c.operator-> ());
|
||||
|
||||
PyList_Append (all_list.get (), PythonRef (c2python (c->name ())).get ());
|
||||
PyModule_AddObject (module, c->name ().c_str (), (PyObject *) type);
|
||||
|
|
|
|||
|
|
@ -120,9 +120,7 @@ private:
|
|||
std::vector<PyGetSetDef *> m_getseters_heap;
|
||||
|
||||
std::string m_mod_name, m_mod_description;
|
||||
std::string m_base_class_name;
|
||||
PythonRef mp_module;
|
||||
PythonRef mp_base_class;
|
||||
char *mp_mod_def;
|
||||
|
||||
static std::map<const gsi::MethodBase *, std::string> m_python_doc;
|
||||
|
|
|
|||
|
|
@ -129,8 +129,8 @@ Callee::call (int id, gsi::SerialArgs &args, gsi::SerialArgs &ret) const
|
|||
PythonRef argv (PyTuple_New (arg4self + std::distance (meth->begin_arguments (), meth->end_arguments ())));
|
||||
|
||||
// Put self into first argument
|
||||
PyTuple_SetItem (argv.get (), 0, mp_obj);
|
||||
Py_INCREF (mp_obj);
|
||||
PyTuple_SetItem (argv.get (), 0, mp_obj->py_object ());
|
||||
Py_INCREF (mp_obj->py_object ());
|
||||
|
||||
// TODO: callbacks with default arguments?
|
||||
for (gsi::MethodBase::argument_iterator a = meth->begin_arguments (); args && a != meth->end_arguments (); ++a) {
|
||||
|
|
@ -169,8 +169,9 @@ Callee::call (int id, gsi::SerialArgs &args, gsi::SerialArgs &ret) const
|
|||
// --------------------------------------------------------------------------
|
||||
// Implementation of PYAObjectBase
|
||||
|
||||
PYAObjectBase::PYAObjectBase(const gsi::ClassBase *_cls_decl)
|
||||
: m_listener (new pya::StatusChangedListener (this)),
|
||||
PYAObjectBase::PYAObjectBase(const gsi::ClassBase *_cls_decl, PyObject *py_object)
|
||||
: mp_py_object (py_object),
|
||||
m_listener (new pya::StatusChangedListener (this)),
|
||||
m_callee (new pya::Callee (this)),
|
||||
m_cls_decl (_cls_decl),
|
||||
m_obj (0),
|
||||
|
|
@ -179,6 +180,7 @@ PYAObjectBase::PYAObjectBase(const gsi::ClassBase *_cls_decl)
|
|||
m_destroyed (false),
|
||||
m_can_destroy (false)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
PYAObjectBase::~PYAObjectBase ()
|
||||
|
|
@ -223,7 +225,7 @@ PYAObjectBase::object_destroyed ()
|
|||
|
||||
// NOTE: this may delete "this"!
|
||||
if (!prev_owner) {
|
||||
Py_DECREF (this);
|
||||
Py_DECREF (py_object ());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -246,7 +248,7 @@ PYAObjectBase::release ()
|
|||
if (!m_owned) {
|
||||
m_owned = true;
|
||||
// NOTE: this may delete "this"! TODO: this should not happen. Can we assert that somehow?
|
||||
Py_DECREF (this);
|
||||
Py_DECREF (py_object ());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -254,7 +256,7 @@ void
|
|||
PYAObjectBase::keep_internal ()
|
||||
{
|
||||
if (m_owned) {
|
||||
Py_INCREF (this);
|
||||
Py_INCREF (py_object ());
|
||||
m_owned = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -328,7 +330,7 @@ PYAObjectBase::set (void *obj, bool owned, bool const_ref, bool can_destroy)
|
|||
}
|
||||
|
||||
if (!m_owned) {
|
||||
Py_INCREF (this);
|
||||
Py_INCREF (py_object ());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -353,7 +355,7 @@ PYAObjectBase::initialize_callbacks ()
|
|||
// TODO: caching appears to create some leaks ...
|
||||
#if 1
|
||||
|
||||
PythonRef type_ref ((PyObject *) Py_TYPE (this), false /*borrowed*/);
|
||||
PythonRef type_ref ((PyObject *) Py_TYPE (py_object ()), false /*borrowed*/);
|
||||
|
||||
// Locate the callback-enabled methods set by Python tpye object (pointer)
|
||||
// NOTE: I'm not quite sure whether the type object pointer is a good key
|
||||
|
|
@ -391,7 +393,7 @@ PYAObjectBase::initialize_callbacks ()
|
|||
// TOOD: That may happen too often, i.e. if the Python class does not reimplement the virtual
|
||||
// method, but the C++ class defines a method hook that the reimplementation can call.
|
||||
// We don't want to produce a lot of overhead for the Qt classes here.
|
||||
PythonRef py_attr = PyObject_GetAttrString ((PyObject *) Py_TYPE (this), nstr);
|
||||
PythonRef py_attr = PyObject_GetAttrString ((PyObject *) Py_TYPE (py_object ()), nstr);
|
||||
if (! py_attr) {
|
||||
|
||||
// because PyObject_GetAttrString left an error
|
||||
|
|
@ -423,7 +425,7 @@ PYAObjectBase::initialize_callbacks ()
|
|||
|
||||
PythonRef py_attr;
|
||||
const char *nstr = (*m)->primary_name ().c_str ();
|
||||
py_attr = PyObject_GetAttrString ((PyObject *) Py_TYPE (this), nstr);
|
||||
py_attr = PyObject_GetAttrString ((PyObject *) Py_TYPE (py_object ()), nstr);
|
||||
|
||||
int id = m_callee->add_callback (CallbackFunction (py_attr, *m));
|
||||
(*m)->set_callback (m_obj, gsi::Callback (id, m_callee.get (), (*m)->argsize (), (*m)->retsize ()));
|
||||
|
|
@ -458,7 +460,7 @@ PYAObjectBase::initialize_callbacks ()
|
|||
// TOOD: That may happen too often, i.e. if the Python class does not reimplement the virtual
|
||||
// method, but the C++ class defines a method hook that the reimplementation can call.
|
||||
// We don't want to produce a lot of overhead for the Qt classes here.
|
||||
PythonRef py_attr = PyObject_GetAttrString ((PyObject *) Py_TYPE (this), nstr);
|
||||
PythonRef py_attr = PyObject_GetAttrString ((PyObject *) Py_TYPE (py_object ()), nstr);
|
||||
if (! py_attr) {
|
||||
|
||||
// because PyObject_GetAttrString left an error
|
||||
|
|
@ -471,7 +473,7 @@ PYAObjectBase::initialize_callbacks ()
|
|||
// may create issues with callbacks during destruction (i.e. QWidget-destroyed signal)
|
||||
if (! PyCFunction_Check (py_attr.get ())) {
|
||||
|
||||
PyObject *py_attr = PyObject_GetAttrString ((PyObject *) Py_TYPE (this), nstr);
|
||||
PyObject *py_attr = PyObject_GetAttrString ((PyObject *) Py_TYPE (py_object ()), nstr);
|
||||
tl_assert (py_attr != NULL);
|
||||
int id = m_callee.add_callback (CallbackFunction (py_attr, *m));
|
||||
(*m)->set_callback (m_obj, gsi::Callback (id, &m_callee, (*m)->argsize (), (*m)->retsize ()));
|
||||
|
|
@ -501,7 +503,7 @@ PYAObjectBase::clear_callbacks_cache ()
|
|||
void
|
||||
PYAObjectBase::detach_callbacks ()
|
||||
{
|
||||
PythonRef type_ref ((PyObject *) Py_TYPE (this), false /*borrowed*/);
|
||||
PythonRef type_ref ((PyObject *) Py_TYPE (py_object ()), false /*borrowed*/);
|
||||
|
||||
callbacks_cache::iterator cb = s_callbacks_cache.find (type_ref);
|
||||
if (cb != s_callbacks_cache.end ()) {
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@
|
|||
#include "pyaRefs.h"
|
||||
#include "pyaCommon.h"
|
||||
|
||||
#include "tlAssert.h"
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
|
@ -50,23 +52,43 @@ class StatusChangedListener;
|
|||
/**
|
||||
* @brief The Python object representing a GSI object
|
||||
*
|
||||
* Note: the PYAObjectBase must be directly derived from PyObject so that
|
||||
* a PyObject pointer can be cast to a PYAObjectBase pointer.
|
||||
* NOTE: this memory block is attached to the actual structure
|
||||
* and obtained by taking the last sizeof(PYAObjectBase) bytes.
|
||||
* It's basically a connector between GSI objects and the Python
|
||||
* objects.
|
||||
*/
|
||||
class PYA_PUBLIC PYAObjectBase
|
||||
: public PyObject
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor - creates a new object for the given GSI class
|
||||
*/
|
||||
PYAObjectBase (const gsi::ClassBase *_cls_decl);
|
||||
PYAObjectBase (const gsi::ClassBase *_cls_decl, PyObject *py_object);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~PYAObjectBase ();
|
||||
|
||||
/**
|
||||
* @brief Gets the PYAObjectBase pointer from a PyObject pointer
|
||||
*/
|
||||
static PYAObjectBase *from_pyobject (PyObject *py_object)
|
||||
{
|
||||
PYAObjectBase *pya_object = (PYAObjectBase *)((char *) py_object + Py_TYPE (py_object)->tp_basicsize - sizeof (PYAObjectBase));
|
||||
tl_assert (pya_object->py_object () == py_object);
|
||||
return pya_object;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the PYAObjectBase pointer from a PyObject pointer
|
||||
* This version doesn't check anything.
|
||||
*/
|
||||
static PYAObjectBase *from_pyobject_unsafe (PyObject *py_object)
|
||||
{
|
||||
return (PYAObjectBase *)((char *) py_object + Py_TYPE (py_object)->tp_basicsize - sizeof (PYAObjectBase));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Indicates that a C++ object is present
|
||||
*/
|
||||
|
|
@ -142,6 +164,14 @@ public:
|
|||
m_const_ref = c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the Python object for this bridge object
|
||||
*/
|
||||
PyObject *py_object () const
|
||||
{
|
||||
return mp_py_object;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the C++ object reference
|
||||
*/
|
||||
|
|
@ -189,6 +219,7 @@ private:
|
|||
void object_destroyed ();
|
||||
void keep_internal ();
|
||||
|
||||
PyObject *mp_py_object;
|
||||
std::auto_ptr<StatusChangedListener> m_listener;
|
||||
std::auto_ptr<Callee> m_callee;
|
||||
const gsi::ClassBase *m_cls_decl;
|
||||
|
|
|
|||
|
|
@ -2718,6 +2718,7 @@ class BasicTest(unittest.TestCase):
|
|||
go = None
|
||||
self.assertEqual(pya.GObject.g_inst_count(), gc)
|
||||
|
||||
|
||||
# run unit tests
|
||||
if __name__ == '__main__':
|
||||
suite = unittest.TestSuite()
|
||||
|
|
|
|||
Loading…
Reference in New Issue