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;