1
0
mirror of https://github.com/samba-team/samba.git synced 2025-03-27 22:50:26 +03:00

pytalloc: Add new BaseObject

This new object not only avoids the ABI issues of talloc.Object
it stores one more pointer, being the start of the array, and
so can be used to fix the PIDL bindings/talloc refcount issue.

Signed-off-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Garming Sam <garming@catalyst.net.nz>
This commit is contained in:
Andrew Bartlett 2016-02-22 14:02:28 +13:00
parent 528dce1b53
commit 80f2b36efb
7 changed files with 434 additions and 32 deletions

View File

@ -20,6 +20,7 @@
#include <Python.h>
#include <talloc.h>
#include <pytalloc.h>
#include "pytalloc_private.h"
static PyTypeObject TallocObject_Type;
@ -157,6 +158,86 @@ static PyTypeObject TallocObject_Type = {
#endif
};
/**
* Default (but only slightly more useful than the default) implementation of Repr().
*/
static PyObject *pytalloc_base_default_repr(PyObject *obj)
{
pytalloc_BaseObject *talloc_obj = (pytalloc_BaseObject *)obj;
PyTypeObject *type = (PyTypeObject*)PyObject_Type(obj);
return PyStr_FromFormat("<%s talloc based object at 0x%p>",
type->tp_name, talloc_obj->ptr);
}
/**
* Simple dealloc for talloc-wrapping PyObjects
*/
static void pytalloc_base_dealloc(PyObject* self)
{
pytalloc_BaseObject *obj = (pytalloc_BaseObject *)self;
assert(talloc_unlink(NULL, obj->talloc_ctx) != -1);
obj->talloc_ctx = NULL;
self->ob_type->tp_free(self);
}
/**
* Default (but only slightly more useful than the default) implementation of cmp.
*/
#if PY_MAJOR_VERSION >= 3
static PyObject *pytalloc_base_default_richcmp(PyObject *obj1, PyObject *obj2, int op)
{
void *ptr1;
void *ptr2;
if (Py_TYPE(obj1) == Py_TYPE(obj2)) {
/* When types match, compare pointers */
ptr1 = pytalloc_get_ptr(obj1);
ptr2 = pytalloc_get_ptr(obj2);
} else if (PyObject_TypeCheck(obj2, &TallocObject_Type)) {
/* Otherwise, compare types */
ptr1 = Py_TYPE(obj1);
ptr2 = Py_TYPE(obj2);
} else {
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
switch (op) {
case Py_EQ: return PyBool_FromLong(ptr1 == ptr2);
case Py_NE: return PyBool_FromLong(ptr1 != ptr2);
case Py_LT: return PyBool_FromLong(ptr1 < ptr2);
case Py_GT: return PyBool_FromLong(ptr1 > ptr2);
case Py_LE: return PyBool_FromLong(ptr1 <= ptr2);
case Py_GE: return PyBool_FromLong(ptr1 >= ptr2);
}
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
#else
static int pytalloc_base_default_cmp(PyObject *_obj1, PyObject *_obj2)
{
pytalloc_BaseObject *obj1 = (pytalloc_BaseObject *)_obj1,
*obj2 = (pytalloc_BaseObject *)_obj2;
if (obj1->ob_type != obj2->ob_type)
return ((char *)obj1->ob_type - (char *)obj2->ob_type);
return ((char *)pytalloc_get_ptr(obj1) - (char *)pytalloc_get_ptr(obj2));
}
#endif
static PyTypeObject TallocBaseObject_Type = {
.tp_name = "talloc.BaseObject",
.tp_doc = "Python wrapper for a talloc-maintained object.",
.tp_basicsize = sizeof(pytalloc_BaseObject),
.tp_dealloc = (destructor)pytalloc_base_dealloc,
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
.tp_repr = pytalloc_base_default_repr,
#if PY_MAJOR_VERSION >= 3
.tp_richcompare = pytalloc_base_default_richcmp,
#else
.tp_compare = pytalloc_base_default_cmp,
#endif
};
#define MODULE_DOC PyDoc_STR("Python wrapping of talloc-maintained objects.")
#if PY_MAJOR_VERSION >= 3
@ -177,6 +258,9 @@ static PyObject *module_init(void)
if (PyType_Ready(&TallocObject_Type) < 0)
return NULL;
if (PyType_Ready(&TallocBaseObject_Type) < 0)
return NULL;
#if PY_MAJOR_VERSION >= 3
m = PyModule_Create(&moduledef);
#else
@ -187,6 +271,8 @@ static PyObject *module_init(void)
Py_INCREF(&TallocObject_Type);
PyModule_AddObject(m, "Object", (PyObject *)&TallocObject_Type);
Py_INCREF(&TallocBaseObject_Type);
PyModule_AddObject(m, "BaseObject", (PyObject *)&TallocBaseObject_Type);
return m;
}

View File

@ -26,15 +26,20 @@
typedef struct {
PyObject_HEAD
TALLOC_CTX *talloc_ctx;
void *ptr;
void *ptr; /* eg the array element */
} pytalloc_Object;
/* Return the PyTypeObject for pytalloc_Object. Returns a new reference. */
PyTypeObject *pytalloc_GetObjectType(void);
/* Return the PyTypeObject for pytalloc_BaseObject. Returns a new reference. */
PyTypeObject *pytalloc_GetBaseObjectType(void);
/* Check whether a specific object is a talloc Object. */
int pytalloc_Check(PyObject *);
int pytalloc_BaseObject_check(PyObject *);
/* Retrieve the pointer for a pytalloc_object. Like talloc_get_type()
* but for pytalloc_Objects. */
void *_pytalloc_get_type(PyObject *py_obj, const char *type_name);
@ -56,4 +61,7 @@ PyObject *pytalloc_reference_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx, void
PyObject *pytalloc_CObject_FromTallocPtr(void *);
#endif
size_t pytalloc_BaseObject_size(void);
#endif /* _PYTALLOC_H_ */

View File

@ -29,7 +29,7 @@ Python's PEP3149 ABI tag, for example "pytalloc.cpython34m".
To make a build for Python 3, configure with PYTHON=/usr/bin/python3.
.
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
pytalloc_Object
pytalloc_Object / pytalloc_BaseObject
This is the new base class that all Python objects that wrap talloc pointers
derive from. It is itself a subclass of the "Object" type that all objects
@ -53,6 +53,10 @@ compares the pointers the object is wrapping rather than the objects
themselves (since there can be multiple objects that wrap the same talloc
pointer).
It is preferred to use pytalloc_BaseObject as this implementation
exposes less in the C ABI and correctly supports pointers in C arrays
in the way needed by PIDL.
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
PyTypeObject *pytalloc_GetObjectType(void)
@ -60,12 +64,25 @@ Obtain a reference to the PyTypeObject for `pytalloc_Object`. The reference
counter for the object will be incremented, so the caller will have to
decrement it when it no longer needs it (using `Py_DECREF`).
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
PyTypeObject *pytalloc_GetBaseObjectType(void)
Obtain a reference to the PyTypeObject for `pytalloc_Object`. The reference
counter for the object will be incremented, so the caller will have to
decrement it when it no longer needs it (using `Py_DECREF`).
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-
int pytalloc_Check(PyObject *)
Check whether a specific object is a talloc Object. Returns non-zero if it is
a pytalloc_Object and zero otherwise.
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-
int pytalloc_BaseObject_Check(PyObject *)
Check whether a specific object is a talloc BaseObject. Returns non-zero if it is
a pytalloc_BaseObject and zero otherwise.
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
type *pytalloc_get_type(PyObject *py_obj, type)
@ -75,13 +92,14 @@ C type, similar to a type passed to `talloc_get_type`.
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
pytalloc_get_ptr(PyObject *py_obj)
Retrieve the pointer from a `pytalloc_Object` py_obj. There is no
type checking - use `pytalloc_get_type` if possible.
Retrieve the pointer from a `pytalloc_Object` or `pytalloc_BaseObject`
py_obj. There is no type checking - use `pytalloc_get_type` if
possible.
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
TALLOC_CTX *pytalloc_get_mem_ctx(PyObject *py_obj)
Retrieve the talloc context associated with a pytalloc_Object.
Retrieve the talloc context associated with a pytalloc_Object or pytalloc_BaseObject.
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
PyObject *pytalloc_steal_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx, void *ptr)

