diff --git a/src/pya/pya/pyaConvert.cc b/src/pya/pya/pyaConvert.cc index 2d771a2e5..41d28cf2c 100644 --- a/src/pya/pya/pyaConvert.cc +++ b/src/pya/pya/pyaConvert.cc @@ -291,7 +291,7 @@ tl::Variant python2c_func::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; } } diff --git a/src/pya/pya/pyaConvert.h b/src/pya/pya/pyaConvert.h index 57e0dccf2..8aab23136 100644 --- a/src/pya/pya/pyaConvert.h +++ b/src/pya/pya/pyaConvert.h @@ -352,7 +352,7 @@ template struct python2c_func 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 ()); } }; diff --git a/src/pya/pya/pyaMarshal.cc b/src/pya/pya/pyaMarshal.cc index 719ff51e1..0b265280d 100644 --- a/src/pya/pya/pyaMarshal.cc +++ b/src/pya/pya/pyaMarshal.cc @@ -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 (p->obj ()); if (bo) { *ret = bo->value ().template morph ().native_ptr (); @@ -389,7 +389,7 @@ struct writer 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 } 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 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 } else if (cls_decl->can_convert_to (atype.cls ())) { - PYAObjectBase *p = (PYAObjectBase *) (arg); + PYAObjectBase *p = PYAObjectBase::from_pyobject (arg); aa->write (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 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 (*heap)); @@ -506,7 +506,7 @@ struct reader template <> 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) { tl_assert (! arg.is_cref ()); tl_assert (! arg.is_ref ()); diff --git a/src/pya/pya/pyaModule.cc b/src/pya/pya/pyaModule.cc index 40b5ed262..793f4f2ad 100644 --- a/src/pya/pya/pyaModule.cc +++ b/src/pya/pya/pyaModule.cc @@ -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 (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); diff --git a/src/pya/pya/pyaModule.h b/src/pya/pya/pyaModule.h index 85515e7d6..f06ab4676 100644 --- a/src/pya/pya/pyaModule.h +++ b/src/pya/pya/pyaModule.h @@ -120,9 +120,7 @@ private: std::vector 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 m_python_doc; diff --git a/src/pya/pya/pyaObject.cc b/src/pya/pya/pyaObject.cc index ca247173e..ae9fd624d 100644 --- a/src/pya/pya/pyaObject.cc +++ b/src/pya/pya/pyaObject.cc @@ -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 ()) { diff --git a/src/pya/pya/pyaObject.h b/src/pya/pya/pyaObject.h index fa0023f8b..9e59c8790 100644 --- a/src/pya/pya/pyaObject.h +++ b/src/pya/pya/pyaObject.h @@ -29,6 +29,8 @@ #include "pyaRefs.h" #include "pyaCommon.h" +#include "tlAssert.h" + #include #include #include @@ -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 m_listener; std::auto_ptr m_callee; const gsi::ClassBase *m_cls_decl; diff --git a/testdata/python/basic.py b/testdata/python/basic.py index 1fca4191e..eb495d0c8 100644 --- a/testdata/python/basic.py +++ b/testdata/python/basic.py @@ -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()