1 /* Subclasses of built-in Python types supporting extra D-Bus functionality.
3 * Copyright (C) 2006, 2007 Collabora Ltd.
5 * Licensed under the Academic Free License version 2.1
7 * This library is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include <structmember.h>
28 #include "dbus_bindings-internal.h"
29 #include "types-internal.h"
31 /* Dict indexed by object IDs, whose values are nonzero variant levels
32 * for immutable variable-sized D-Bus data types (_LongBase, _StrBase, Struct).
34 * This is a strange way to store them, but adding a __dict__ to the offending
35 * objects seems even more error-prone, given that their sizes are variable!
37 PyObject
*_dbus_py_variant_levels
= NULL
;
40 dbus_py_variant_level_get(PyObject
*obj
)
43 PyObject
*key
= PyLong_FromVoidPtr(obj
);
49 vl_obj
= PyDict_GetItem(_dbus_py_variant_levels
, key
);
54 return PyInt_AsLong(vl_obj
);
58 dbus_py_variant_level_set(PyObject
*obj
, long variant_level
)
60 /* key is the object's ID (= pointer) to avoid referencing it */
61 PyObject
*key
= PyLong_FromVoidPtr(obj
);
67 if (variant_level
<= 0) {
68 if (PyDict_GetItem (_dbus_py_variant_levels
, key
)) {
69 if (PyDict_DelItem (_dbus_py_variant_levels
, key
) < 0) {
76 PyObject
*vl_obj
= PyInt_FromLong(variant_level
);
81 if (PyDict_SetItem (_dbus_py_variant_levels
, key
, vl_obj
) < 0) {
91 dbus_py_variant_level_getattro(PyObject
*obj
, PyObject
*name
)
93 PyObject
*key
, *value
;
95 if (PyString_Check(name
)) {
98 else if (PyUnicode_Check(name
)) {
99 name
= PyUnicode_AsEncodedString(name
, NULL
, NULL
);
105 PyErr_SetString(PyExc_TypeError
, "attribute name must be string");
109 if (strcmp(PyString_AS_STRING(name
), "variant_level")) {
110 value
= PyObject_GenericGetAttr(obj
, name
);
117 key
= PyLong_FromVoidPtr(obj
);
123 value
= PyDict_GetItem(_dbus_py_variant_levels
, key
);
127 return PyInt_FromLong(0);
132 /* To be invoked by destructors. Clear the variant level without touching the
135 dbus_py_variant_level_clear(PyObject
*self
)
137 PyObject
*et
, *ev
, *etb
;
139 /* avoid clobbering any pending exception */
140 PyErr_Fetch(&et
, &ev
, &etb
);
141 if (!dbus_py_variant_level_set(self
, 0)) {
142 /* should never happen */
143 PyErr_WriteUnraisable(self
);
145 PyErr_Restore(et
, ev
, etb
);
148 /* Support code for int subclasses. ================================== */
150 PyDoc_STRVAR(DBusPythonInt_tp_doc
,\
151 "Base class for int subclasses with a ``variant_level`` attribute.\n"
152 "Do not rely on the existence of this class outside dbus-python.\n"
155 static PyMemberDef DBusPythonInt_tp_members
[] = {
156 {"variant_level", T_LONG
, offsetof(DBusPyIntBase
, variant_level
),
158 "The number of nested variants wrapping the real data. "
159 "0 if not in a variant."},
164 DBusPythonInt_tp_new(PyTypeObject
*cls
, PyObject
*args
, PyObject
*kwargs
)
167 long variantness
= 0;
168 static char *argnames
[] = {"variant_level", NULL
};
170 if (PyTuple_Size(args
) > 1) {
171 PyErr_SetString(PyExc_TypeError
,
172 "__new__ takes at most one positional parameter");
175 if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple
, kwargs
,
176 "|l:__new__", argnames
,
177 &variantness
)) return NULL
;
178 if (variantness
< 0) {
179 PyErr_SetString(PyExc_ValueError
,
180 "variant_level must be non-negative");
184 self
= (PyInt_Type
.tp_new
)(cls
, args
, NULL
);
186 ((DBusPyIntBase
*)self
)->variant_level
= variantness
;
192 DBusPythonInt_tp_repr(PyObject
*self
)
194 PyObject
*parent_repr
= (PyInt_Type
.tp_repr
)(self
);
195 long variant_level
= ((DBusPyIntBase
*)self
)->variant_level
;
198 if (!parent_repr
) return NULL
;
199 if (variant_level
> 0) {
200 my_repr
= PyString_FromFormat("%s(%s, variant_level=%ld)",
201 self
->ob_type
->tp_name
,
202 PyString_AS_STRING(parent_repr
),
206 my_repr
= PyString_FromFormat("%s(%s)", self
->ob_type
->tp_name
,
207 PyString_AS_STRING(parent_repr
));
209 /* whether my_repr is NULL or not: */
210 Py_DECREF(parent_repr
);
214 PyTypeObject DBusPyIntBase_Type
= {
215 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type
))
217 "_dbus_bindings._IntBase",
218 sizeof(DBusPyIntBase
),
225 DBusPythonInt_tp_repr
, /* tp_repr */
226 0, /* tp_as_number */
227 0, /* tp_as_sequence */
228 0, /* tp_as_mapping */
234 0, /* tp_as_buffer */
235 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /* tp_flags */
236 DBusPythonInt_tp_doc
, /* tp_doc */
239 0, /* tp_richcompare */
240 0, /* tp_weaklistoffset */
244 DBusPythonInt_tp_members
, /* tp_members */
246 DEFERRED_ADDRESS(&PyInt_Type
), /* tp_base */
248 0, /* tp_descr_get */
249 0, /* tp_descr_set */
250 0, /* tp_dictoffset */
252 PyType_GenericAlloc
, /* tp_alloc */
253 DBusPythonInt_tp_new
, /* tp_new */
254 PyObject_Del
, /* tp_free */
257 /* Support code for float subclasses. ================================ */
259 /* There's only one subclass at the moment (Double) but these are factored
260 out to make room for Float later. (Float is implemented and #if'd out) */
262 PyDoc_STRVAR(DBusPythonFloat_tp_doc
,\
263 "Base class for float subclasses with a ``variant_level`` attribute.\n"
264 "Do not rely on the existence of this class outside dbus-python.\n"
267 static PyMemberDef DBusPythonFloat_tp_members
[] = {
268 {"variant_level", T_LONG
, offsetof(DBusPyFloatBase
, variant_level
),
270 "The number of nested variants wrapping the real data. "
271 "0 if not in a variant."},
276 DBusPythonFloat_tp_new(PyTypeObject
*cls
, PyObject
*args
, PyObject
*kwargs
)
279 long variantness
= 0;
280 static char *argnames
[] = {"variant_level", NULL
};
282 if (PyTuple_Size(args
) > 1) {
283 PyErr_SetString(PyExc_TypeError
,
284 "__new__ takes at most one positional parameter");
287 if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple
, kwargs
,
288 "|l:__new__", argnames
,
289 &variantness
)) return NULL
;
290 if (variantness
< 0) {
291 PyErr_SetString(PyExc_ValueError
,
292 "variant_level must be non-negative");
296 self
= (PyFloat_Type
.tp_new
)(cls
, args
, NULL
);
298 ((DBusPyFloatBase
*)self
)->variant_level
= variantness
;
304 DBusPythonFloat_tp_repr(PyObject
*self
)
306 PyObject
*parent_repr
= (PyFloat_Type
.tp_repr
)(self
);
307 long variant_level
= ((DBusPyFloatBase
*)self
)->variant_level
;
310 if (!parent_repr
) return NULL
;
311 if (variant_level
> 0) {
312 my_repr
= PyString_FromFormat("%s(%s, variant_level=%ld)",
313 self
->ob_type
->tp_name
,
314 PyString_AS_STRING(parent_repr
),
318 my_repr
= PyString_FromFormat("%s(%s)", self
->ob_type
->tp_name
,
319 PyString_AS_STRING(parent_repr
));
321 /* whether my_repr is NULL or not: */
322 Py_DECREF(parent_repr
);
326 PyTypeObject DBusPyFloatBase_Type
= {
327 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type
))
329 "_dbus_bindings._FloatBase",
330 sizeof(DBusPyFloatBase
),
337 DBusPythonFloat_tp_repr
, /* tp_repr */
338 0, /* tp_as_number */
339 0, /* tp_as_sequence */
340 0, /* tp_as_mapping */
346 0, /* tp_as_buffer */
347 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /* tp_flags */
348 DBusPythonFloat_tp_doc
, /* tp_doc */
351 0, /* tp_richcompare */
352 0, /* tp_weaklistoffset */
356 DBusPythonFloat_tp_members
, /* tp_members */
358 DEFERRED_ADDRESS(&PyFloat_Type
), /* tp_base */
360 0, /* tp_descr_get */
361 0, /* tp_descr_set */
362 0, /* tp_dictoffset */
365 DBusPythonFloat_tp_new
, /* tp_new */
368 /* Support code for str subclasses ================================== */
370 PyDoc_STRVAR(DBusPythonString_tp_doc
,\
371 "Base class for str subclasses with a ``variant_level`` attribute.\n"
372 "Do not rely on the existence of this class outside dbus-python.\n"
376 DBusPythonString_tp_new(PyTypeObject
*cls
, PyObject
*args
, PyObject
*kwargs
)
379 long variantness
= 0;
380 static char *argnames
[] = {"variant_level", NULL
};
382 if (PyTuple_Size(args
) > 1) {
383 PyErr_SetString(PyExc_TypeError
,
384 "__new__ takes at most one positional parameter");
387 if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple
, kwargs
,
388 "|l:__new__", argnames
,
389 &variantness
)) return NULL
;
390 if (variantness
< 0) {
391 PyErr_SetString(PyExc_ValueError
,
392 "variant_level must be non-negative");
396 self
= (PyString_Type
.tp_new
)(cls
, args
, NULL
);
398 if (!dbus_py_variant_level_set(self
, variantness
)) {
407 DBusPythonString_tp_repr(PyObject
*self
)
409 PyObject
*parent_repr
= (PyString_Type
.tp_repr
)(self
);
414 if (!parent_repr
) return NULL
;
415 vl_obj
= PyObject_GetAttr(self
, dbus_py_variant_level_const
);
417 Py_DECREF(parent_repr
);
420 variant_level
= PyInt_AsLong(vl_obj
);
422 if (variant_level
> 0) {
423 my_repr
= PyString_FromFormat("%s(%s, variant_level=%ld)",
424 self
->ob_type
->tp_name
,
425 PyString_AS_STRING(parent_repr
),
429 my_repr
= PyString_FromFormat("%s(%s)", self
->ob_type
->tp_name
,
430 PyString_AS_STRING(parent_repr
));
432 /* whether my_repr is NULL or not: */
433 Py_DECREF(parent_repr
);
438 DBusPyStrBase_tp_dealloc(PyObject
*self
)
440 dbus_py_variant_level_clear(self
);
441 (PyString_Type
.tp_dealloc
)(self
);
444 PyTypeObject DBusPyStrBase_Type
= {
445 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type
))
447 "_dbus_bindings._StrBase",
450 DBusPyStrBase_tp_dealloc
, /* tp_dealloc */
455 DBusPythonString_tp_repr
, /* tp_repr */
456 0, /* tp_as_number */
457 0, /* tp_as_sequence */
458 0, /* tp_as_mapping */
462 dbus_py_variant_level_getattro
, /* tp_getattro */
463 dbus_py_immutable_setattro
, /* tp_setattro */
464 0, /* tp_as_buffer */
465 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /* tp_flags */
466 DBusPythonString_tp_doc
, /* tp_doc */
469 0, /* tp_richcompare */
470 0, /* tp_weaklistoffset */
476 DEFERRED_ADDRESS(&PyString_Type
), /* tp_base */
478 0, /* tp_descr_get */
479 0, /* tp_descr_set */
480 0, /* tp_dictoffset */
483 DBusPythonString_tp_new
, /* tp_new */
486 /* Support code for long subclasses ================================= */
488 PyDoc_STRVAR(DBusPythonLong_tp_doc
,\
489 "Base class for ``long`` subclasses with a ``variant_level`` attribute.\n"
490 "Do not rely on the existence of this class outside dbus-python.\n"
494 DBusPythonLong_tp_new(PyTypeObject
*cls
, PyObject
*args
, PyObject
*kwargs
)
497 long variantness
= 0;
498 static char *argnames
[] = {"variant_level", NULL
};
500 if (PyTuple_Size(args
) > 1) {
501 PyErr_SetString(PyExc_TypeError
,
502 "__new__ takes at most one positional parameter");
505 if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple
, kwargs
,
506 "|l:__new__", argnames
,
507 &variantness
)) return NULL
;
508 if (variantness
< 0) {
509 PyErr_SetString(PyExc_ValueError
,
510 "variant_level must be non-negative");
514 self
= (PyLong_Type
.tp_new
)(cls
, args
, NULL
);
516 if (!dbus_py_variant_level_set(self
, variantness
)) {
525 DBusPythonLong_tp_repr(PyObject
*self
)
527 PyObject
*parent_repr
= (PyLong_Type
.tp_repr
)(self
);
532 if (!parent_repr
) return NULL
;
533 vl_obj
= PyObject_GetAttr(self
, dbus_py_variant_level_const
);
535 Py_DECREF(parent_repr
);
538 variant_level
= PyInt_AsLong(vl_obj
);
541 my_repr
= PyString_FromFormat("%s(%s, variant_level=%ld)",
542 self
->ob_type
->tp_name
,
543 PyString_AS_STRING(parent_repr
),
547 my_repr
= PyString_FromFormat("%s(%s)", self
->ob_type
->tp_name
,
548 PyString_AS_STRING(parent_repr
));
550 /* whether my_repr is NULL or not: */
551 Py_DECREF(parent_repr
);
556 DBusPyLongBase_tp_dealloc(PyObject
*self
)
558 dbus_py_variant_level_clear(self
);
559 (PyLong_Type
.tp_dealloc
)(self
);
562 PyTypeObject DBusPyLongBase_Type
= {
563 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type
))
565 "_dbus_bindings._LongBase",
568 DBusPyLongBase_tp_dealloc
, /* tp_dealloc */
573 DBusPythonLong_tp_repr
, /* tp_repr */
574 0, /* tp_as_number */
575 0, /* tp_as_sequence */
576 0, /* tp_as_mapping */
580 dbus_py_variant_level_getattro
, /* tp_getattro */
581 dbus_py_immutable_setattro
, /* tp_setattro */
582 0, /* tp_as_buffer */
583 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /* tp_flags */
584 DBusPythonLong_tp_doc
, /* tp_doc */
587 0, /* tp_richcompare */
588 0, /* tp_weaklistoffset */
594 DEFERRED_ADDRESS(&PyLong_Type
), /* tp_base */
596 0, /* tp_descr_get */
597 0, /* tp_descr_set */
598 0, /* tp_dictoffset */
601 DBusPythonLong_tp_new
, /* tp_new */
604 PyObject
*dbus_py_variant_level_const
= NULL
;
605 PyObject
*dbus_py_signature_const
= NULL
;
606 PyObject
*dbus_py__dbus_object_path__const
= NULL
;
609 dbus_py_init_abstract(void)
611 _dbus_py_variant_levels
= PyDict_New();
612 if (!_dbus_py_variant_levels
) return 0;
614 dbus_py__dbus_object_path__const
= PyString_InternFromString("__dbus_object_path__");
615 if (!dbus_py__dbus_object_path__const
) return 0;
617 dbus_py_variant_level_const
= PyString_InternFromString("variant_level");
618 if (!dbus_py_variant_level_const
) return 0;
620 dbus_py_signature_const
= PyString_InternFromString("signature");
621 if (!dbus_py_signature_const
) return 0;
623 DBusPyIntBase_Type
.tp_base
= &PyInt_Type
;
624 if (PyType_Ready(&DBusPyIntBase_Type
) < 0) return 0;
625 /* disable the tp_print copied from PyInt_Type, so tp_repr gets called as
627 DBusPyIntBase_Type
.tp_print
= NULL
;
629 DBusPyFloatBase_Type
.tp_base
= &PyFloat_Type
;
630 if (PyType_Ready(&DBusPyFloatBase_Type
) < 0) return 0;
631 DBusPyFloatBase_Type
.tp_print
= NULL
;
633 DBusPyLongBase_Type
.tp_base
= &PyLong_Type
;
634 if (PyType_Ready(&DBusPyLongBase_Type
) < 0) return 0;
635 DBusPyLongBase_Type
.tp_print
= NULL
;
637 DBusPyStrBase_Type
.tp_base
= &PyString_Type
;
638 if (PyType_Ready(&DBusPyStrBase_Type
) < 0) return 0;
639 DBusPyStrBase_Type
.tp_print
= NULL
;
645 dbus_py_insert_abstract_types(PyObject
*this_module
)
647 Py_INCREF(&DBusPyIntBase_Type
);
648 Py_INCREF(&DBusPyLongBase_Type
);
649 Py_INCREF(&DBusPyStrBase_Type
);
650 Py_INCREF(&DBusPyFloatBase_Type
);
651 if (PyModule_AddObject(this_module
, "_IntBase",
652 (PyObject
*)&DBusPyIntBase_Type
) < 0) return 0;
653 if (PyModule_AddObject(this_module
, "_LongBase",
654 (PyObject
*)&DBusPyLongBase_Type
) < 0) return 0;
655 if (PyModule_AddObject(this_module
, "_StrBase",
656 (PyObject
*)&DBusPyStrBase_Type
) < 0) return 0;
657 if (PyModule_AddObject(this_module
, "_FloatBase",
658 (PyObject
*)&DBusPyFloatBase_Type
) < 0) return 0;