1 /* Subclasses of built-in Python types supporting extra D-Bus functionality.
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 /* Dict indexed by object IDs, whose values are nonzero variant levels
35 * for immutable variable-sized D-Bus data types (_LongBase, _StrBase, Struct).
37 * This is a strange way to store them, but adding a __dict__ to the offending
38 * objects seems even more error-prone, given that their sizes are variable!
40 PyObject
*_dbus_py_variant_levels
= NULL
;
43 dbus_py_variant_level_get(PyObject
*obj
)
46 PyObject
*key
= PyLong_FromVoidPtr(obj
);
52 vl_obj
= PyDict_GetItem(_dbus_py_variant_levels
, key
);
57 return PyInt_AsLong(vl_obj
);
61 dbus_py_variant_level_set(PyObject
*obj
, long variant_level
)
63 /* key is the object's ID (= pointer) to avoid referencing it */
64 PyObject
*key
= PyLong_FromVoidPtr(obj
);
70 if (variant_level
<= 0) {
71 if (PyDict_GetItem (_dbus_py_variant_levels
, key
)) {
72 if (PyDict_DelItem (_dbus_py_variant_levels
, key
) < 0) {
79 PyObject
*vl_obj
= PyInt_FromLong(variant_level
);
84 if (PyDict_SetItem (_dbus_py_variant_levels
, key
, vl_obj
) < 0) {
94 dbus_py_variant_level_getattro(PyObject
*obj
, PyObject
*name
)
96 PyObject
*key
, *value
;
98 if (PyString_Check(name
)) {
101 else if (PyUnicode_Check(name
)) {
102 name
= PyUnicode_AsEncodedString(name
, NULL
, NULL
);
108 PyErr_SetString(PyExc_TypeError
, "attribute name must be string");
112 if (strcmp(PyString_AS_STRING(name
), "variant_level")) {
113 value
= PyObject_GenericGetAttr(obj
, name
);
120 key
= PyLong_FromVoidPtr(obj
);
126 value
= PyDict_GetItem(_dbus_py_variant_levels
, key
);
130 return PyInt_FromLong(0);
135 /* To be invoked by destructors. Clear the variant level without touching the
138 dbus_py_variant_level_clear(PyObject
*self
)
140 PyObject
*et
, *ev
, *etb
;
142 /* avoid clobbering any pending exception */
143 PyErr_Fetch(&et
, &ev
, &etb
);
144 if (!dbus_py_variant_level_set(self
, 0)) {
145 /* should never happen */
146 PyErr_WriteUnraisable(self
);
148 PyErr_Restore(et
, ev
, etb
);
151 /* Support code for int subclasses. ================================== */
153 PyDoc_STRVAR(DBusPythonInt_tp_doc
,\
154 "Base class for int subclasses with a ``variant_level`` attribute.\n"
155 "Do not rely on the existence of this class outside dbus-python.\n"
158 static PyMemberDef DBusPythonInt_tp_members
[] = {
159 {"variant_level", T_LONG
, offsetof(DBusPyIntBase
, variant_level
),
161 "The number of nested variants wrapping the real data. "
162 "0 if not in a variant."},
167 DBusPythonInt_tp_new(PyTypeObject
*cls
, PyObject
*args
, PyObject
*kwargs
)
170 long variantness
= 0;
171 static char *argnames
[] = {"variant_level", NULL
};
173 if (PyTuple_Size(args
) > 1) {
174 PyErr_SetString(PyExc_TypeError
,
175 "__new__ takes at most one positional parameter");
178 if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple
, kwargs
,
179 "|l:__new__", argnames
,
180 &variantness
)) return NULL
;
181 if (variantness
< 0) {
182 PyErr_SetString(PyExc_ValueError
,
183 "variant_level must be non-negative");
187 self
= (PyInt_Type
.tp_new
)(cls
, args
, NULL
);
189 ((DBusPyIntBase
*)self
)->variant_level
= variantness
;
195 DBusPythonInt_tp_repr(PyObject
*self
)
197 PyObject
*parent_repr
= (PyInt_Type
.tp_repr
)(self
);
198 long variant_level
= ((DBusPyIntBase
*)self
)->variant_level
;
201 if (!parent_repr
) return NULL
;
202 if (variant_level
> 0) {
203 my_repr
= PyString_FromFormat("%s(%s, variant_level=%ld)",
204 self
->ob_type
->tp_name
,
205 PyString_AS_STRING(parent_repr
),
209 my_repr
= PyString_FromFormat("%s(%s)", self
->ob_type
->tp_name
,
210 PyString_AS_STRING(parent_repr
));
212 /* whether my_repr is NULL or not: */
213 Py_DECREF(parent_repr
);
217 PyTypeObject DBusPyIntBase_Type
= {
218 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type
))
220 "_dbus_bindings._IntBase",
221 sizeof(DBusPyIntBase
),
228 DBusPythonInt_tp_repr
, /* tp_repr */
229 0, /* tp_as_number */
230 0, /* tp_as_sequence */
231 0, /* tp_as_mapping */
237 0, /* tp_as_buffer */
238 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /* tp_flags */
239 DBusPythonInt_tp_doc
, /* tp_doc */
242 0, /* tp_richcompare */
243 0, /* tp_weaklistoffset */
247 DBusPythonInt_tp_members
, /* tp_members */
249 DEFERRED_ADDRESS(&PyInt_Type
), /* tp_base */
251 0, /* tp_descr_get */
252 0, /* tp_descr_set */
253 0, /* tp_dictoffset */
255 PyType_GenericAlloc
, /* tp_alloc */
256 DBusPythonInt_tp_new
, /* tp_new */
257 PyObject_Del
, /* tp_free */
260 /* Support code for float subclasses. ================================ */
262 /* There's only one subclass at the moment (Double) but these are factored
263 out to make room for Float later. (Float is implemented and #if'd out) */
265 PyDoc_STRVAR(DBusPythonFloat_tp_doc
,\
266 "Base class for float subclasses with a ``variant_level`` attribute.\n"
267 "Do not rely on the existence of this class outside dbus-python.\n"
270 static PyMemberDef DBusPythonFloat_tp_members
[] = {
271 {"variant_level", T_LONG
, offsetof(DBusPyFloatBase
, variant_level
),
273 "The number of nested variants wrapping the real data. "
274 "0 if not in a variant."},
279 DBusPythonFloat_tp_new(PyTypeObject
*cls
, PyObject
*args
, PyObject
*kwargs
)
282 long variantness
= 0;
283 static char *argnames
[] = {"variant_level", NULL
};
285 if (PyTuple_Size(args
) > 1) {
286 PyErr_SetString(PyExc_TypeError
,
287 "__new__ takes at most one positional parameter");
290 if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple
, kwargs
,
291 "|l:__new__", argnames
,
292 &variantness
)) return NULL
;
293 if (variantness
< 0) {
294 PyErr_SetString(PyExc_ValueError
,
295 "variant_level must be non-negative");
299 self
= (PyFloat_Type
.tp_new
)(cls
, args
, NULL
);
301 ((DBusPyFloatBase
*)self
)->variant_level
= variantness
;
307 DBusPythonFloat_tp_repr(PyObject
*self
)
309 PyObject
*parent_repr
= (PyFloat_Type
.tp_repr
)(self
);
310 long variant_level
= ((DBusPyFloatBase
*)self
)->variant_level
;
313 if (!parent_repr
) return NULL
;
314 if (variant_level
> 0) {
315 my_repr
= PyString_FromFormat("%s(%s, variant_level=%ld)",
316 self
->ob_type
->tp_name
,
317 PyString_AS_STRING(parent_repr
),
321 my_repr
= PyString_FromFormat("%s(%s)", self
->ob_type
->tp_name
,
322 PyString_AS_STRING(parent_repr
));
324 /* whether my_repr is NULL or not: */
325 Py_DECREF(parent_repr
);
329 PyTypeObject DBusPyFloatBase_Type
= {
330 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type
))
332 "_dbus_bindings._FloatBase",
333 sizeof(DBusPyFloatBase
),
340 DBusPythonFloat_tp_repr
, /* tp_repr */
341 0, /* tp_as_number */
342 0, /* tp_as_sequence */
343 0, /* tp_as_mapping */
349 0, /* tp_as_buffer */
350 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /* tp_flags */
351 DBusPythonFloat_tp_doc
, /* tp_doc */
354 0, /* tp_richcompare */
355 0, /* tp_weaklistoffset */
359 DBusPythonFloat_tp_members
, /* tp_members */
361 DEFERRED_ADDRESS(&PyFloat_Type
), /* tp_base */
363 0, /* tp_descr_get */
364 0, /* tp_descr_set */
365 0, /* tp_dictoffset */
368 DBusPythonFloat_tp_new
, /* tp_new */
371 /* Support code for str subclasses ================================== */
373 PyDoc_STRVAR(DBusPythonString_tp_doc
,\
374 "Base class for str subclasses with a ``variant_level`` attribute.\n"
375 "Do not rely on the existence of this class outside dbus-python.\n"
379 DBusPythonString_tp_new(PyTypeObject
*cls
, PyObject
*args
, PyObject
*kwargs
)
382 long variantness
= 0;
383 static char *argnames
[] = {"variant_level", NULL
};
385 if (PyTuple_Size(args
) > 1) {
386 PyErr_SetString(PyExc_TypeError
,
387 "__new__ takes at most one positional parameter");
390 if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple
, kwargs
,
391 "|l:__new__", argnames
,
392 &variantness
)) return NULL
;
393 if (variantness
< 0) {
394 PyErr_SetString(PyExc_ValueError
,
395 "variant_level must be non-negative");
399 self
= (PyString_Type
.tp_new
)(cls
, args
, NULL
);
401 if (!dbus_py_variant_level_set(self
, variantness
)) {
410 DBusPythonString_tp_repr(PyObject
*self
)
412 PyObject
*parent_repr
= (PyString_Type
.tp_repr
)(self
);
417 if (!parent_repr
) return NULL
;
418 vl_obj
= PyObject_GetAttr(self
, dbus_py_variant_level_const
);
420 Py_DECREF(parent_repr
);
423 variant_level
= PyInt_AsLong(vl_obj
);
425 if (variant_level
> 0) {
426 my_repr
= PyString_FromFormat("%s(%s, variant_level=%ld)",
427 self
->ob_type
->tp_name
,
428 PyString_AS_STRING(parent_repr
),
432 my_repr
= PyString_FromFormat("%s(%s)", self
->ob_type
->tp_name
,
433 PyString_AS_STRING(parent_repr
));
435 /* whether my_repr is NULL or not: */
436 Py_DECREF(parent_repr
);
441 DBusPyStrBase_tp_dealloc(PyObject
*self
)
443 dbus_py_variant_level_clear(self
);
444 (PyString_Type
.tp_dealloc
)(self
);
447 PyTypeObject DBusPyStrBase_Type
= {
448 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type
))
450 "_dbus_bindings._StrBase",
453 DBusPyStrBase_tp_dealloc
, /* tp_dealloc */
458 DBusPythonString_tp_repr
, /* tp_repr */
459 0, /* tp_as_number */
460 0, /* tp_as_sequence */
461 0, /* tp_as_mapping */
465 dbus_py_variant_level_getattro
, /* tp_getattro */
466 dbus_py_immutable_setattro
, /* tp_setattro */
467 0, /* tp_as_buffer */
468 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /* tp_flags */
469 DBusPythonString_tp_doc
, /* tp_doc */
472 0, /* tp_richcompare */
473 0, /* tp_weaklistoffset */
479 DEFERRED_ADDRESS(&PyString_Type
), /* tp_base */
481 0, /* tp_descr_get */
482 0, /* tp_descr_set */
483 0, /* tp_dictoffset */
486 DBusPythonString_tp_new
, /* tp_new */
489 /* Support code for long subclasses ================================= */
491 PyDoc_STRVAR(DBusPythonLong_tp_doc
,\
492 "Base class for ``long`` subclasses with a ``variant_level`` attribute.\n"
493 "Do not rely on the existence of this class outside dbus-python.\n"
497 DBusPythonLong_tp_new(PyTypeObject
*cls
, PyObject
*args
, PyObject
*kwargs
)
500 long variantness
= 0;
501 static char *argnames
[] = {"variant_level", NULL
};
503 if (PyTuple_Size(args
) > 1) {
504 PyErr_SetString(PyExc_TypeError
,
505 "__new__ takes at most one positional parameter");
508 if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple
, kwargs
,
509 "|l:__new__", argnames
,
510 &variantness
)) return NULL
;
511 if (variantness
< 0) {
512 PyErr_SetString(PyExc_ValueError
,
513 "variant_level must be non-negative");
517 self
= (PyLong_Type
.tp_new
)(cls
, args
, NULL
);
519 if (!dbus_py_variant_level_set(self
, variantness
)) {
528 DBusPythonLong_tp_repr(PyObject
*self
)
530 PyObject
*parent_repr
= (PyLong_Type
.tp_repr
)(self
);
535 if (!parent_repr
) return NULL
;
536 vl_obj
= PyObject_GetAttr(self
, dbus_py_variant_level_const
);
538 Py_DECREF(parent_repr
);
541 variant_level
= PyInt_AsLong(vl_obj
);
544 my_repr
= PyString_FromFormat("%s(%s, variant_level=%ld)",
545 self
->ob_type
->tp_name
,
546 PyString_AS_STRING(parent_repr
),
550 my_repr
= PyString_FromFormat("%s(%s)", self
->ob_type
->tp_name
,
551 PyString_AS_STRING(parent_repr
));
553 /* whether my_repr is NULL or not: */
554 Py_DECREF(parent_repr
);
559 DBusPyLongBase_tp_dealloc(PyObject
*self
)
561 dbus_py_variant_level_clear(self
);
562 (PyLong_Type
.tp_dealloc
)(self
);
565 PyTypeObject DBusPyLongBase_Type
= {
566 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type
))
568 "_dbus_bindings._LongBase",
571 DBusPyLongBase_tp_dealloc
, /* tp_dealloc */
576 DBusPythonLong_tp_repr
, /* tp_repr */
577 0, /* tp_as_number */
578 0, /* tp_as_sequence */
579 0, /* tp_as_mapping */
583 dbus_py_variant_level_getattro
, /* tp_getattro */
584 dbus_py_immutable_setattro
, /* tp_setattro */
585 0, /* tp_as_buffer */
586 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /* tp_flags */
587 DBusPythonLong_tp_doc
, /* tp_doc */
590 0, /* tp_richcompare */
591 0, /* tp_weaklistoffset */
597 DEFERRED_ADDRESS(&PyLong_Type
), /* tp_base */
599 0, /* tp_descr_get */
600 0, /* tp_descr_set */
601 0, /* tp_dictoffset */
604 DBusPythonLong_tp_new
, /* tp_new */
607 PyObject
*dbus_py_variant_level_const
= NULL
;
608 PyObject
*dbus_py_signature_const
= NULL
;
609 PyObject
*dbus_py__dbus_object_path__const
= NULL
;
612 dbus_py_init_abstract(void)
614 _dbus_py_variant_levels
= PyDict_New();
615 if (!_dbus_py_variant_levels
) return 0;
617 dbus_py__dbus_object_path__const
= PyString_InternFromString("__dbus_object_path__");
618 if (!dbus_py__dbus_object_path__const
) return 0;
620 dbus_py_variant_level_const
= PyString_InternFromString("variant_level");
621 if (!dbus_py_variant_level_const
) return 0;
623 dbus_py_signature_const
= PyString_InternFromString("signature");
624 if (!dbus_py_signature_const
) return 0;
626 DBusPyIntBase_Type
.tp_base
= &PyInt_Type
;
627 if (PyType_Ready(&DBusPyIntBase_Type
) < 0) return 0;
628 /* disable the tp_print copied from PyInt_Type, so tp_repr gets called as
630 DBusPyIntBase_Type
.tp_print
= NULL
;
632 DBusPyFloatBase_Type
.tp_base
= &PyFloat_Type
;
633 if (PyType_Ready(&DBusPyFloatBase_Type
) < 0) return 0;
634 DBusPyFloatBase_Type
.tp_print
= NULL
;
636 DBusPyLongBase_Type
.tp_base
= &PyLong_Type
;
637 if (PyType_Ready(&DBusPyLongBase_Type
) < 0) return 0;
638 DBusPyLongBase_Type
.tp_print
= NULL
;
640 DBusPyStrBase_Type
.tp_base
= &PyString_Type
;
641 if (PyType_Ready(&DBusPyStrBase_Type
) < 0) return 0;
642 DBusPyStrBase_Type
.tp_print
= NULL
;
648 dbus_py_insert_abstract_types(PyObject
*this_module
)
650 Py_INCREF(&DBusPyIntBase_Type
);
651 Py_INCREF(&DBusPyLongBase_Type
);
652 Py_INCREF(&DBusPyStrBase_Type
);
653 Py_INCREF(&DBusPyFloatBase_Type
);
654 if (PyModule_AddObject(this_module
, "_IntBase",
655 (PyObject
*)&DBusPyIntBase_Type
) < 0) return 0;
656 if (PyModule_AddObject(this_module
, "_LongBase",
657 (PyObject
*)&DBusPyLongBase_Type
) < 0) return 0;
658 if (PyModule_AddObject(this_module
, "_StrBase",
659 (PyObject
*)&DBusPyStrBase_Type
) < 0) return 0;
660 if (PyModule_AddObject(this_module
, "_FloatBase",
661 (PyObject
*)&DBusPyFloatBase_Type
) < 0) return 0;