Update NEWS for 0.81.0
[dbus-python-phuang.git] / _dbus_bindings / abstract.c
blob392f4c74325c12c33c6cf415b844b77af729a24a
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
23 #include <Python.h>
24 #include <structmember.h>
26 #include <stdint.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;
39 long
40 dbus_py_variant_level_get(PyObject *obj)
42 PyObject *vl_obj;
43 PyObject *key = PyLong_FromVoidPtr(obj);
45 if (!key) {
46 return 0;
49 vl_obj = PyDict_GetItem(_dbus_py_variant_levels, key);
50 Py_DECREF(key);
52 if (!vl_obj)
53 return 0;
54 return PyInt_AsLong(vl_obj);
57 dbus_bool_t
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);
63 if (!key) {
64 return FALSE;
67 if (variant_level <= 0) {
68 if (PyDict_GetItem (_dbus_py_variant_levels, key)) {
69 if (PyDict_DelItem (_dbus_py_variant_levels, key) < 0) {
70 Py_DECREF(key);
71 return FALSE;
75 else {
76 PyObject *vl_obj = PyInt_FromLong(variant_level);
77 if (!vl_obj) {
78 Py_DECREF(key);
79 return FALSE;
81 if (PyDict_SetItem (_dbus_py_variant_levels, key, vl_obj) < 0) {
82 Py_DECREF(key);
83 return FALSE;
86 Py_DECREF(key);
87 return TRUE;
90 PyObject *
91 dbus_py_variant_level_getattro(PyObject *obj, PyObject *name)
93 PyObject *key, *value;
95 if (PyString_Check(name)) {
96 Py_INCREF(name);
98 else if (PyUnicode_Check(name)) {
99 name = PyUnicode_AsEncodedString(name, NULL, NULL);
100 if (!name) {
101 return NULL;
104 else {
105 PyErr_SetString(PyExc_TypeError, "attribute name must be string");
106 return NULL;
109 if (strcmp(PyString_AS_STRING(name), "variant_level")) {
110 value = PyObject_GenericGetAttr(obj, name);
111 Py_DECREF(name);
112 return value;
115 Py_DECREF(name);
117 key = PyLong_FromVoidPtr(obj);
119 if (!key) {
120 return NULL;
123 value = PyDict_GetItem(_dbus_py_variant_levels, key);
124 Py_DECREF(key);
126 if (!value)
127 return PyInt_FromLong(0);
128 Py_INCREF(value);
129 return value;
132 /* To be invoked by destructors. Clear the variant level without touching the
133 * exception state */
134 void
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),
157 READONLY,
158 "The number of nested variants wrapping the real data. "
159 "0 if not in a variant."},
160 {NULL},
163 static PyObject *
164 DBusPythonInt_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
166 PyObject *self;
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");
173 return NULL;
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");
181 return NULL;
184 self = (PyInt_Type.tp_new)(cls, args, NULL);
185 if (self) {
186 ((DBusPyIntBase *)self)->variant_level = variantness;
188 return self;
191 static PyObject *
192 DBusPythonInt_tp_repr(PyObject *self)
194 PyObject *parent_repr = (PyInt_Type.tp_repr)(self);
195 long variant_level = ((DBusPyIntBase *)self)->variant_level;
196 PyObject *my_repr;
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),
203 variant_level);
205 else {
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);
211 return my_repr;
214 PyTypeObject DBusPyIntBase_Type = {
215 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
217 "_dbus_bindings._IntBase",
218 sizeof(DBusPyIntBase),
220 0, /* tp_dealloc */
221 0, /* tp_print */
222 0, /* tp_getattr */
223 0, /* tp_setattr */
224 0, /* tp_compare */
225 DBusPythonInt_tp_repr, /* tp_repr */
226 0, /* tp_as_number */
227 0, /* tp_as_sequence */
228 0, /* tp_as_mapping */
229 0, /* tp_hash */
230 0, /* tp_call */
231 0, /* tp_str */
232 0, /* tp_getattro */
233 0, /* tp_setattro */
234 0, /* tp_as_buffer */
235 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
236 DBusPythonInt_tp_doc, /* tp_doc */
237 0, /* tp_traverse */
238 0, /* tp_clear */
239 0, /* tp_richcompare */
240 0, /* tp_weaklistoffset */
241 0, /* tp_iter */
242 0, /* tp_iternext */
243 0, /* tp_methods */
244 DBusPythonInt_tp_members, /* tp_members */
245 0, /* tp_getset */
246 DEFERRED_ADDRESS(&PyInt_Type), /* tp_base */
247 0, /* tp_dict */
248 0, /* tp_descr_get */
249 0, /* tp_descr_set */
250 0, /* tp_dictoffset */
251 0, /* tp_init */
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),
269 READONLY,
270 "The number of nested variants wrapping the real data. "
271 "0 if not in a variant."},
272 {NULL},
275 static PyObject *
276 DBusPythonFloat_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
278 PyObject *self;
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");
285 return NULL;
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");
293 return NULL;
296 self = (PyFloat_Type.tp_new)(cls, args, NULL);
297 if (self) {
298 ((DBusPyFloatBase *)self)->variant_level = variantness;
300 return self;
303 static PyObject *
304 DBusPythonFloat_tp_repr(PyObject *self)
306 PyObject *parent_repr = (PyFloat_Type.tp_repr)(self);
307 long variant_level = ((DBusPyFloatBase *)self)->variant_level;
308 PyObject *my_repr;
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),
315 variant_level);
317 else {
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);
323 return my_repr;
326 PyTypeObject DBusPyFloatBase_Type = {
327 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
329 "_dbus_bindings._FloatBase",
330 sizeof(DBusPyFloatBase),
332 0, /* tp_dealloc */
333 0, /* tp_print */
334 0, /* tp_getattr */
335 0, /* tp_setattr */
336 0, /* tp_compare */
337 DBusPythonFloat_tp_repr, /* tp_repr */
338 0, /* tp_as_number */
339 0, /* tp_as_sequence */
340 0, /* tp_as_mapping */
341 0, /* tp_hash */
342 0, /* tp_call */
343 0, /* tp_str */
344 0, /* tp_getattro */
345 0, /* tp_setattro */
346 0, /* tp_as_buffer */
347 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
348 DBusPythonFloat_tp_doc, /* tp_doc */
349 0, /* tp_traverse */
350 0, /* tp_clear */
351 0, /* tp_richcompare */
352 0, /* tp_weaklistoffset */
353 0, /* tp_iter */
354 0, /* tp_iternext */
355 0, /* tp_methods */
356 DBusPythonFloat_tp_members, /* tp_members */
357 0, /* tp_getset */
358 DEFERRED_ADDRESS(&PyFloat_Type), /* tp_base */
359 0, /* tp_dict */
360 0, /* tp_descr_get */
361 0, /* tp_descr_set */
362 0, /* tp_dictoffset */
363 0, /* tp_init */
364 0, /* tp_alloc */
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"
375 static PyObject *
376 DBusPythonString_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
378 PyObject *self;
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");
385 return NULL;
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");
393 return NULL;
396 self = (PyString_Type.tp_new)(cls, args, NULL);
397 if (self) {
398 if (!dbus_py_variant_level_set(self, variantness)) {
399 Py_DECREF(self);
400 return NULL;
403 return self;
406 static PyObject *
407 DBusPythonString_tp_repr(PyObject *self)
409 PyObject *parent_repr = (PyString_Type.tp_repr)(self);
410 PyObject *vl_obj;
411 PyObject *my_repr;
412 long variant_level;
414 if (!parent_repr) return NULL;
415 vl_obj = PyObject_GetAttr(self, dbus_py_variant_level_const);
416 if (!vl_obj) {
417 Py_DECREF(parent_repr);
418 return NULL;
420 variant_level = PyInt_AsLong(vl_obj);
421 Py_DECREF(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),
426 variant_level);
428 else {
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);
434 return my_repr;
437 static void
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 */
451 0, /* tp_print */
452 0, /* tp_getattr */
453 0, /* tp_setattr */
454 0, /* tp_compare */
455 DBusPythonString_tp_repr, /* tp_repr */
456 0, /* tp_as_number */
457 0, /* tp_as_sequence */
458 0, /* tp_as_mapping */
459 0, /* tp_hash */
460 0, /* tp_call */
461 0, /* tp_str */
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 */
467 0, /* tp_traverse */
468 0, /* tp_clear */
469 0, /* tp_richcompare */
470 0, /* tp_weaklistoffset */
471 0, /* tp_iter */
472 0, /* tp_iternext */
473 0, /* tp_methods */
474 0, /* tp_members */
475 0, /* tp_getset */
476 DEFERRED_ADDRESS(&PyString_Type), /* tp_base */
477 0, /* tp_dict */
478 0, /* tp_descr_get */
479 0, /* tp_descr_set */
480 0, /* tp_dictoffset */
481 0, /* tp_init */
482 0, /* tp_alloc */
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"
493 static PyObject *
494 DBusPythonLong_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
496 PyObject *self;
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");
503 return NULL;
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");
511 return NULL;
514 self = (PyLong_Type.tp_new)(cls, args, NULL);
515 if (self) {
516 if (!dbus_py_variant_level_set(self, variantness)) {
517 Py_DECREF(self);
518 return NULL;
521 return self;
524 static PyObject *
525 DBusPythonLong_tp_repr(PyObject *self)
527 PyObject *parent_repr = (PyLong_Type.tp_repr)(self);
528 PyObject *vl_obj;
529 PyObject *my_repr;
530 long variant_level;
532 if (!parent_repr) return NULL;
533 vl_obj = PyObject_GetAttr(self, dbus_py_variant_level_const);
534 if (!vl_obj) {
535 Py_DECREF(parent_repr);
536 return NULL;
538 variant_level = PyInt_AsLong(vl_obj);
539 Py_DECREF(vl_obj);
540 if (variant_level) {
541 my_repr = PyString_FromFormat("%s(%s, variant_level=%ld)",
542 self->ob_type->tp_name,
543 PyString_AS_STRING(parent_repr),
544 variant_level);
546 else {
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);
552 return my_repr;
555 static void
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 */
569 0, /* tp_print */
570 0, /* tp_getattr */
571 0, /* tp_setattr */
572 0, /* tp_compare */
573 DBusPythonLong_tp_repr, /* tp_repr */
574 0, /* tp_as_number */
575 0, /* tp_as_sequence */
576 0, /* tp_as_mapping */
577 0, /* tp_hash */
578 0, /* tp_call */
579 0, /* tp_str */
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 */
585 0, /* tp_traverse */
586 0, /* tp_clear */
587 0, /* tp_richcompare */
588 0, /* tp_weaklistoffset */
589 0, /* tp_iter */
590 0, /* tp_iternext */
591 0, /* tp_methods */
592 0, /* tp_members */
593 0, /* tp_getset */
594 DEFERRED_ADDRESS(&PyLong_Type), /* tp_base */
595 0, /* tp_dict */
596 0, /* tp_descr_get */
597 0, /* tp_descr_set */
598 0, /* tp_dictoffset */
599 0, /* tp_init */
600 0, /* tp_alloc */
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;
608 dbus_bool_t
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
626 desired */
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;
641 return 1;
644 dbus_bool_t
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;
660 return 1;