This commit is contained in:
Daniel Wang 2018-07-19 19:23:00 -04:00
commit c430c82744
No known key found for this signature in database
GPG Key ID: 82968CE7F0EA634E
8 changed files with 114 additions and 99 deletions

View File

@ -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;
}
}

View File

@ -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 ());
}
};

View File

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

View File

@ -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);

View File

@ -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;

View File

@ -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 ()) {

View File

@ -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;

View File

@ -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()