1 /* D-Bus container types: Array, Dict and Struct.
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 /* Array ============================================================ */
33 PyDoc_STRVAR(Array_tp_doc
,
34 "An array of similar items, implemented as a subtype of list.\n"
36 "As currently implemented, an Array behaves just like a list, but\n"
37 "with the addition of a ``signature`` property set by the constructor;\n"
38 "conversion of its items to D-Bus types is only done when it's sent in\n"
39 "a Message. This might change in future so validation is done earlier.\n"
43 " dbus.Array([iterable][, signature][, variant_level])\n"
45 "``variant_level`` must be non-negative; the default is 0.\n"
47 "``signature`` is the D-Bus signature string for a single element of the\n"
48 "array, or None. If not None it must represent a single complete type, the\n"
49 "type of a single array item; the signature of the whole Array may be\n"
50 "obtained by prepending ``a`` to the given signature.\n"
52 "If None (the default), when the Array is sent over\n"
53 "D-Bus, the item signature will be guessed from the first element.\n"
56 " `variant_level` : int\n"
57 " Indicates how many nested Variant containers this object\n"
58 " is contained in: if a message's wire format has a variant containing a\n"
59 " variant containing an array, this is represented in Python by an\n"
60 " Array with variant_level==2.\n"
63 static struct PyMemberDef Array_tp_members
[] = {
64 {"signature", T_OBJECT
, offsetof(DBusPyArray
, signature
), READONLY
,
65 "The D-Bus signature of each element of this Array (a Signature "
67 {"variant_level", T_LONG
, offsetof(DBusPyArray
, variant_level
),
69 "The number of nested variants wrapping the real data. "
70 "0 if not in a variant."},
75 Array_tp_dealloc (DBusPyArray
*self
)
77 Py_XDECREF(self
->signature
);
78 self
->signature
= NULL
;
79 (PyList_Type
.tp_dealloc
)((PyObject
*)self
);
83 Array_tp_repr(DBusPyArray
*self
)
85 PyObject
*parent_repr
= (PyList_Type
.tp_repr
)((PyObject
*)self
);
86 PyObject
*sig_repr
= PyObject_Repr(self
->signature
);
87 PyObject
*my_repr
= NULL
;
88 long variant_level
= self
->variant_level
;
90 if (!parent_repr
) goto finally
;
91 if (!sig_repr
) goto finally
;
92 if (variant_level
> 0) {
93 my_repr
= PyString_FromFormat("%s(%s, signature=%s, "
95 self
->super
.ob_type
->tp_name
,
96 PyString_AS_STRING(parent_repr
),
97 PyString_AS_STRING(sig_repr
),
101 my_repr
= PyString_FromFormat("%s(%s, signature=%s)",
102 self
->super
.ob_type
->tp_name
,
103 PyString_AS_STRING(parent_repr
),
104 PyString_AS_STRING(sig_repr
));
107 Py_XDECREF(parent_repr
);
108 Py_XDECREF(sig_repr
);
113 Array_tp_new (PyTypeObject
*cls
, PyObject
*args
, PyObject
*kwargs
)
115 PyObject
*variant_level
= NULL
;
116 DBusPyArray
*self
= (DBusPyArray
*)(PyList_Type
.tp_new
)(cls
, args
, kwargs
);
118 /* variant_level is immutable, so handle it in __new__ rather than
120 if (!self
) return NULL
;
122 self
->signature
= Py_None
;
123 self
->variant_level
= 0;
125 variant_level
= PyDict_GetItem(kwargs
, dbus_py_variant_level_const
);
128 self
->variant_level
= PyInt_AsLong(variant_level
);
129 if (PyErr_Occurred()) {
130 Py_DECREF((PyObject
*)self
);
134 return (PyObject
*)self
;
138 Array_tp_init (DBusPyArray
*self
, PyObject
*args
, PyObject
*kwargs
)
140 PyObject
*obj
= dbus_py_empty_tuple
;
141 PyObject
*signature
= NULL
;
143 PyObject
*variant_level
;
144 /* variant_level is accepted but ignored - it's immutable, so
145 * __new__ handles it */
146 static char *argnames
[] = {"iterable", "signature", "variant_level", NULL
};
148 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "|OOO:__init__", argnames
,
149 &obj
, &signature
, &variant_level
)) {
153 /* convert signature from a borrowed ref of unknown type to an owned ref
154 of type Signature (or None) */
155 if (!signature
) signature
= Py_None
;
156 if (signature
== Py_None
157 || PyObject_IsInstance(signature
, (PyObject
*)&DBusPySignature_Type
)) {
158 Py_INCREF(signature
);
161 signature
= PyObject_CallFunction((PyObject
*)&DBusPySignature_Type
,
163 if (!signature
) return -1;
166 if (signature
!= Py_None
) {
167 const char *c_str
= PyString_AS_STRING(signature
);
169 if (!dbus_signature_validate_single(c_str
, NULL
)) {
170 Py_DECREF(signature
);
171 PyErr_SetString(PyExc_ValueError
,
172 "There must be exactly one complete type in "
173 "an Array's signature parameter");
178 tuple
= Py_BuildValue("(O)", obj
);
180 Py_DECREF(signature
);
183 if ((PyList_Type
.tp_init
)((PyObject
*)self
, tuple
, NULL
) < 0) {
185 Py_DECREF(signature
);
190 Py_XDECREF(self
->signature
);
191 self
->signature
= signature
;
195 PyTypeObject DBusPyArray_Type
= {
196 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type
))
201 (destructor
)Array_tp_dealloc
, /* tp_dealloc */
206 (reprfunc
)Array_tp_repr
, /* tp_repr */
207 0, /* tp_as_number */
208 0, /* tp_as_sequence */
209 0, /* tp_as_mapping */
215 0, /* tp_as_buffer */
216 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /* tp_flags */
217 Array_tp_doc
, /* tp_doc */
220 0, /* tp_richcompare */
221 0, /* tp_weaklistoffset */
225 Array_tp_members
, /* tp_members */
229 0, /* tp_descr_get */
230 0, /* tp_descr_set */
231 0, /* tp_dictoffset */
232 (initproc
)Array_tp_init
, /* tp_init */
234 Array_tp_new
, /* tp_new */
237 /* Dict ============================================================= */
239 PyDoc_STRVAR(Dict_tp_doc
,
240 "An mapping whose keys are similar and whose values are similar,\n"
241 "implemented as a subtype of dict.\n"
243 "As currently implemented, a Dictionary behaves just like a dict, but\n"
244 "with the addition of a ``signature`` property set by the constructor;\n"
245 "conversion of its items to D-Bus types is only done when it's sent in\n"
246 "a Message. This may change in future so validation is done earlier.\n"
250 " Dictionary(mapping_or_iterable=(), signature=None, variant_level=0)\n"
252 "``variant_level`` must be non-negative; the default is 0.\n"
254 "``signature`` is either a string or None. If a string, it must consist\n"
255 "of exactly two complete type signatures, representing the 'key' type\n"
256 "(which must be a primitive type, i.e. one of \"bd"
257 #ifdef WITH_DBUS_FLOAT32
261 "and the 'value' type. The signature of the whole Dictionary will be\n"
262 "``a{xx}`` where ``xx`` is replaced by the given signature.\n"
264 "If it is None (the default), when the Dictionary is sent over\n"
265 "D-Bus, the key and value signatures will be guessed from an arbitrary\n"
266 "element of the Dictionary.\n"
269 " `variant_level` : int\n"
270 " Indicates how many nested Variant containers this object\n"
271 " is contained in: if a message's wire format has a variant containing a\n"
272 " variant containing an array of DICT_ENTRY, this is represented in\n"
273 " Python by a Dictionary with variant_level==2.\n"
276 static struct PyMemberDef Dict_tp_members
[] = {
277 {"signature", T_OBJECT
, offsetof(DBusPyDict
, signature
), READONLY
,
278 "The D-Bus signature of each key in this Dictionary, followed by "
279 "that of each value in this Dictionary, as a Signature instance."},
280 {"variant_level", T_LONG
, offsetof(DBusPyDict
, variant_level
),
282 "The number of nested variants wrapping the real data. "
283 "0 if not in a variant."},
288 Dict_tp_dealloc (DBusPyDict
*self
)
290 Py_XDECREF(self
->signature
);
291 self
->signature
= NULL
;
292 (PyDict_Type
.tp_dealloc
)((PyObject
*)self
);
296 Dict_tp_repr(DBusPyDict
*self
)
298 PyObject
*parent_repr
= (PyDict_Type
.tp_repr
)((PyObject
*)self
);
299 PyObject
*sig_repr
= PyObject_Repr(self
->signature
);
300 PyObject
*my_repr
= NULL
;
301 long variant_level
= self
->variant_level
;
303 if (!parent_repr
) goto finally
;
304 if (!sig_repr
) goto finally
;
305 if (variant_level
> 0) {
306 my_repr
= PyString_FromFormat("%s(%s, signature=%s, "
307 "variant_level=%ld)",
308 self
->super
.ob_type
->tp_name
,
309 PyString_AS_STRING(parent_repr
),
310 PyString_AS_STRING(sig_repr
),
314 my_repr
= PyString_FromFormat("%s(%s, signature=%s)",
315 self
->super
.ob_type
->tp_name
,
316 PyString_AS_STRING(parent_repr
),
317 PyString_AS_STRING(sig_repr
));
320 Py_XDECREF(parent_repr
);
321 Py_XDECREF(sig_repr
);
326 Dict_tp_new(PyTypeObject
*cls
, PyObject
*args
, PyObject
*kwargs
)
328 DBusPyDict
*self
= (DBusPyDict
*)(PyDict_Type
.tp_new
)(cls
, args
, kwargs
);
329 PyObject
*variant_level
= NULL
;
331 /* variant_level is immutable, so handle it in __new__ rather than
333 if (!self
) return NULL
;
335 self
->signature
= Py_None
;
336 self
->variant_level
= 0;
338 variant_level
= PyDict_GetItem(kwargs
, dbus_py_variant_level_const
);
341 self
->variant_level
= PyInt_AsLong(variant_level
);
342 if (PyErr_Occurred()) {
343 Py_DECREF((PyObject
*)self
);
347 return (PyObject
*)self
;
351 Dict_tp_init(DBusPyDict
*self
, PyObject
*args
, PyObject
*kwargs
)
353 PyObject
*obj
= dbus_py_empty_tuple
;
354 PyObject
*signature
= NULL
;
356 PyObject
*variant_level
; /* ignored here - __new__ uses it */
357 static char *argnames
[] = {"mapping_or_iterable", "signature",
358 "variant_level", NULL
};
360 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "|OOO:__init__", argnames
,
361 &obj
, &signature
, &variant_level
)) {
365 /* convert signature from a borrowed ref of unknown type to an owned ref
366 of type Signature (or None) */
367 if (!signature
) signature
= Py_None
;
368 if (signature
== Py_None
369 || PyObject_IsInstance(signature
, (PyObject
*)&DBusPySignature_Type
)) {
370 Py_INCREF(signature
);
373 signature
= PyObject_CallFunction((PyObject
*)&DBusPySignature_Type
,
375 if (!signature
) return -1;
378 if (signature
!= Py_None
) {
379 const char *c_str
= PyString_AS_STRING(signature
);
383 case DBUS_TYPE_BOOLEAN
:
384 case DBUS_TYPE_INT16
:
385 case DBUS_TYPE_UINT16
:
386 case DBUS_TYPE_INT32
:
387 case DBUS_TYPE_UINT32
:
388 case DBUS_TYPE_INT64
:
389 case DBUS_TYPE_UINT64
:
390 case DBUS_TYPE_DOUBLE
:
391 #ifdef WITH_DBUS_FLOAT32
392 case DBUS_TYPE_FLOAT
:
394 case DBUS_TYPE_STRING
:
395 case DBUS_TYPE_OBJECT_PATH
:
396 case DBUS_TYPE_SIGNATURE
:
399 Py_DECREF(signature
);
400 PyErr_SetString(PyExc_ValueError
,
401 "The key type in a Dictionary's signature "
402 "must be a primitive type");
406 if (!dbus_signature_validate_single(c_str
+ 1, NULL
)) {
407 Py_DECREF(signature
);
408 PyErr_SetString(PyExc_ValueError
,
409 "There must be exactly two complete types in "
410 "a Dictionary's signature parameter");
415 tuple
= Py_BuildValue("(O)", obj
);
417 Py_DECREF(signature
);
421 if ((PyDict_Type
.tp_init((PyObject
*)self
, tuple
, NULL
)) < 0) {
423 Py_DECREF(signature
);
428 Py_XDECREF(self
->signature
);
429 self
->signature
= signature
;
433 PyTypeObject DBusPyDict_Type
= {
434 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type
))
439 (destructor
)Dict_tp_dealloc
, /* tp_dealloc */
444 (reprfunc
)Dict_tp_repr
, /* tp_repr */
445 0, /* tp_as_number */
446 0, /* tp_as_sequence */
447 0, /* tp_as_mapping */
453 0, /* tp_as_buffer */
454 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /* tp_flags */
455 Dict_tp_doc
, /* tp_doc */
458 0, /* tp_richcompare */
459 0, /* tp_weaklistoffset */
463 Dict_tp_members
, /* tp_members */
467 0, /* tp_descr_get */
468 0, /* tp_descr_set */
469 0, /* tp_dictoffset */
470 (initproc
)Dict_tp_init
, /* tp_init */
472 Dict_tp_new
, /* tp_new */
475 /* Struct =========================================================== */
477 static PyObject
*struct_signatures
;
479 PyDoc_STRVAR(Struct_tp_doc
,
480 "An structure containing items of possibly distinct types.\n"
484 " dbus.Struct(iterable, signature=None, variant_level=0) -> Struct\n"
486 "D-Bus structs may not be empty, so the iterable argument is required and\n"
487 "may not be an empty iterable.\n"
489 "``signature`` is either None, or a string representing the contents of the\n"
490 "struct as one or more complete type signatures. The overall signature of\n"
491 "the struct will be the given signature enclosed in parentheses, ``()``.\n"
493 "If the signature is None (default) it will be guessed\n"
494 "from the types of the items during construction.\n"
496 "``variant_level`` must be non-negative; the default is 0.\n"
499 " `variant_level` : int\n"
500 " Indicates how many nested Variant containers this object\n"
501 " is contained in: if a message's wire format has a variant containing a\n"
502 " variant containing a struct, this is represented in Python by a\n"
503 " Struct with variant_level==2.\n"
507 Struct_tp_repr(PyObject
*self
)
509 PyObject
*parent_repr
= (PyTuple_Type
.tp_repr
)((PyObject
*)self
);
511 PyObject
*sig_repr
= NULL
;
514 PyObject
*my_repr
= NULL
;
516 if (!parent_repr
) goto finally
;
517 key
= PyLong_FromVoidPtr(self
);
518 if (!key
) goto finally
;
519 sig
= PyDict_GetItem(struct_signatures
, key
);
521 if (!sig
) sig
= Py_None
;
522 sig_repr
= PyObject_Repr(sig
);
523 if (!sig_repr
) goto finally
;
524 variant_level
= dbus_py_variant_level_get(self
);
525 if (variant_level
> 0) {
526 my_repr
= PyString_FromFormat("%s(%s, signature=%s, "
527 "variant_level=%ld)",
528 self
->ob_type
->tp_name
,
529 PyString_AS_STRING(parent_repr
),
530 PyString_AS_STRING(sig_repr
),
534 my_repr
= PyString_FromFormat("%s(%s, signature=%s)",
535 self
->ob_type
->tp_name
,
536 PyString_AS_STRING(parent_repr
),
537 PyString_AS_STRING(sig_repr
));
541 Py_XDECREF(parent_repr
);
542 Py_XDECREF(sig_repr
);
547 Struct_tp_new (PyTypeObject
*cls
, PyObject
*args
, PyObject
*kwargs
)
549 PyObject
*signature
= NULL
;
550 long variantness
= 0;
551 PyObject
*self
, *key
;
552 static char *argnames
[] = {"signature", "variant_level", NULL
};
554 if (PyTuple_Size(args
) != 1) {
555 PyErr_SetString(PyExc_TypeError
,
556 "__new__ takes exactly one positional parameter");
559 if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple
, kwargs
,
560 "|Ol:__new__", argnames
,
561 &signature
, &variantness
)) {
564 if (variantness
< 0) {
565 PyErr_SetString(PyExc_ValueError
,
566 "variant_level must be non-negative");
570 self
= (PyTuple_Type
.tp_new
)(cls
, args
, NULL
);
573 if (PyTuple_Size(self
) < 1) {
574 PyErr_SetString(PyExc_ValueError
, "D-Bus structs may not be empty");
579 if (!dbus_py_variant_level_set(self
, variantness
)) {
584 /* convert signature from a borrowed ref of unknown type to an owned ref
585 of type Signature (or None) */
586 if (!signature
) signature
= Py_None
;
587 if (signature
== Py_None
588 || PyObject_IsInstance(signature
, (PyObject
*)&DBusPySignature_Type
)) {
589 Py_INCREF(signature
);
592 signature
= PyObject_CallFunction((PyObject
*)&DBusPySignature_Type
,
600 key
= PyLong_FromVoidPtr(self
);
603 Py_DECREF(signature
);
606 if (PyDict_SetItem(struct_signatures
, key
, signature
) < 0) {
609 Py_DECREF(signature
);
614 Py_DECREF(signature
);
619 Struct_tp_dealloc(PyObject
*self
)
621 PyObject
*et
, *ev
, *etb
, *key
;
623 dbus_py_variant_level_clear(self
);
624 PyErr_Fetch(&et
, &ev
, &etb
);
626 key
= PyLong_FromVoidPtr(self
);
628 if (PyDict_GetItem(struct_signatures
, key
)) {
629 if (PyDict_DelItem(struct_signatures
, key
) < 0) {
630 /* should never happen */
631 PyErr_WriteUnraisable(self
);
637 /* not enough memory to free all the memory... leak the signature,
638 * there's not much else we could do here */
639 PyErr_WriteUnraisable(self
);
642 PyErr_Restore(et
, ev
, etb
);
643 (PyTuple_Type
.tp_dealloc
)(self
);
647 Struct_tp_getattro(PyObject
*obj
, PyObject
*name
)
649 PyObject
*key
, *value
;
651 if (PyString_Check(name
)) {
654 else if (PyUnicode_Check(name
)) {
655 name
= PyUnicode_AsEncodedString(name
, NULL
, NULL
);
661 PyErr_SetString(PyExc_TypeError
, "attribute name must be string");
665 if (strcmp(PyString_AS_STRING(name
), "signature")) {
666 value
= dbus_py_variant_level_getattro(obj
, name
);
673 key
= PyLong_FromVoidPtr(obj
);
679 value
= PyDict_GetItem(struct_signatures
, key
);
688 PyTypeObject DBusPyStruct_Type
= {
689 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type
))
694 Struct_tp_dealloc
, /* tp_dealloc */
699 (reprfunc
)Struct_tp_repr
, /* tp_repr */
700 0, /* tp_as_number */
701 0, /* tp_as_sequence */
702 0, /* tp_as_mapping */
706 Struct_tp_getattro
, /* tp_getattro */
707 dbus_py_immutable_setattro
, /* tp_setattro */
708 0, /* tp_as_buffer */
709 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /* tp_flags */
710 Struct_tp_doc
, /* tp_doc */
713 0, /* tp_richcompare */
714 0, /* tp_weaklistoffset */
722 0, /* tp_descr_get */
723 0, /* tp_descr_set */
724 0, /* tp_dictoffset */
727 Struct_tp_new
, /* tp_new */
731 dbus_py_init_container_types(void)
733 struct_signatures
= PyDict_New();
734 if (!struct_signatures
) return 0;
736 DBusPyArray_Type
.tp_base
= &PyList_Type
;
737 if (PyType_Ready(&DBusPyArray_Type
) < 0) return 0;
738 DBusPyArray_Type
.tp_print
= NULL
;
740 DBusPyDict_Type
.tp_base
= &PyDict_Type
;
741 if (PyType_Ready(&DBusPyDict_Type
) < 0) return 0;
742 DBusPyDict_Type
.tp_print
= NULL
;
744 DBusPyStruct_Type
.tp_base
= &PyTuple_Type
;
745 if (PyType_Ready(&DBusPyStruct_Type
) < 0) return 0;
746 DBusPyStruct_Type
.tp_print
= NULL
;
752 dbus_py_insert_container_types(PyObject
*this_module
)
754 Py_INCREF(&DBusPyArray_Type
);
755 if (PyModule_AddObject(this_module
, "Array",
756 (PyObject
*)&DBusPyArray_Type
) < 0) return 0;
758 Py_INCREF(&DBusPyDict_Type
);
759 if (PyModule_AddObject(this_module
, "Dictionary",
760 (PyObject
*)&DBusPyDict_Type
) < 0) return 0;
762 Py_INCREF(&DBusPyStruct_Type
);
763 if (PyModule_AddObject(this_module
, "Struct",
764 (PyObject
*)&DBusPyStruct_Type
) < 0) return 0;
769 /* vim:set ft=c cino< sw=4 sts=4 et: */