View File

@ -0,0 +1,26 @@
/*
Unix SMB/CIFS implementation.
Samba utility functions
Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2016
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
typedef struct {
PyObject_HEAD
TALLOC_CTX *talloc_ctx;
TALLOC_CTX *talloc_ptr_ctx; /* eg the start of the array */
void *ptr; /* eg the array element */
} pytalloc_BaseObject;

View File

@ -22,6 +22,7 @@
#include <talloc.h>
#include "pytalloc.h"
#include <assert.h>
#include "pytalloc_private.h"
_PUBLIC_ PyTypeObject *pytalloc_GetObjectType(void)
{
@ -43,23 +44,82 @@ _PUBLIC_ PyTypeObject *pytalloc_GetObjectType(void)
return type;
}
_PUBLIC_ PyTypeObject *pytalloc_GetBaseObjectType(void)
{
static PyTypeObject *type = NULL;
PyObject *mod;
if (type != NULL) {
return type;
}
mod = PyImport_ImportModule("talloc");
if (mod == NULL) {
return NULL;
}
type = (PyTypeObject *)PyObject_GetAttrString(mod, "BaseObject");
Py_DECREF(mod);
return type;
}
/**
* Import an existing talloc pointer into a Python object.
*/
_PUBLIC_ PyObject *pytalloc_steal_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx,
void *ptr)
void *ptr)
{
pytalloc_Object *ret = (pytalloc_Object *)py_type->tp_alloc(py_type, 0);
ret->talloc_ctx = talloc_new(NULL);
if (ret->talloc_ctx == NULL) {
PyTypeObject *BaseObjectType = pytalloc_GetBaseObjectType();
PyTypeObject *ObjectType = pytalloc_GetObjectType();
if (mem_ctx == NULL) {
return PyErr_NoMemory();
}
if (PyType_IsSubtype(py_type, BaseObjectType)) {
pytalloc_BaseObject *ret
= (pytalloc_BaseObject *)py_type->tp_alloc(py_type, 0);
ret->talloc_ctx = talloc_new(NULL);
if (ret->talloc_ctx == NULL) {
return NULL;
}
/*
* This allows us to keep multiple references to this object -
* we only reference this context, which is per ptr, not the
* talloc_ctx, which is per pytalloc_Object
*/
if (talloc_steal(ret->talloc_ctx, mem_ctx) == NULL) {
return NULL;
}
ret->talloc_ptr_ctx = mem_ctx;
talloc_set_name_const(ret->talloc_ctx, py_type->tp_name);
ret->ptr = ptr;
return (PyObject *)ret;
} else if (PyType_IsSubtype(py_type, ObjectType)) {
pytalloc_Object *ret
= (pytalloc_Object *)py_type->tp_alloc(py_type, 0);
ret->talloc_ctx = talloc_new(NULL);
if (ret->talloc_ctx == NULL) {
return NULL;
}
if (talloc_steal(ret->talloc_ctx, mem_ctx) == NULL) {
return NULL;
}
talloc_set_name_const(ret->talloc_ctx, py_type->tp_name);
ret->ptr = ptr;
return (PyObject *)ret;
} else {
PyErr_SetString(PyExc_RuntimeError,
"pytalloc_steal_ex() called for object type "
"not based on talloc");
return NULL;
}
if (talloc_steal(ret->talloc_ctx, mem_ctx) == NULL) {
return NULL;
}
talloc_set_name_const(ret->talloc_ctx, py_type->tp_name);
ret->ptr = ptr;
return (PyObject *)ret;
}
/**
@ -74,27 +134,57 @@ _PUBLIC_ PyObject *pytalloc_steal(PyTypeObject *py_type, void *ptr)
/**
* Import an existing talloc pointer into a Python object, leaving the
* original parent, and creating a reference to the object in the python
* object
* object.
*
* We remember the object we hold the reference to (a
* possibly-non-talloc pointer), the existing parent (typically the
* start of the array) and the new referenced parent. That way we can
* cope with the fact that we will have multiple parents, one per time
* python sees the object.
*/
_PUBLIC_ PyObject *pytalloc_reference_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx, void *ptr)
_PUBLIC_ PyObject *pytalloc_reference_ex(PyTypeObject *py_type,
TALLOC_CTX *mem_ctx, void *ptr)
{
pytalloc_Object *ret;
PyTypeObject *BaseObjectType = pytalloc_GetBaseObjectType();
PyTypeObject *ObjectType = pytalloc_GetObjectType();
if (ptr == NULL) {
Py_RETURN_NONE;
if (mem_ctx == NULL) {
return PyErr_NoMemory();
}
ret = (pytalloc_Object *)py_type->tp_alloc(py_type, 0);
ret->talloc_ctx = talloc_new(NULL);
if (ret->talloc_ctx == NULL) {
if (PyType_IsSubtype(py_type, BaseObjectType)) {
pytalloc_BaseObject *ret
= (pytalloc_BaseObject *)py_type->tp_alloc(py_type, 0);
ret->talloc_ctx = talloc_new(NULL);
if (ret->talloc_ctx == NULL) {
return NULL;
}
if (talloc_reference(ret->talloc_ctx, mem_ctx) == NULL) {
return NULL;
}
talloc_set_name_const(ret->talloc_ctx, py_type->tp_name);
ret->talloc_ptr_ctx = mem_ctx;
ret->ptr = ptr;
return (PyObject *)ret;
} else if (PyType_IsSubtype(py_type, ObjectType)) {
pytalloc_Object *ret
= (pytalloc_Object *)py_type->tp_alloc(py_type, 0);
ret->talloc_ctx = talloc_new(NULL);
if (ret->talloc_ctx == NULL) {
return NULL;
}
if (talloc_reference(ret->talloc_ctx, mem_ctx) == NULL) {
return NULL;
}
talloc_set_name_const(ret->talloc_ctx, py_type->tp_name);
ret->ptr = ptr;
return (PyObject *)ret;
} else {
PyErr_SetString(PyExc_RuntimeError,
"pytalloc_reference_ex() called for object type "
"not based on talloc");
return NULL;
}
if (talloc_reference(ret->talloc_ctx, mem_ctx) == NULL) {
return NULL;
}
talloc_set_name_const(ret->talloc_ctx, py_type->tp_name);
ret->ptr = ptr;
return (PyObject *)ret;
}
#if PY_MAJOR_VERSION < 3
@ -121,6 +211,18 @@ _PUBLIC_ int pytalloc_Check(PyObject *obj)
return PyObject_TypeCheck(obj, tp);
}
_PUBLIC_ int pytalloc_BaseObject_check(PyObject *obj)
{
PyTypeObject *tp = pytalloc_GetBaseObjectType();
return PyObject_TypeCheck(obj, tp);
}
_PUBLIC_ size_t pytalloc_BaseObject_size(void)
{
return sizeof(pytalloc_BaseObject);
}
_PUBLIC_ void *_pytalloc_get_type(PyObject *py_obj, const char *type_name)
{
void *ptr = _pytalloc_get_ptr(py_obj);
@ -138,10 +240,22 @@ _PUBLIC_ void *_pytalloc_get_type(PyObject *py_obj, const char *type_name)
_PUBLIC_ void *_pytalloc_get_ptr(PyObject *py_obj)
{
return ((pytalloc_Object *)py_obj)->ptr;
if (pytalloc_BaseObject_check(py_obj)) {
return ((pytalloc_BaseObject *)py_obj)->ptr;
}
if (pytalloc_Check(py_obj)) {
return ((pytalloc_Object *)py_obj)->ptr;
}
return NULL;
}
_PUBLIC_ TALLOC_CTX *_pytalloc_get_mem_ctx(PyObject *py_obj)
{
return ((pytalloc_Object *)py_obj)->talloc_ctx;
if (pytalloc_BaseObject_check(py_obj)) {
return ((pytalloc_BaseObject *)py_obj)->talloc_ptr_ctx;
}
if (pytalloc_Check(py_obj)) {
return ((pytalloc_Object *)py_obj)->talloc_ctx;
}
return NULL;
}

View File

@ -42,6 +42,18 @@ static PyObject *testpytalloc_get_object_type(PyObject *mod) {
return type;
}
static PyObject *testpytalloc_base_new(PyTypeObject *mod)
{
char *obj = talloc_strdup(NULL, "This is a test string for a BaseObject");;
return pytalloc_steal(pytalloc_GetBaseObjectType(), obj);
}
static PyObject *testpytalloc_base_get_object_type(PyObject *mod) {
PyObject *type = (PyObject *)pytalloc_GetBaseObjectType();
Py_INCREF(type);
return type;
}
static PyObject *testpytalloc_reference(PyObject *mod, PyObject *args) {
PyObject *source = NULL;
void *ptr;
@ -53,13 +65,30 @@ static PyObject *testpytalloc_reference(PyObject *mod, PyObject *args) {
return pytalloc_reference_ex(pytalloc_GetObjectType(), ptr, ptr);
}
static PyObject *testpytalloc_base_reference(PyObject *mod, PyObject *args) {
PyObject *source = NULL;
void *mem_ctx;
if (!PyArg_ParseTuple(args, "O!", pytalloc_GetBaseObjectType(), &source)) {
return NULL;
}
mem_ctx = pytalloc_get_mem_ctx(source);
return pytalloc_reference_ex(pytalloc_GetBaseObjectType(), mem_ctx, mem_ctx);
}
static PyMethodDef test_talloc_methods[] = {
{ "new", (PyCFunction)testpytalloc_new, METH_NOARGS,
"create a talloc Object with a testing string"},
{ "get_object_type", (PyCFunction)testpytalloc_get_object_type, METH_NOARGS,
"call pytalloc_GetObjectType"},
{ "base_new", (PyCFunction)testpytalloc_base_new, METH_NOARGS,
"create a talloc BaseObject with a testing string"},
{ "base_get_object_type", (PyCFunction)testpytalloc_base_get_object_type, METH_NOARGS,
"call pytalloc_GetBaseObjectType"},
{ "reference", (PyCFunction)testpytalloc_reference, METH_VARARGS,
"call pytalloc_reference_ex"},
{ "base_reference", (PyCFunction)testpytalloc_base_reference, METH_VARARGS,
"call pytalloc_reference_ex"},
{ NULL }
};
@ -104,6 +133,46 @@ static PyTypeObject DObject_Type = {
.tp_doc = "test talloc object that calls a function when underlying data is freed\n",
};
static PyTypeObject DBaseObject_Type;
static int d_base_object_destructor(void *ptr)
{
PyObject *destructor_func = *talloc_get_type(ptr, PyObject*);
PyObject *ret;
ret = PyObject_CallObject(destructor_func, NULL);
Py_DECREF(destructor_func);
if (ret == NULL) {
PyErr_Print();
} else {
Py_DECREF(ret);
}
return 0;
}
static PyObject *d_base_object_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
{
PyObject *destructor_func = NULL;
PyObject **obj;
if (!PyArg_ParseTuple(args, "O", &destructor_func))
return NULL;
Py_INCREF(destructor_func);
obj = talloc(NULL, PyObject*);
*obj = destructor_func;
talloc_set_destructor((void*)obj, d_base_object_destructor);
return pytalloc_steal(&DBaseObject_Type, obj);
}
static PyTypeObject DBaseObject_Type = {
.tp_name = "_test_pytalloc.DBaseObject",
.tp_methods = NULL,
.tp_new = d_base_object_new,
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_doc = "test talloc object that calls a function when underlying data is freed\n",
};
#define MODULE_DOC PyDoc_STR("Test utility module for pytalloc")
#if PY_MAJOR_VERSION >= 3
@ -126,6 +195,12 @@ static PyObject *module_init(void)
return NULL;
}
DBaseObject_Type.tp_basicsize = pytalloc_BaseObject_size();
DBaseObject_Type.tp_base = pytalloc_GetBaseObjectType();
if (PyType_Ready(&DBaseObject_Type) < 0) {
return NULL;
}
#if PY_MAJOR_VERSION >= 3
m = PyModule_Create(&moduledef);
#else
@ -140,6 +215,10 @@ static PyObject *module_init(void)
Py_INCREF(DObject_Type.tp_base);
PyModule_AddObject(m, "DObject", (PyObject *)&DObject_Type);
Py_INCREF(&DBaseObject_Type);
Py_INCREF(DBaseObject_Type.tp_base);
PyModule_AddObject(m, "DBaseObject", (PyObject *)&DBaseObject_Type);
return m;
}

View File

@ -43,6 +43,12 @@ class TallocTests(unittest.TestCase):
self.assertTrue(repr(obj).startswith(prefix))
self.assertEqual(repr(obj), str(obj))
def test_base_repr(self):
obj = _test_pytalloc.base_new()
prefix = '<talloc.BaseObject talloc based object at'
self.assertTrue(repr(obj).startswith(prefix))
self.assertEqual(repr(obj), str(obj))
def test_destructor(self):
# Check correct lifetime of the talloc'd data
lst = []
@ -52,6 +58,15 @@ class TallocTests(unittest.TestCase):
gc.collect()
self.assertEqual(lst, ['dead'])
def test_base_destructor(self):
# Check correct lifetime of the talloc'd data
lst = []
obj = _test_pytalloc.DBaseObject(lambda: lst.append('dead'))
self.assertEqual(lst, [])
del obj
gc.collect()
self.assertEqual(lst, ['dead'])
class TallocComparisonTests(unittest.TestCase):
@ -94,13 +109,54 @@ class TallocComparisonTests(unittest.TestCase):
self.assertFalse(obj1 >= obj2)
self.assertFalse(obj1 > obj2)
class TallocBaseComparisonTests(unittest.TestCase):
def test_compare_same(self):
obj1 = _test_pytalloc.base_new()
self.assertTrue(obj1 == obj1)
self.assertFalse(obj1 != obj1)
self.assertTrue(obj1 <= obj1)
self.assertFalse(obj1 < obj1)
self.assertTrue(obj1 >= obj1)
self.assertFalse(obj1 > obj1)
def test_compare_different(self):
# object comparison is consistent
obj1, obj2 = sorted([
_test_pytalloc.base_new(),
_test_pytalloc.base_new()])
self.assertFalse(obj1 == obj2)
self.assertTrue(obj1 != obj2)
self.assertTrue(obj1 <= obj2)
self.assertTrue(obj1 < obj2)
self.assertFalse(obj1 >= obj2)
self.assertFalse(obj1 > obj2)
def test_compare_different_types(self):
# object comparison falls back to comparing types
if sys.version_info >= (3, 0):
# In Python 3, types are unorderable -- nothing to test
return
if talloc.BaseObject < _test_pytalloc.DBaseObject:
obj1 = _test_pytalloc.base_new()
obj2 = _test_pytalloc.DBaseObject(dummy_func)
else:
obj2 = _test_pytalloc.base_new()
obj1 = _test_pytalloc.DBaseObject(dummy_func)
self.assertFalse(obj1 == obj2)
self.assertTrue(obj1 != obj2)
self.assertTrue(obj1 <= obj2)
self.assertTrue(obj1 < obj2)
self.assertFalse(obj1 >= obj2)
self.assertFalse(obj1 > obj2)
class TallocUtilTests(unittest.TestCase):
def test_get_type(self):
self.assertTrue(talloc.Object is _test_pytalloc.get_object_type())
def test_refrence(self):
def test_reference(self):
# Check correct lifetime of the talloc'd data with multiple references
lst = []
obj = _test_pytalloc.DObject(lambda: lst.append('dead'))
@ -112,6 +168,21 @@ class TallocUtilTests(unittest.TestCase):
gc.collect()
self.assertEqual(lst, ['dead'])
def test_get_base_type(self):
self.assertTrue(talloc.BaseObject is _test_pytalloc.base_get_object_type())
def test_base_reference(self):
# Check correct lifetime of the talloc'd data with multiple references
lst = []
obj = _test_pytalloc.DBaseObject(lambda: lst.append('dead'))
ref = _test_pytalloc.base_reference(obj)
del obj
gc.collect()
self.assertEqual(lst, [])
del ref
gc.collect()
self.assertEqual(lst, ['dead'])
if __name__ == '__main__':
unittest.TestProgram()