1 /* D-Bus container types: Array, Dict and Struct.
3 * Copyright (C) 2006-2007 Collabora Ltd. <http://www.collabora.co.uk/>
5 * Permission is hereby granted, free of charge, to any person
6 * obtaining a copy of this software and associated documentation
7 * files (the "Software"), to deal in the Software without
8 * restriction, including without limitation the rights to use, copy,
9 * modify, merge, publish, distribute, sublicense, and/or sell copies
10 * of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
27 #include <structmember.h>
31 #include "dbus_bindings-internal.h"
32 #include "types-internal.h"
34 /* Array ============================================================ */
36 PyDoc_STRVAR(Array_tp_doc
,
37 "An array of similar items, implemented as a subtype of list.\n"
39 "As currently implemented, an Array behaves just like a list, but\n"
40 "with the addition of a ``signature`` property set by the constructor;\n"
41 "conversion of its items to D-Bus types is only done when it's sent in\n"
42 "a Message. This might change in future so validation is done earlier.\n"
46 " dbus.Array([iterable][, signature][, variant_level])\n"
48 "``variant_level`` must be non-negative; the default is 0.\n"
50 "``signature`` is the D-Bus signature string for a single element of the\n"
51 "array, or None. If not None it must represent a single complete type, the\n"
52 "type of a single array item; the signature of the whole Array may be\n"
53 "obtained by prepending ``a`` to the given signature.\n"
55 "If None (the default), when the Array is sent over\n"
56 "D-Bus, the item signature will be guessed from the first element.\n"
59 " `variant_level` : int\n"
60 " Indicates how many nested Variant containers this object\n"
61 " is contained in: if a message's wire format has a variant containing a\n"
62 " variant containing an array, this is represented in Python by an\n"
63 " Array with variant_level==2.\n"
66 static struct PyMemberDef Array_tp_members
[] = {
67 {"signature", T_OBJECT
, offsetof(DBusPyArray
, signature
), READONLY
,
68 "The D-Bus signature of each element of this Array (a Signature "
70 {"variant_level", T_LONG
, offsetof(DBusPyArray
, variant_level
),
72 "The number of nested variants wrapping the real data. "
73 "0 if not in a variant."},
78 Array_tp_dealloc (DBusPyArray
*self
)
80 Py_XDECREF(self
->signature
);
81 self
->signature
= NULL
;
82 (PyList_Type
.tp_dealloc
)((PyObject
*)self
);
86 Array_tp_repr(DBusPyArray
*self
)
88 PyObject
*parent_repr
= (PyList_Type
.tp_repr
)((PyObject
*)self
);
89 PyObject
*sig_repr
= PyObject_Repr(self
->signature
);
90 PyObject
*my_repr
= NULL
;
91 long variant_level
= self
->variant_level
;
93 if (!parent_repr
) goto finally
;
94 if (!sig_repr
) goto finally
;
95 if (variant_level
> 0) {
96 my_repr
= PyString_FromFormat("%s(%s, signature=%s, "
98 self
->super
.ob_type
->tp_name
,
99 PyString_AS_STRING(parent_repr
),
100 PyString_AS_STRING(sig_repr
),
104 my_repr
= PyString_FromFormat("%s(%s, signature=%s)",
105 self
->super
.ob_type
->tp_name
,
106 PyString_AS_STRING(parent_repr
),
107 PyString_AS_STRING(sig_repr
));
110 Py_XDECREF(parent_repr
);
111 Py_XDECREF(sig_repr
);
116 Array_tp_new (PyTypeObject
*cls
, PyObject
*args
, PyObject
*kwargs
)
118 PyObject
*variant_level
= NULL
;
119 DBusPyArray
*self
= (DBusPyArray
*)(PyList_Type
.tp_new
)(cls
, args
, kwargs
);
121 /* variant_level is immutable, so handle it in __new__ rather than
123 if (!self
) return NULL
;
125 self
->signature
= Py_None
;
126 self
->variant_level
= 0;
128 variant_level
= PyDict_GetItem(kwargs
, dbus_py_variant_level_const
);
131 self
->variant_level
= PyInt_AsLong(variant_level
);
132 if (PyErr_Occurred()) {
133 Py_DECREF((PyObject
*)self
);
137 return (PyObject
*)self
;
141 Array_tp_init (DBusPyArray
*self
, PyObject
*args
, PyObject
*kwargs
)
143 PyObject
*obj
= dbus_py_empty_tuple
;
144 PyObject
*signature
= NULL
;
146 PyObject
*variant_level
;
147 /* variant_level is accepted but ignored - it's immutable, so
148 * __new__ handles it */
149 static char *argnames
[] = {"iterable", "signature", "variant_level", NULL
};
151 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "|OOO:__init__", argnames
,
152 &obj
, &signature
, &variant_level
)) {
156 /* convert signature from a borrowed ref of unknown type to an owned ref
157 of type Signature (or None) */
158 if (!signature
) signature
= Py_None
;
159 if (signature
== Py_None
160 || PyObject_IsInstance(signature
, (PyObject
*)&DBusPySignature_Type
)) {
161 Py_INCREF(signature
);
164 signature
= PyObject_CallFunction((PyObject
*)&DBusPySignature_Type
,
166 if (!signature
) return -1;
169 if (signature
!= Py_None
) {
170 const char *c_str
= PyString_AS_STRING(signature
);
172 if (!dbus_signature_validate_single(c_str
, NULL
)) {
173 Py_DECREF(signature
);
174 PyErr_SetString(PyExc_ValueError
,
175 "There must be exactly one complete type in "
176 "an Array's signature parameter");
181 tuple
= Py_BuildValue("(O)", obj
);
183 Py_DECREF(signature
);
186 if ((PyList_Type
.tp_init
)((PyObject
*)self
, tuple
, NULL
) < 0) {
188 Py_DECREF(signature
);
193 Py_XDECREF(self
->signature
);
194 self
->signature
= signature
;
198 PyTypeObject DBusPyArray_Type
= {
199 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type
))
204 (destructor
)Array_tp_dealloc
, /* tp_dealloc */
209 (reprfunc
)Array_tp_repr
, /* tp_repr */
210 0, /* tp_as_number */
211 0, /* tp_as_sequence */
212 0, /* tp_as_mapping */
218 0, /* tp_as_buffer */
219 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /* tp_flags */
220 Array_tp_doc
, /* tp_doc */
223 0, /* tp_richcompare */
224 0, /* tp_weaklistoffset */
228 Array_tp_members
, /* tp_members */
232 0, /* tp_descr_get */
233 0, /* tp_descr_set */
234 0, /* tp_dictoffset */
235 (initproc
)Array_tp_init
, /* tp_init */
237 Array_tp_new
, /* tp_new */
240 /* Dict ============================================================= */
242 PyDoc_STRVAR(Dict_tp_doc
,
243 "An mapping whose keys are similar and whose values are similar,\n"
244 "implemented as a subtype of dict.\n"
246 "As currently implemented, a Dictionary behaves just like a dict, but\n"
247 "with the addition of a ``signature`` property set by the constructor;\n"
248 "conversion of its items to D-Bus types is only done when it's sent in\n"
249 "a Message. This may change in future so validation is done earlier.\n"
253 " Dictionary(mapping_or_iterable=(), signature=None, variant_level=0)\n"
255 "``variant_level`` must be non-negative; the default is 0.\n"
257 "``signature`` is either a string or None. If a string, it must consist\n"
258 "of exactly two complete type signatures, representing the 'key' type\n"
259 "(which must be a primitive type, i.e. one of \"bdginoqstuxy\")\n"
260 "and the 'value' type. The signature of the whole Dictionary will be\n"
261 "``a{xx}`` where ``xx`` is replaced by the given signature.\n"
263 "If it is None (the default), when the Dictionary is sent over\n"
264 "D-Bus, the key and value signatures will be guessed from an arbitrary\n"
265 "element of the Dictionary.\n"
268 " `variant_level` : int\n"
269 " Indicates how many nested Variant containers this object\n"
270 " is contained in: if a message's wire format has a variant containing a\n"
271 " variant containing an array of DICT_ENTRY, this is represented in\n"
272 " Python by a Dictionary with variant_level==2.\n"
275 static struct PyMemberDef Dict_tp_members
[] = {
276 {"signature", T_OBJECT
, offsetof(DBusPyDict
, signature
), READONLY
,
277 "The D-Bus signature of each key in this Dictionary, followed by "
278 "that of each value in this Dictionary, as a Signature instance."},
279 {"variant_level", T_LONG
, offsetof(DBusPyDict
, variant_level
),
281 "The number of nested variants wrapping the real data. "
282 "0 if not in a variant."},
287 Dict_tp_dealloc (DBusPyDict
*self
)
289 Py_XDECREF(self
->signature
);
290 self
->signature
= NULL
;
291 (PyDict_Type
.tp_dealloc
)((PyObject
*)self
);
295 Dict_tp_repr(DBusPyDict
*self
)
297 PyObject
*parent_repr
= (PyDict_Type
.tp_repr
)((PyObject
*)self
);
298 PyObject
*sig_repr
= PyObject_Repr(self
->signature
);
299 PyObject
*my_repr
= NULL
;
300 long variant_level
= self
->variant_level
;
302 if (!parent_repr
) goto finally
;
303 if (!sig_repr
) goto finally
;
304 if (variant_level
> 0) {
305 my_repr
= PyString_FromFormat("%s(%s, signature=%s, "
306 "variant_level=%ld)",
307 self
->super
.ob_type
->tp_name
,
308 PyString_AS_STRING(parent_repr
),
309 PyString_AS_STRING(sig_repr
),
313 my_repr
= PyString_FromFormat("%s(%s, signature=%s)",
314 self
->super
.ob_type
->tp_name
,
315 PyString_AS_STRING(parent_repr
),
316 PyString_AS_STRING(sig_repr
));
319 Py_XDECREF(parent_repr
);
320 Py_XDECREF(sig_repr
);
325 Dict_tp_new(PyTypeObject
*cls
, PyObject
*args
, PyObject
*kwargs
)
327 DBusPyDict
*self
= (DBusPyDict
*)(PyDict_Type
.tp_new
)(cls
, args
, kwargs
);
328 PyObject
*variant_level
= NULL
;
330 /* variant_level is immutable, so handle it in __new__ rather than
332 if (!self
) return NULL
;
334 self
->signature
= Py_None
;
335 self
->variant_level
= 0;
337 variant_level
= PyDict_GetItem(kwargs
, dbus_py_variant_level_const
);
340 self
->variant_level
= PyInt_AsLong(variant_level
);
341 if (PyErr_Occurred()) {
342 Py_DECREF((PyObject
*)self
);
346 return (PyObject
*)self
;
350 Dict_tp_init(DBusPyDict
*self
, PyObject
*args
, PyObject
*kwargs
)
352 PyObject
*obj
= dbus_py_empty_tuple
;
353 PyObject
*signature
= NULL
;
355 PyObject
*variant_level
; /* ignored here - __new__ uses it */
356 static char *argnames
[] = {"mapping_or_iterable", "signature",
357 "variant_level", NULL
};
359 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "|OOO:__init__", argnames
,
360 &obj
, &signature
, &variant_level
)) {
364 /* convert signature from a borrowed ref of unknown type to an owned ref
365 of type Signature (or None) */
366 if (!signature
) signature
= Py_None
;
367 if (signature
== Py_None
368 || PyObject_IsInstance(signature
, (PyObject
*)&DBusPySignature_Type
)) {
369 Py_INCREF(signature
);
372 signature
= PyObject_CallFunction((PyObject
*)&DBusPySignature_Type
,
374 if (!signature
) return -1;
377 if (signature
!= Py_None
) {
378 const char *c_str
= PyString_AS_STRING(signature
);
382 case DBUS_TYPE_BOOLEAN
:
383 case DBUS_TYPE_INT16
:
384 case DBUS_TYPE_UINT16
:
385 case DBUS_TYPE_INT32
:
386 case DBUS_TYPE_UINT32
:
387 case DBUS_TYPE_INT64
:
388 case DBUS_TYPE_UINT64
:
389 case DBUS_TYPE_DOUBLE
:
390 #ifdef WITH_DBUS_FLOAT32
391 case DBUS_TYPE_FLOAT
:
393 case DBUS_TYPE_STRING
:
394 case DBUS_TYPE_OBJECT_PATH
:
395 case DBUS_TYPE_SIGNATURE
:
398 Py_DECREF(signature
);
399 PyErr_SetString(PyExc_ValueError
,
400 "The key type in a Dictionary's signature "
401 "must be a primitive type");
405 if (!dbus_signature_validate_single(c_str
+ 1, NULL
)) {
406 Py_DECREF(signature
);
407 PyErr_SetString(PyExc_ValueError
,
408 "There must be exactly two complete types in "
409 "a Dictionary's signature parameter");
414 tuple
= Py_BuildValue("(O)", obj
);
416 Py_DECREF(signature
);
420 if ((PyDict_Type
.tp_init((PyObject
*)self
, tuple
, NULL
)) < 0) {
422 Py_DECREF(signature
);
427 Py_XDECREF(self
->signature
);
428 self
->signature
= signature
;
432 PyTypeObject DBusPyDict_Type
= {
433 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type
))
438 (destructor
)Dict_tp_dealloc
, /* tp_dealloc */
443 (reprfunc
)Dict_tp_repr
, /* tp_repr */
444 0, /* tp_as_number */
445 0, /* tp_as_sequence */
446 0, /* tp_as_mapping */
452 0, /* tp_as_buffer */
453 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /* tp_flags */
454 Dict_tp_doc
, /* tp_doc */
457 0, /* tp_richcompare */
458 0, /* tp_weaklistoffset */
462 Dict_tp_members
, /* tp_members */
466 0, /* tp_descr_get */
467 0, /* tp_descr_set */
468 0, /* tp_dictoffset */
469 (initproc
)Dict_tp_init
, /* tp_init */
471 Dict_tp_new
, /* tp_new */
474 /* Struct =========================================================== */
476 static PyObject
*struct_signatures
;
478 PyDoc_STRVAR(Struct_tp_doc
,
479 "An structure containing items of possibly distinct types.\n"
483 " dbus.Struct(iterable, signature=None, variant_level=0) -> Struct\n"
485 "D-Bus structs may not be empty, so the iterable argument is required and\n"
486 "may not be an empty iterable.\n"
488 "``signature`` is either None, or a string representing the contents of the\n"
489 "struct as one or more complete type signatures. The overall signature of\n"
490 "the struct will be the given signature enclosed in parentheses, ``()``.\n"
492 "If the signature is None (default) it will be guessed\n"
493 "from the types of the items during construction.\n"
495 "``variant_level`` must be non-negative; the default is 0.\n"
498 " `variant_level` : int\n"
499 " Indicates how many nested Variant containers this object\n"
500 " is contained in: if a message's wire format has a variant containing a\n"
501 " variant containing a struct, this is represented in Python by a\n"
502 " Struct with variant_level==2.\n"
506 Struct_tp_repr(PyObject
*self
)
508 PyObject
*parent_repr
= (PyTuple_Type
.tp_repr
)((PyObject
*)self
);
510 PyObject
*sig_repr
= NULL
;
513 PyObject
*my_repr
= NULL
;
515 if (!parent_repr
) goto finally
;
516 key
= PyLong_FromVoidPtr(self
);
517 if (!key
) goto finally
;
518 sig
= PyDict_GetItem(struct_signatures
, key
);
520 if (!sig
) sig
= Py_None
;
521 sig_repr
= PyObject_Repr(sig
);
522 if (!sig_repr
) goto finally
;
523 variant_level
= dbus_py_variant_level_get(self
);
524 if (variant_level
> 0) {
525 my_repr
= PyString_FromFormat("%s(%s, signature=%s, "
526 "variant_level=%ld)",
527 self
->ob_type
->tp_name
,
528 PyString_AS_STRING(parent_repr
),
529 PyString_AS_STRING(sig_repr
),
533 my_repr
= PyString_FromFormat("%s(%s, signature=%s)",
534 self
->ob_type
->tp_name
,
535 PyString_AS_STRING(parent_repr
),
536 PyString_AS_STRING(sig_repr
));
540 Py_XDECREF(parent_repr
);
541 Py_XDECREF(sig_repr
);
546 Struct_tp_new (PyTypeObject
*cls
, PyObject
*args
, PyObject
*kwargs
)
548 PyObject
*signature
= NULL
;
549 long variantness
= 0;
550 PyObject
*self
, *key
;
551 static char *argnames
[] = {"signature", "variant_level", NULL
};
553 if (PyTuple_Size(args
) != 1) {
554 PyErr_SetString(PyExc_TypeError
,
555 "__new__ takes exactly one positional parameter");
558 if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple
, kwargs
,
559 "|Ol:__new__", argnames
,
560 &signature
, &variantness
)) {
563 if (variantness
< 0) {
564 PyErr_SetString(PyExc_ValueError
,
565 "variant_level must be non-negative");
569 self
= (PyTuple_Type
.tp_new
)(cls
, args
, NULL
);
572 if (PyTuple_Size(self
) < 1) {
573 PyErr_SetString(PyExc_ValueError
, "D-Bus structs may not be empty");
578 if (!dbus_py_variant_level_set(self
, variantness
)) {
583 /* convert signature from a borrowed ref of unknown type to an owned ref
584 of type Signature (or None) */
585 if (!signature
) signature
= Py_None
;
586 if (signature
== Py_None
587 || PyObject_IsInstance(signature
, (PyObject
*)&DBusPySignature_Type
)) {
588 Py_INCREF(signature
);
591 signature
= PyObject_CallFunction((PyObject
*)&DBusPySignature_Type
,
599 key
= PyLong_FromVoidPtr(self
);
602 Py_DECREF(signature
);
605 if (PyDict_SetItem(struct_signatures
, key
, signature
) < 0) {
608 Py_DECREF(signature
);
613 Py_DECREF(signature
);
618 Struct_tp_dealloc(PyObject
*self
)
620 PyObject
*et
, *ev
, *etb
, *key
;
622 dbus_py_variant_level_clear(self
);
623 PyErr_Fetch(&et
, &ev
, &etb
);
625 key
= PyLong_FromVoidPtr(self
);
627 if (PyDict_GetItem(struct_signatures
, key
)) {
628 if (PyDict_DelItem(struct_signatures
, key
) < 0) {
629 /* should never happen */
630 PyErr_WriteUnraisable(self
);
636 /* not enough memory to free all the memory... leak the signature,
637 * there's not much else we could do here */
638 PyErr_WriteUnraisable(self
);
641 PyErr_Restore(et
, ev
, etb
);
642 (PyTuple_Type
.tp_dealloc
)(self
);
646 Struct_tp_getattro(PyObject
*obj
, PyObject
*name
)
648 PyObject
*key
, *value
;
650 if (PyString_Check(name
)) {
653 else if (PyUnicode_Check(name
)) {
654 name
= PyUnicode_AsEncodedString(name
, NULL
, NULL
);
660 PyErr_SetString(PyExc_TypeError
, "attribute name must be string");
664 if (strcmp(PyString_AS_STRING(name
), "signature")) {
665 value
= dbus_py_variant_level_getattro(obj
, name
);
672 key
= PyLong_FromVoidPtr(obj
);
678 value
= PyDict_GetItem(struct_signatures
, key
);
687 PyTypeObject DBusPyStruct_Type
= {
688 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type
))
693 Struct_tp_dealloc
, /* tp_dealloc */
698 (reprfunc
)Struct_tp_repr
, /* tp_repr */
699 0, /* tp_as_number */
700 0, /* tp_as_sequence */
701 0, /* tp_as_mapping */
705 Struct_tp_getattro
, /* tp_getattro */
706 dbus_py_immutable_setattro
, /* tp_setattro */
707 0, /* tp_as_buffer */
708 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /* tp_flags */
709 Struct_tp_doc
, /* tp_doc */
712 0, /* tp_richcompare */
713 0, /* tp_weaklistoffset */
721 0, /* tp_descr_get */
722 0, /* tp_descr_set */
723 0, /* tp_dictoffset */
726 Struct_tp_new
, /* tp_new */
730 dbus_py_init_container_types(void)
732 struct_signatures
= PyDict_New();
733 if (!struct_signatures
) return 0;
735 DBusPyArray_Type
.tp_base
= &PyList_Type
;
736 if (PyType_Ready(&DBusPyArray_Type
) < 0) return 0;
737 DBusPyArray_Type
.tp_print
= NULL
;
739 DBusPyDict_Type
.tp_base
= &PyDict_Type
;
740 if (PyType_Ready(&DBusPyDict_Type
) < 0) return 0;
741 DBusPyDict_Type
.tp_print
= NULL
;
743 DBusPyStruct_Type
.tp_base
= &PyTuple_Type
;
744 if (PyType_Ready(&DBusPyStruct_Type
) < 0) return 0;
745 DBusPyStruct_Type
.tp_print
= NULL
;
751 dbus_py_insert_container_types(PyObject
*this_module
)
753 Py_INCREF(&DBusPyArray_Type
);
754 if (PyModule_AddObject(this_module
, "Array",
755 (PyObject
*)&DBusPyArray_Type
) < 0) return 0;
757 Py_INCREF(&DBusPyDict_Type
);
758 if (PyModule_AddObject(this_module
, "Dictionary",
759 (PyObject
*)&DBusPyDict_Type
) < 0) return 0;
761 Py_INCREF(&DBusPyStruct_Type
);
762 if (PyModule_AddObject(this_module
, "Struct",
763 (PyObject
*)&DBusPyStruct_Type
) < 0) return 0;
768 /* vim:set ft=c cino< sw=4 sts=4 et: */