diff options
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | NEWS | 16 | ||||
-rw-r--r-- | _dbus_bindings/abstract.c | 384 | ||||
-rw-r--r-- | _dbus_bindings/bytes.c | 299 | ||||
-rw-r--r-- | _dbus_bindings/conn-methods.c | 427 | ||||
-rw-r--r-- | _dbus_bindings/containers.c | 771 | ||||
-rw-r--r-- | _dbus_bindings/dbus_bindings-internal.h | 86 | ||||
-rw-r--r-- | _dbus_bindings/float.c | 184 | ||||
-rw-r--r-- | _dbus_bindings/int.c | 912 | ||||
-rw-r--r-- | _dbus_bindings/message-append.c | 123 | ||||
-rw-r--r-- | _dbus_bindings/message-get-args.c | 144 | ||||
-rw-r--r-- | _dbus_bindings/message.c | 6 | ||||
-rw-r--r-- | _dbus_bindings/module.c | 21 | ||||
-rw-r--r-- | _dbus_bindings/signature.c | 181 | ||||
-rw-r--r-- | _dbus_bindings/string.c | 455 | ||||
-rw-r--r-- | _dbus_bindings/types-internal.h | 36 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | dbus/__init__.py | 10 | ||||
-rw-r--r-- | dbus/_dbus.py | 3 | ||||
-rw-r--r-- | dbus/connection.py | 297 | ||||
-rw-r--r-- | dbus/data.py | 564 | ||||
-rw-r--r-- | dbus/dbus_bindings.py | 2 | ||||
-rw-r--r-- | dbus/decorators.py | 5 | ||||
-rw-r--r-- | dbus/service.py | 11 | ||||
-rw-r--r-- | dbus/types.py | 17 | ||||
-rw-r--r-- | test/cross-test-client.py | 11 | ||||
-rwxr-xr-x | test/test-standalone.py | 2 |
27 files changed, 1919 insertions, 3051 deletions
diff --git a/Makefile.am b/Makefile.am index fff5e2b..45fa47b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -21,6 +21,7 @@ nobase_python_PYTHON = \ dbus_bindings.py \ dbus/bus.py \ dbus/connection.py \ + dbus/data.py \ dbus/dbus_bindings.py \ dbus/_dbus.py \ dbus/_version.py \ @@ -1,3 +1,19 @@ +D-Bus Python Bindings, 'purity' branch (unreleased) +=================================================== + +* Implement the object-path tree, and user filters, in pure Python +* Refactor _dbus_bindings to facilitate porting types to pure Python + +Roadmap: + +* Port types to pure Python +* Implement parameterized types +* Implement signature parsing and signature <-> type-sequence round trip in + pure Python +* Implement message argument coercion in pure Python +* Implement message serialization and deserialization in pure Python + (may need to be conditional on having dbus >= 1.1) + D-Bus Python Bindings 0.82.4 (unreleased) ========================================= diff --git a/_dbus_bindings/abstract.c b/_dbus_bindings/abstract.c index 9a4f350..f88bd8e 100644 --- a/_dbus_bindings/abstract.c +++ b/_dbus_bindings/abstract.c @@ -148,226 +148,6 @@ dbus_py_variant_level_clear(PyObject *self) PyErr_Restore(et, ev, etb); } -/* Support code for int subclasses. ================================== */ - -PyDoc_STRVAR(DBusPythonInt_tp_doc,\ -"Base class for int subclasses with a ``variant_level`` attribute.\n" -"Do not rely on the existence of this class outside dbus-python.\n" -); - -static PyMemberDef DBusPythonInt_tp_members[] = { - {"variant_level", T_LONG, offsetof(DBusPyIntBase, variant_level), - READONLY, - "The number of nested variants wrapping the real data. " - "0 if not in a variant."}, - {NULL}, -}; - -static PyObject * -DBusPythonInt_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs) -{ - PyObject *self; - long variantness = 0; - static char *argnames[] = {"variant_level", NULL}; - - if (PyTuple_Size(args) > 1) { - PyErr_SetString(PyExc_TypeError, - "__new__ takes at most one positional parameter"); - return NULL; - } - if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs, - "|l:__new__", argnames, - &variantness)) return NULL; - if (variantness < 0) { - PyErr_SetString(PyExc_ValueError, - "variant_level must be non-negative"); - return NULL; - } - - self = (PyInt_Type.tp_new)(cls, args, NULL); - if (self) { - ((DBusPyIntBase *)self)->variant_level = variantness; - } - return self; -} - -static PyObject * -DBusPythonInt_tp_repr(PyObject *self) -{ - PyObject *parent_repr = (PyInt_Type.tp_repr)(self); - long variant_level = ((DBusPyIntBase *)self)->variant_level; - PyObject *my_repr; - - if (!parent_repr) return NULL; - if (variant_level > 0) { - my_repr = PyString_FromFormat("%s(%s, variant_level=%ld)", - self->ob_type->tp_name, - PyString_AS_STRING(parent_repr), - variant_level); - } - else { - my_repr = PyString_FromFormat("%s(%s)", self->ob_type->tp_name, - PyString_AS_STRING(parent_repr)); - } - /* whether my_repr is NULL or not: */ - Py_DECREF(parent_repr); - return my_repr; -} - -PyTypeObject DBusPyIntBase_Type = { - PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type)) - 0, - "_dbus_bindings._IntBase", - sizeof(DBusPyIntBase), - 0, - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - DBusPythonInt_tp_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - DBusPythonInt_tp_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - DBusPythonInt_tp_members, /* tp_members */ - 0, /* tp_getset */ - DEFERRED_ADDRESS(&PyInt_Type), /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ - DBusPythonInt_tp_new, /* tp_new */ - PyObject_Del, /* tp_free */ -}; - -/* Support code for float subclasses. ================================ */ - -/* There's only one subclass at the moment (Double) but these are factored -out to make room for Float later. (Float is implemented and #if'd out) */ - -PyDoc_STRVAR(DBusPythonFloat_tp_doc,\ -"Base class for float subclasses with a ``variant_level`` attribute.\n" -"Do not rely on the existence of this class outside dbus-python.\n" -); - -static PyMemberDef DBusPythonFloat_tp_members[] = { - {"variant_level", T_LONG, offsetof(DBusPyFloatBase, variant_level), - READONLY, - "The number of nested variants wrapping the real data. " - "0 if not in a variant."}, - {NULL}, -}; - -static PyObject * -DBusPythonFloat_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs) -{ - PyObject *self; - long variantness = 0; - static char *argnames[] = {"variant_level", NULL}; - - if (PyTuple_Size(args) > 1) { - PyErr_SetString(PyExc_TypeError, - "__new__ takes at most one positional parameter"); - return NULL; - } - if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs, - "|l:__new__", argnames, - &variantness)) return NULL; - if (variantness < 0) { - PyErr_SetString(PyExc_ValueError, - "variant_level must be non-negative"); - return NULL; - } - - self = (PyFloat_Type.tp_new)(cls, args, NULL); - if (self) { - ((DBusPyFloatBase *)self)->variant_level = variantness; - } - return self; -} - -static PyObject * -DBusPythonFloat_tp_repr(PyObject *self) -{ - PyObject *parent_repr = (PyFloat_Type.tp_repr)(self); - long variant_level = ((DBusPyFloatBase *)self)->variant_level; - PyObject *my_repr; - - if (!parent_repr) return NULL; - if (variant_level > 0) { - my_repr = PyString_FromFormat("%s(%s, variant_level=%ld)", - self->ob_type->tp_name, - PyString_AS_STRING(parent_repr), - variant_level); - } - else { - my_repr = PyString_FromFormat("%s(%s)", self->ob_type->tp_name, - PyString_AS_STRING(parent_repr)); - } - /* whether my_repr is NULL or not: */ - Py_DECREF(parent_repr); - return my_repr; -} - -PyTypeObject DBusPyFloatBase_Type = { - PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type)) - 0, - "_dbus_bindings._FloatBase", - sizeof(DBusPyFloatBase), - 0, - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - DBusPythonFloat_tp_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - DBusPythonFloat_tp_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - DBusPythonFloat_tp_members, /* tp_members */ - 0, /* tp_getset */ - DEFERRED_ADDRESS(&PyFloat_Type), /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - DBusPythonFloat_tp_new, /* tp_new */ -}; - /* Support code for str subclasses ================================== */ PyDoc_STRVAR(DBusPythonString_tp_doc,\ @@ -486,128 +266,51 @@ PyTypeObject DBusPyStrBase_Type = { DBusPythonString_tp_new, /* tp_new */ }; -/* Support code for long subclasses ================================= */ - -PyDoc_STRVAR(DBusPythonLong_tp_doc,\ -"Base class for ``long`` subclasses with a ``variant_level`` attribute.\n" -"Do not rely on the existence of this class outside dbus-python.\n" -); +PyObject *dbus_py_variant_level_const = NULL; +PyObject *dbus_py_signature_const = NULL; +PyObject *dbus_py__dbus_object_path__const = NULL; -static PyObject * -DBusPythonLong_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs) +PyObject * +DBusPy_BuildConstructorKeywordArgs(long variant_level, const char *signature) { - PyObject *self; - long variantness = 0; - static char *argnames[] = {"variant_level", NULL}; + PyObject *dict = PyDict_New(); + PyObject *value; + int status; - if (PyTuple_Size(args) > 1) { - PyErr_SetString(PyExc_TypeError, - "__new__ takes at most one positional parameter"); - return NULL; - } - if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs, - "|l:__new__", argnames, - &variantness)) return NULL; - if (variantness < 0) { - PyErr_SetString(PyExc_ValueError, - "variant_level must be non-negative"); + if (!dict) return NULL; - } - self = (PyLong_Type.tp_new)(cls, args, NULL); - if (self) { - if (!dbus_py_variant_level_set(self, variantness)) { - Py_DECREF(self); + if (variant_level != 0) { + value = PyInt_FromLong(variant_level); + if (!value) { + Py_DECREF(dict); + return NULL; + } + status = PyDict_SetItem(dict, dbus_py_variant_level_const, value); + Py_DECREF(value); + if (status < 0) { + Py_DECREF(dict); return NULL; } } - return self; -} -static PyObject * -DBusPythonLong_tp_repr(PyObject *self) -{ - PyObject *parent_repr = (PyLong_Type.tp_repr)(self); - PyObject *vl_obj; - PyObject *my_repr; - long variant_level; - - if (!parent_repr) return NULL; - vl_obj = PyObject_GetAttr(self, dbus_py_variant_level_const); - if (!vl_obj) { - Py_DECREF(parent_repr); - return NULL; - } - variant_level = PyInt_AsLong(vl_obj); - Py_DECREF(vl_obj); - if (variant_level) { - my_repr = PyString_FromFormat("%s(%s, variant_level=%ld)", - self->ob_type->tp_name, - PyString_AS_STRING(parent_repr), - variant_level); - } - else { - my_repr = PyString_FromFormat("%s(%s)", self->ob_type->tp_name, - PyString_AS_STRING(parent_repr)); + if (signature != NULL) { + value = DBusPySignature_FromString(signature); + if (!value) { + Py_DECREF(dict); + return NULL; + } + status = PyDict_SetItem(dict, dbus_py_signature_const, value); + Py_DECREF(value); + if (status < 0) { + Py_DECREF(dict); + return NULL; + } } - /* whether my_repr is NULL or not: */ - Py_DECREF(parent_repr); - return my_repr; -} -static void -DBusPyLongBase_tp_dealloc(PyObject *self) -{ - dbus_py_variant_level_clear(self); - (PyLong_Type.tp_dealloc)(self); + return dict; } -PyTypeObject DBusPyLongBase_Type = { - PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type)) - 0, - "_dbus_bindings._LongBase", - 0, - 0, - DBusPyLongBase_tp_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - DBusPythonLong_tp_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - dbus_py_variant_level_getattro, /* tp_getattro */ - dbus_py_immutable_setattro, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - DBusPythonLong_tp_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - DEFERRED_ADDRESS(&PyLong_Type), /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - DBusPythonLong_tp_new, /* tp_new */ -}; - -PyObject *dbus_py_variant_level_const = NULL; -PyObject *dbus_py_signature_const = NULL; -PyObject *dbus_py__dbus_object_path__const = NULL; - dbus_bool_t dbus_py_init_abstract(void) { @@ -623,20 +326,6 @@ dbus_py_init_abstract(void) dbus_py_signature_const = PyString_InternFromString("signature"); if (!dbus_py_signature_const) return 0; - DBusPyIntBase_Type.tp_base = &PyInt_Type; - if (PyType_Ready(&DBusPyIntBase_Type) < 0) return 0; - /* disable the tp_print copied from PyInt_Type, so tp_repr gets called as - desired */ - DBusPyIntBase_Type.tp_print = NULL; - - DBusPyFloatBase_Type.tp_base = &PyFloat_Type; - if (PyType_Ready(&DBusPyFloatBase_Type) < 0) return 0; - DBusPyFloatBase_Type.tp_print = NULL; - - DBusPyLongBase_Type.tp_base = &PyLong_Type; - if (PyType_Ready(&DBusPyLongBase_Type) < 0) return 0; - DBusPyLongBase_Type.tp_print = NULL; - DBusPyStrBase_Type.tp_base = &PyString_Type; if (PyType_Ready(&DBusPyStrBase_Type) < 0) return 0; DBusPyStrBase_Type.tp_print = NULL; @@ -647,18 +336,9 @@ dbus_py_init_abstract(void) dbus_bool_t dbus_py_insert_abstract_types(PyObject *this_module) { - Py_INCREF(&DBusPyIntBase_Type); - Py_INCREF(&DBusPyLongBase_Type); Py_INCREF(&DBusPyStrBase_Type); - Py_INCREF(&DBusPyFloatBase_Type); - if (PyModule_AddObject(this_module, "_IntBase", - (PyObject *)&DBusPyIntBase_Type) < 0) return 0; - if (PyModule_AddObject(this_module, "_LongBase", - (PyObject *)&DBusPyLongBase_Type) < 0) return 0; if (PyModule_AddObject(this_module, "_StrBase", (PyObject *)&DBusPyStrBase_Type) < 0) return 0; - if (PyModule_AddObject(this_module, "_FloatBase", - (PyObject *)&DBusPyFloatBase_Type) < 0) return 0; return 1; } diff --git a/_dbus_bindings/bytes.c b/_dbus_bindings/bytes.c index a5648fe..73bc67c 100644 --- a/_dbus_bindings/bytes.c +++ b/_dbus_bindings/bytes.c @@ -31,236 +31,129 @@ #include "dbus_bindings-internal.h" #include "types-internal.h" -PyDoc_STRVAR(Byte_tp_doc, -"An unsigned byte: a subtype of int, with range restricted to [0, 255].\n" -"\n" -"A Byte b may be converted to a str of length 1 via str(b) == chr(b).\n" -"\n" -"Most of the time you don't want to use this class - it mainly exists\n" -"for symmetry with the other D-Bus types. See `dbus.ByteArray` for a\n" -"better way to handle arrays of Byte.\n" -"\n" -"Constructor::\n" -"\n" -" dbus.Byte(integer or str of length 1[, variant_level])\n" -"\n" -"``variant_level`` must be non-negative; the default is 0.\n" -"\n" -":IVariables:\n" -" `variant_level` : int\n" -" Indicates how many nested Variant containers this object\n" -" is contained in: if a message's wire format has a variant containing a\n" -" variant containing a byte, this is represented in Python by a\n" -" Byte with variant_level==2.\n" -); +static PyObject *Byte = NULL; +static PyObject *ByteArray = NULL; -static PyObject * -Byte_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs) +static dbus_bool_t +do_import(void) { - PyObject *obj; - PyObject *tuple; - long variantness = 0; - static char *argnames[] = {"variant_level", NULL}; + PyObject *name; + PyObject *module; - if (PyTuple_Size(args) > 1) { - PyErr_SetString(PyExc_TypeError, "Byte constructor takes no more " - "than one positional argument"); - return NULL; - } - if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs, - "|l:__new__", argnames, - &variantness)) return NULL; - if (variantness < 0) { - PyErr_SetString(PyExc_ValueError, - "variant_level must be non-negative"); - return NULL; - } + if (ByteArray != NULL && Byte != NULL) + return TRUE; - /* obj is only a borrowed ref for the moment */ - obj = PyTuple_GetItem(args, 0); + Py_CLEAR(Byte); + Py_CLEAR(ByteArray); - if (PyString_Check(obj)) { - /* string of length 1, we hope */ - if (PyString_GET_SIZE(obj) != 1) { - goto bad_arg; - } - obj = PyInt_FromLong((unsigned char)(PyString_AS_STRING(obj)[0])); - } - else if (PyInt_Check(obj)) { - long i = PyInt_AS_LONG(obj); + name = PyString_FromString("dbus.data"); + if (!name) + return FALSE; + + module = PyImport_Import(name); + Py_DECREF(name); + if (!module) + return FALSE; + + Byte = PyObject_GetAttrString(module, "Byte"); + ByteArray = PyObject_GetAttrString(module, "ByteArray"); + Py_DECREF(module); - if (obj->ob_type == cls && - ((DBusPyIntBase *)obj)->variant_level == variantness) { - Py_INCREF(obj); - return obj; - } - if (i < 0 || i > 255) goto bad_range; - /* else make it a new reference */ - Py_INCREF(obj); + if (Byte && !PyType_Check(Byte)) { + PyErr_SetString(PyExc_AssertionError, "Assertion failed: " + "isinstance(dbus.data.Byte, type)"); + Byte = NULL; } - else { - goto bad_arg; + if (ByteArray && !PyType_Check(ByteArray)) { + PyErr_SetString(PyExc_AssertionError, "Assertion failed: " + "isinstance(dbus.data.ByteArray, type)"); + ByteArray = NULL; } - tuple = Py_BuildValue("(O)", obj); - if (!tuple) return NULL; - Py_DECREF(obj); - obj = NULL; + return (ByteArray != NULL && Byte != NULL); +} - obj = DBusPyIntBase_Type.tp_new(cls, tuple, kwargs); - Py_DECREF(tuple); - tuple = NULL; - return obj; +int +DBusPyByte_Check(PyObject *o) +{ + if (!Byte && !do_import()) + return 0; + return PyObject_TypeCheck(o, (PyTypeObject *)Byte); +} -bad_arg: - PyErr_SetString(PyExc_TypeError, "Expected a string of length 1, " - "or an int in the range 0-255"); - return NULL; -bad_range: - PyErr_SetString(PyExc_ValueError, "Integer outside range 0-255"); - return NULL; +int +DBusPyByteArray_Check(PyObject *o) +{ + if (!ByteArray && !do_import()) + return 0; + return PyObject_TypeCheck(o, (PyTypeObject *)ByteArray); } -static PyObject * -Byte_tp_str(PyObject *self) +PyObject * +DBusPyByte_New(unsigned char value, long variant_level) { - unsigned char str[2] = { (unsigned char)PyInt_AS_LONG(self), 0 }; - return PyString_FromStringAndSize((char *)str, 1); + PyObject *args = NULL; + PyObject *kwargs = NULL; + PyObject *ret = NULL; + + if (!Byte && !do_import()) + return NULL; + + if (variant_level != 0) { + kwargs = DBusPy_BuildConstructorKeywordArgs(variant_level, NULL); + if (!kwargs) + goto finally; + } + + args = Py_BuildValue("(I)", (unsigned int) value); + if (!args) + goto finally; + + ret = PyObject_Call(Byte, args, kwargs); + +finally: + Py_XDECREF(args); + Py_XDECREF(kwargs); + return ret; } -PyTypeObject DBusPyByte_Type = { - PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type)) - 0, - "dbus.Byte", - 0, - 0, - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - Byte_tp_str, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - Byte_tp_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - DEFERRED_ADDRESS(&PyInt_Type), /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - Byte_new, /* tp_new */ -}; +PyObject * +DBusPyByteArray_New(const char *bytes, Py_ssize_t count, long variant_level) +{ + PyObject *args = NULL; + PyObject *kwargs = NULL; + PyObject *ret = NULL; + + if (!ByteArray && !do_import()) + return NULL; + + if (variant_level != 0) { + kwargs = DBusPy_BuildConstructorKeywordArgs(variant_level, NULL); + if (!kwargs) + goto finally; + } + + args = Py_BuildValue("(s#)", bytes, count); + if (!args) + goto finally; -PyDoc_STRVAR(ByteArray_tp_doc, -"ByteArray is a subtype of str which can be used when you want an\n" -"efficient immutable representation of a D-Bus byte array (signature 'ay').\n" -"\n" -"By default, when byte arrays are converted from D-Bus to Python, they\n" -"come out as a `dbus.Array` of `dbus.Byte`. This is just for symmetry with\n" -"the other D-Bus types - in practice, what you usually want is the byte\n" -"array represented as a string, using this class. To get this, pass the\n" -"``byte_arrays=True`` keyword argument to any of these methods:\n" -"\n" -"* any D-Bus method proxy, or ``connect_to_signal``, on the objects returned\n" -" by `Bus.get_object`\n" -"* any D-Bus method on a `dbus.Interface`\n" -"* `dbus.Interface.connect_to_signal`\n" -"* `Bus.add_signal_receiver`\n" -"\n" -"Import via::\n" -"\n" -" from dbus import ByteArray\n" -"\n" -"Constructor::\n" -"\n" -" ByteArray(str)\n" -); + ret = PyObject_Call(ByteArray, args, kwargs); -PyTypeObject DBusPyByteArray_Type = { - PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type)) - 0, - "dbus.ByteArray", - 0, - 0, - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - ByteArray_tp_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - DEFERRED_ADDRESS(&DBusPyStrBase_Type), /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ -}; +finally: + Py_XDECREF(args); + Py_XDECREF(kwargs); + return ret; +} dbus_bool_t dbus_py_init_byte_types(void) { - DBusPyByte_Type.tp_base = &DBusPyIntBase_Type; - if (PyType_Ready(&DBusPyByte_Type) < 0) return 0; - DBusPyByte_Type.tp_print = NULL; - - DBusPyByteArray_Type.tp_base = &DBusPyStrBase_Type; - if (PyType_Ready(&DBusPyByteArray_Type) < 0) return 0; - DBusPyByteArray_Type.tp_print = NULL; - return 1; } dbus_bool_t -dbus_py_insert_byte_types(PyObject *this_module) +dbus_py_insert_byte_types(PyObject *this_module UNUSED) { - Py_INCREF(&DBusPyByte_Type); - if (PyModule_AddObject(this_module, "Byte", - (PyObject *)&DBusPyByte_Type) < 0) return 0; - Py_INCREF(&DBusPyByteArray_Type); - if (PyModule_AddObject(this_module, "ByteArray", - (PyObject *)&DBusPyByteArray_Type) < 0) return 0; - return 1; } diff --git a/_dbus_bindings/conn-methods.c b/_dbus_bindings/conn-methods.c index 6fadc31..7e3273c 100644 --- a/_dbus_bindings/conn-methods.c +++ b/_dbus_bindings/conn-methods.c @@ -27,112 +27,6 @@ #include "dbus_bindings-internal.h" #include "conn-internal.h" -static void -_object_path_unregister(DBusConnection *conn, void *user_data) -{ - PyGILState_STATE gil = PyGILState_Ensure(); - PyObject *tuple = NULL; - Connection *conn_obj = NULL; - PyObject *callable; - - conn_obj = (Connection *)DBusPyConnection_ExistingFromDBusConnection(conn); - if (!conn_obj) goto out; - TRACE(conn_obj); - - DBG("Connection at %p unregistering object path %s", - conn_obj, PyString_AS_STRING((PyObject *)user_data)); - tuple = DBusPyConnection_GetObjectPathHandlers((PyObject *)conn_obj, (PyObject *)user_data); - if (!tuple) goto out; - if (tuple == Py_None) goto out; - - DBG("%s", "... yes we have handlers for that object path"); - - /* 0'th item is the unregisterer (if that's a word) */ - callable = PyTuple_GetItem(tuple, 0); - if (callable && callable != Py_None) { - DBG("%s", "... and we even have an unregisterer"); - /* any return from the unregisterer is ignored */ - Py_XDECREF(PyObject_CallFunctionObjArgs(callable, conn_obj, NULL)); - } -out: - Py_XDECREF(conn_obj); - Py_XDECREF(tuple); - /* the user_data (a Python str) is no longer ref'd by the DBusConnection */ - Py_XDECREF((PyObject *)user_data); - if (PyErr_Occurred()) { - PyErr_Print(); - } - PyGILState_Release(gil); -} - -static DBusHandlerResult -_object_path_message(DBusConnection *conn, DBusMessage *message, - void *user_data) -{ - DBusHandlerResult ret; - PyGILState_STATE gil = PyGILState_Ensure(); - Connection *conn_obj = NULL; - PyObject *tuple = NULL; - PyObject *msg_obj; - PyObject *callable; /* borrowed */ - - dbus_message_ref(message); - msg_obj = DBusPyMessage_ConsumeDBusMessage(message); - if (!msg_obj) { - ret = DBUS_HANDLER_RESULT_NEED_MEMORY; - goto out; - } - - conn_obj = (Connection *)DBusPyConnection_ExistingFromDBusConnection(conn); - if (!conn_obj) { - ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - goto out; - } - TRACE(conn_obj); - - DBG("Connection at %p messaging object path %s", - conn_obj, PyString_AS_STRING((PyObject *)user_data)); - DBG_DUMP_MESSAGE(message); - tuple = DBusPyConnection_GetObjectPathHandlers((PyObject *)conn_obj, (PyObject *)user_data); - if (!tuple || tuple == Py_None) { - ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - goto out; - } - - DBG("%s", "... yes we have handlers for that object path"); - - /* 1st item (0-based) is the message callback */ - callable = PyTuple_GetItem(tuple, 1); - if (!callable) { - DBG("%s", "... error getting message handler from tuple"); - ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - } - else if (callable == Py_None) { - /* there was actually no handler after all */ - DBG("%s", "... but those handlers don't do messages"); - ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - } - else { - DBG("%s", "... and we have a message handler for that object path"); - ret = DBusPyConnection_HandleMessage(conn_obj, msg_obj, callable); - } - -out: - Py_XDECREF(msg_obj); - Py_XDECREF(conn_obj); - Py_XDECREF(tuple); - if (PyErr_Occurred()) { - PyErr_Print(); - } - PyGILState_Release(gil); - return ret; -} - -static const DBusObjectPathVTable _object_path_vtable = { - _object_path_unregister, - _object_path_message, -}; - static DBusHandlerResult _filter_message(DBusConnection *conn, DBusMessage *message, void *user_data) { @@ -651,324 +545,6 @@ Connection_remove_message_filter(Connection *self, PyObject *callable) Py_RETURN_NONE; } -PyDoc_STRVAR(Connection__register_object_path__doc__, -"register_object_path(path, on_message, on_unregister=None, fallback=False)\n" -"\n" -"Register a callback to be called when messages arrive at the given\n" -"object-path. Used to export objects' methods on the bus in a low-level\n" -"way. For the high-level interface to this functionality (usually\n" -"recommended) see the `dbus.service.Object` base class.\n" -"\n" -":Parameters:\n" -" `path` : str\n" -" Object path to be acted on\n" -" `on_message` : callable\n" -" Called when a message arrives at the given object-path, with\n" -" two positional parameters: the first is this Connection,\n" -" the second is the incoming `dbus.lowlevel.Message`.\n" -" `on_unregister` : callable or None\n" -" If not None, called when the callback is unregistered.\n" -" `fallback` : bool\n" -" If True (the default is False), when a message arrives for a\n" -" 'subdirectory' of the given path and there is no more specific\n" -" handler, use this handler. Normally this handler is only run if\n" -" the paths match exactly.\n" -); -static PyObject * -Connection__register_object_path(Connection *self, PyObject *args, - PyObject *kwargs) -{ - dbus_bool_t ok; - int fallback = 0; - PyObject *callbacks, *path, *tuple, *on_message, *on_unregister = Py_None; - static char *argnames[] = {"path", "on_message", "on_unregister", - "fallback", NULL}; - - TRACE(self); - DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn); - if (!Connection__require_main_loop(self, NULL)) { - return NULL; - } - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "OO|Oi:_register_object_path", - argnames, - &path, - &on_message, &on_unregister, - &fallback)) return NULL; - - /* Take a reference to path, which we give away to libdbus in a moment. - - Also, path needs to be a string (not a subclass which could do something - mad) to preserve the desirable property that the DBusConnection can - never strongly reference the Connection, even indirectly. - */ - if (PyString_CheckExact(path)) { - Py_INCREF(path); - } - else if (PyUnicode_Check(path)) { - path = PyUnicode_AsUTF8String(path); - if (!path) return NULL; - } - else if (PyString_Check(path)) { - path = PyString_FromString(PyString_AS_STRING(path)); - if (!path) return NULL; - } - else { - PyErr_SetString(PyExc_TypeError, "path must be a str or unicode object"); - return NULL; - } - - if (!dbus_py_validate_object_path(PyString_AS_STRING(path))) { - Py_DECREF(path); - return NULL; - } - - tuple = Py_BuildValue("(OO)", on_unregister, on_message); - if (!tuple) { - Py_DECREF(path); - return NULL; - } - - /* Guard against registering a handler that already exists. */ - callbacks = PyDict_GetItem(self->object_paths, path); - if (callbacks && callbacks != Py_None) { - PyErr_Format(PyExc_KeyError, "Can't register the object-path " - "handler for '%s': there is already a handler", - PyString_AS_STRING(path)); - Py_DECREF(tuple); - Py_DECREF(path); - return NULL; - } - - /* Pre-allocate a slot in the dictionary, so we know we'll be able - * to replace it with the callbacks without OOM. - * This ensures we can keep libdbus' opinion of whether those - * paths are handled in sync with our own. */ - if (PyDict_SetItem(self->object_paths, path, Py_None) < 0) { - Py_DECREF(tuple); - Py_DECREF(path); - return NULL; - } - - Py_BEGIN_ALLOW_THREADS - if (fallback) { - ok = dbus_connection_register_fallback(self->conn, - PyString_AS_STRING(path), - &_object_path_vtable, - path); - } - else { - ok = dbus_connection_register_object_path(self->conn, - PyString_AS_STRING(path), - &_object_path_vtable, - path); - } - Py_END_ALLOW_THREADS - - if (ok) { - if (PyDict_SetItem(self->object_paths, path, tuple) < 0) { - /* That shouldn't have happened, we already allocated enough - memory for it. Oh well, try to undo the registration to keep - things in sync. If this fails too, we've leaked a bit of - memory in libdbus, but tbh we should never get here anyway. */ - Py_BEGIN_ALLOW_THREADS - ok = dbus_connection_unregister_object_path(self->conn, - PyString_AS_STRING(path)); - Py_END_ALLOW_THREADS - return NULL; - } - /* don't DECREF path: libdbus owns a ref now */ - Py_DECREF(tuple); - Py_RETURN_NONE; - } - else { - /* Oops, OOM. Tidy up, if we can, ignoring any error. */ - PyDict_DelItem(self->object_paths, path); - PyErr_Clear(); - Py_DECREF(tuple); - Py_DECREF(path); - PyErr_NoMemory(); - return NULL; - } -} - -PyDoc_STRVAR(Connection__unregister_object_path__doc__, -"unregister_object_path(path)\n\n" -"Remove a previously registered handler for the given object path.\n" -"\n" -":Parameters:\n" -" `path` : str\n" -" The object path whose handler is to be removed\n" -":Raises KeyError: if there is no handler registered for exactly that\n" -" object path.\n" -); -static PyObject * -Connection__unregister_object_path(Connection *self, PyObject *args, - PyObject *kwargs) -{ - dbus_bool_t ok; - PyObject *path; - PyObject *callbacks; - static char *argnames[] = {"path", NULL}; - - TRACE(self); - DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn); - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "O:_unregister_object_path", - argnames, &path)) return NULL; - - /* Take a ref to the path. Same comments as for _register_object_path. */ - if (PyString_CheckExact(path)) { - Py_INCREF(path); - } - else if (PyUnicode_Check(path)) { - path = PyUnicode_AsUTF8String(path); - if (!path) return NULL; - } - else if (PyString_Check(path)) { - path = PyString_FromString(PyString_AS_STRING(path)); - if (!path) return NULL; - } - else { - PyErr_SetString(PyExc_TypeError, "path must be a str or unicode object"); - return NULL; - } - - /* Guard against unregistering a handler that doesn't, in fact, exist, - or whose unregistration is already in progress. */ - callbacks = PyDict_GetItem(self->object_paths, path); - if (!callbacks || callbacks == Py_None) { - PyErr_Format(PyExc_KeyError, "Can't unregister the object-path " - "handler for '%s': there is no such handler", - PyString_AS_STRING(path)); - Py_DECREF(path); - return NULL; - } - - /* Hang on to a reference to the callbacks for the moment. */ - Py_INCREF(callbacks); - - /* Get rid of the object-path while we still have the GIL, to - guard against unregistering twice from different threads (which - causes undefined behaviour in libdbus). - - Because deletion would make it possible for the re-insertion below - to fail, we instead set the handler to None as a placeholder. - */ - if (PyDict_SetItem(self->object_paths, path, Py_None) < 0) { - /* If that failed, there's no need to be paranoid as below - the - callbacks are still set, so we failed, but at least everything - is in sync. */ - Py_DECREF(callbacks); - Py_DECREF(path); - return NULL; - } - - /* BEGIN PARANOIA - This is something of a critical section - the dict of object-paths - and libdbus' internal structures are out of sync for a bit. We have - to be able to cope with that. - - It's really annoying that dbus_connection_unregister_object_path - can fail, *and* has undefined behaviour if the object path has - already been unregistered. Either/or would be fine. - */ - - Py_BEGIN_ALLOW_THREADS - ok = dbus_connection_unregister_object_path(self->conn, - PyString_AS_STRING(path)); - Py_END_ALLOW_THREADS - - if (ok) { - Py_DECREF(callbacks); - PyDict_DelItem(self->object_paths, path); - /* END PARANOIA on successful code path */ - /* The above can't fail unless by some strange trickery the key is no - longer present. Ignore any errors. */ - Py_DECREF(path); - PyErr_Clear(); - Py_RETURN_NONE; - } - else { - /* Oops, OOM. Put the callbacks back in the dict so - * we'll have another go if/when the user frees some memory - * and tries calling this method again. */ - PyDict_SetItem(self->object_paths, path, callbacks); - /* END PARANOIA on failing code path */ - /* If the SetItem failed, there's nothing we can do about it - but - since we know it's an existing entry, it shouldn't be able to fail - anyway. */ - Py_DECREF(path); - Py_DECREF(callbacks); - return PyErr_NoMemory(); - } -} - -PyDoc_STRVAR(Connection_list_exported_child_objects__doc__, -"list_exported_child_objects(path: str) -> list of str\n\n" -"Return a list of the names of objects exported on this Connection as\n" -"direct children of the given object path.\n" -"\n" -"Each name returned may be converted to a valid object path using\n" -"``dbus.ObjectPath('%s%s%s' % (path, (path != '/' and '/' or ''), name))``.\n" -"For the purposes of this function, every parent or ancestor of an exported\n" -"object is considered to be an exported object, even if it's only an object\n" -"synthesized by the library to support introspection.\n"); -static PyObject * -Connection_list_exported_child_objects (Connection *self, PyObject *args, - PyObject *kwargs) -{ - const char *path; - char **kids, **kid_ptr; - dbus_bool_t ok; - PyObject *ret; - static char *argnames[] = {"path", NULL}; - - DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn); - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", argnames, &path)) { - return NULL; - } - - if (!dbus_py_validate_object_path(path)) { - return NULL; - } - - Py_BEGIN_ALLOW_THREADS - ok = dbus_connection_list_registered(self->conn, path, &kids); - Py_END_ALLOW_THREADS - - if (!ok) { - return PyErr_NoMemory(); - } - - ret = PyList_New(0); - if (!ret) { - return NULL; - } - for (kid_ptr = kids; *kid_ptr; kid_ptr++) { - PyObject *tmp = PyString_FromString(*kid_ptr); - - if (!tmp) { - Py_DECREF(ret); - return NULL; - } - if (PyList_Append(ret, tmp) < 0) { - Py_DECREF(tmp); - Py_DECREF(ret); - return NULL; - } - Py_DECREF(tmp); - } - - dbus_free_string_array(kids); - - return ret; -} - - /* dbus_connection_get_object_path_data - not useful to Python, - * the object path data is just a PyString containing the path */ - /* dbus_connection_list_registered could be useful, though */ - /* dbus_connection_set_change_sigpipe - sets global state */ /* Maxima. Does Python code ever need to manipulate these? @@ -1013,13 +589,10 @@ struct PyMethodDef DBusPyConnection_tp_methods[] = { ENTRY(get_peer_unix_user, METH_NOARGS), ENTRY(get_peer_unix_process_id, METH_NOARGS), ENTRY(add_message_filter, METH_O), - ENTRY(_register_object_path, METH_VARARGS|METH_KEYWORDS), ENTRY(remove_message_filter, METH_O), ENTRY(send_message, METH_VARARGS), ENTRY(send_message_with_reply, METH_VARARGS|METH_KEYWORDS), ENTRY(send_message_with_reply_and_block, METH_VARARGS), - ENTRY(_unregister_object_path, METH_VARARGS|METH_KEYWORDS), - ENTRY(list_exported_child_objects, METH_VARARGS|METH_KEYWORDS), {"_new_for_bus", (PyCFunction)DBusPyConnection_NewForBus, METH_CLASS|METH_VARARGS|METH_KEYWORDS, new_for_bus__doc__}, diff --git a/_dbus_bindings/containers.c b/_dbus_bindings/containers.c index e80098f..cf6ace3 100644 --- a/_dbus_bindings/containers.c +++ b/_dbus_bindings/containers.c @@ -33,735 +33,166 @@ /* Array ============================================================ */ -PyDoc_STRVAR(Array_tp_doc, -"An array of similar items, implemented as a subtype of list.\n" -"\n" -"As currently implemented, an Array behaves just like a list, but\n" -"with the addition of a ``signature`` property set by the constructor;\n" -"conversion of its items to D-Bus types is only done when it's sent in\n" -"a Message. This might change in future so validation is done earlier.\n" -"\n" -"Constructor::\n" -"\n" -" dbus.Array([iterable][, signature][, variant_level])\n" -"\n" -"``variant_level`` must be non-negative; the default is 0.\n" -"\n" -"``signature`` is the D-Bus signature string for a single element of the\n" -"array, or None. If not None it must represent a single complete type, the\n" -"type of a single array item; the signature of the whole Array may be\n" -"obtained by prepending ``a`` to the given signature.\n" -"\n" -"If None (the default), when the Array is sent over\n" -"D-Bus, the item signature will be guessed from the first element.\n" -"\n" -":IVariables:\n" -" `variant_level` : int\n" -" Indicates how many nested Variant containers this object\n" -" is contained in: if a message's wire format has a variant containing a\n" -" variant containing an array, this is represented in Python by an\n" -" Array with variant_level==2.\n" -); - -static struct PyMemberDef Array_tp_members[] = { - {"signature", T_OBJECT, offsetof(DBusPyArray, signature), READONLY, - "The D-Bus signature of each element of this Array (a Signature " - "instance)"}, - {"variant_level", T_LONG, offsetof(DBusPyArray, variant_level), - READONLY, - "The number of nested variants wrapping the real data. " - "0 if not in a variant."}, - {NULL}, -}; - -static void -Array_tp_dealloc (DBusPyArray *self) -{ - Py_XDECREF(self->signature); - self->signature = NULL; - (PyList_Type.tp_dealloc)((PyObject *)self); -} - -static PyObject * -Array_tp_repr(DBusPyArray *self) -{ - PyObject *parent_repr = (PyList_Type.tp_repr)((PyObject *)self); - PyObject *sig_repr = PyObject_Repr(self->signature); - PyObject *my_repr = NULL; - long variant_level = self->variant_level; - - if (!parent_repr) goto finally; - if (!sig_repr) goto finally; - if (variant_level > 0) { - my_repr = PyString_FromFormat("%s(%s, signature=%s, " - "variant_level=%ld)", - self->super.ob_type->tp_name, - PyString_AS_STRING(parent_repr), - PyString_AS_STRING(sig_repr), - variant_level); - } - else { - my_repr = PyString_FromFormat("%s(%s, signature=%s)", - self->super.ob_type->tp_name, - PyString_AS_STRING(parent_repr), - PyString_AS_STRING(sig_repr)); - } -finally: - Py_XDECREF(parent_repr); - Py_XDECREF(sig_repr); - return my_repr; -} - -static PyObject * -Array_tp_new (PyTypeObject *cls, PyObject *args, PyObject *kwargs) -{ - PyObject *variant_level = NULL; - DBusPyArray *self = (DBusPyArray *)(PyList_Type.tp_new)(cls, args, kwargs); - - /* variant_level is immutable, so handle it in __new__ rather than - __init__ */ - if (!self) return NULL; - Py_INCREF(Py_None); - self->signature = Py_None; - self->variant_level = 0; - if (kwargs) { - variant_level = PyDict_GetItem(kwargs, dbus_py_variant_level_const); - } - if (variant_level) { - self->variant_level = PyInt_AsLong(variant_level); - if (PyErr_Occurred()) { - Py_DECREF((PyObject *)self); - return NULL; - } - } - return (PyObject *)self; -} +static PyObject *Array = NULL; +static PyObject *Struct = NULL; +static PyObject *Dictionary = NULL; -static int -Array_tp_init (DBusPyArray *self, PyObject *args, PyObject *kwargs) +static dbus_bool_t +do_import(void) { - PyObject *obj = dbus_py_empty_tuple; - PyObject *signature = NULL; - PyObject *tuple; - PyObject *variant_level; - /* variant_level is accepted but ignored - it's immutable, so - * __new__ handles it */ - static char *argnames[] = {"iterable", "signature", "variant_level", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOO:__init__", argnames, - &obj, &signature, &variant_level)) { - return -1; - } + PyObject *name; + PyObject *module; - /* convert signature from a borrowed ref of unknown type to an owned ref - of type Signature (or None) */ - if (!signature) signature = Py_None; - if (signature == Py_None - || PyObject_IsInstance(signature, (PyObject *)&DBusPySignature_Type)) { - Py_INCREF(signature); - } - else { - signature = PyObject_CallFunction((PyObject *)&DBusPySignature_Type, - "(O)", signature); - if (!signature) return -1; - } + if (Array && Struct && Dictionary) + return TRUE; - if (signature != Py_None) { - const char *c_str = PyString_AS_STRING(signature); + Py_CLEAR(Array); + Py_CLEAR(Struct); + Py_CLEAR(Dictionary); - if (!dbus_signature_validate_single(c_str, NULL)) { - Py_DECREF(signature); - PyErr_SetString(PyExc_ValueError, - "There must be exactly one complete type in " - "an Array's signature parameter"); - return -1; - } - } - - tuple = Py_BuildValue("(O)", obj); - if (!tuple) { - Py_DECREF(signature); - return -1; - } - if ((PyList_Type.tp_init)((PyObject *)self, tuple, NULL) < 0) { - Py_DECREF(tuple); - Py_DECREF(signature); - return -1; - } - Py_DECREF(tuple); - - Py_XDECREF(self->signature); - self->signature = signature; - return 0; -} + name = PyString_FromString("dbus.data"); + if (!name) + return FALSE; -PyTypeObject DBusPyArray_Type = { - PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type)) - 0, - "dbus.Array", - sizeof(DBusPyArray), - 0, - (destructor)Array_tp_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)Array_tp_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - Array_tp_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - Array_tp_members, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Array_tp_init, /* tp_init */ - 0, /* tp_alloc */ - Array_tp_new, /* tp_new */ -}; + module = PyImport_Import(name); + Py_DECREF(name); + if (!module) + return FALSE; -/* Dict ============================================================= */ + Array = PyObject_GetAttrString(module, "Array"); + Struct = PyObject_GetAttrString(module, "Struct"); + Dictionary = PyObject_GetAttrString(module, "Dictionary"); -PyDoc_STRVAR(Dict_tp_doc, -"An mapping whose keys are similar and whose values are similar,\n" -"implemented as a subtype of dict.\n" -"\n" -"As currently implemented, a Dictionary behaves just like a dict, but\n" -"with the addition of a ``signature`` property set by the constructor;\n" -"conversion of its items to D-Bus types is only done when it's sent in\n" -"a Message. This may change in future so validation is done earlier.\n" -"\n" -"Constructor::\n" -"\n" -" Dictionary(mapping_or_iterable=(), signature=None, variant_level=0)\n" -"\n" -"``variant_level`` must be non-negative; the default is 0.\n" -"\n" -"``signature`` is either a string or None. If a string, it must consist\n" -"of exactly two complete type signatures, representing the 'key' type\n" -"(which must be a primitive type, i.e. one of \"bdginoqstuxy\")\n" -"and the 'value' type. The signature of the whole Dictionary will be\n" -"``a{xx}`` where ``xx`` is replaced by the given signature.\n" -"\n" -"If it is None (the default), when the Dictionary is sent over\n" -"D-Bus, the key and value signatures will be guessed from an arbitrary\n" -"element of the Dictionary.\n" -"\n" -":IVariables:\n" -" `variant_level` : int\n" -" Indicates how many nested Variant containers this object\n" -" is contained in: if a message's wire format has a variant containing a\n" -" variant containing an array of DICT_ENTRY, this is represented in\n" -" Python by a Dictionary with variant_level==2.\n" -); - -static struct PyMemberDef Dict_tp_members[] = { - {"signature", T_OBJECT, offsetof(DBusPyDict, signature), READONLY, - "The D-Bus signature of each key in this Dictionary, followed by " - "that of each value in this Dictionary, as a Signature instance."}, - {"variant_level", T_LONG, offsetof(DBusPyDict, variant_level), - READONLY, - "The number of nested variants wrapping the real data. " - "0 if not in a variant."}, - {NULL}, -}; - -static void -Dict_tp_dealloc (DBusPyDict *self) -{ - Py_XDECREF(self->signature); - self->signature = NULL; - (PyDict_Type.tp_dealloc)((PyObject *)self); -} + Py_DECREF(module); -static PyObject * -Dict_tp_repr(DBusPyDict *self) -{ - PyObject *parent_repr = (PyDict_Type.tp_repr)((PyObject *)self); - PyObject *sig_repr = PyObject_Repr(self->signature); - PyObject *my_repr = NULL; - long variant_level = self->variant_level; - - if (!parent_repr) goto finally; - if (!sig_repr) goto finally; - if (variant_level > 0) { - my_repr = PyString_FromFormat("%s(%s, signature=%s, " - "variant_level=%ld)", - self->super.ob_type->tp_name, - PyString_AS_STRING(parent_repr), - PyString_AS_STRING(sig_repr), - variant_level); + if (Array && !PyType_Check(Array)) { + PyErr_SetString(PyExc_AssertionError, "Assertion failed: " + "isinstance(dbus.data.Array, type)"); + Array = NULL; } - else { - my_repr = PyString_FromFormat("%s(%s, signature=%s)", - self->super.ob_type->tp_name, - PyString_AS_STRING(parent_repr), - PyString_AS_STRING(sig_repr)); + if (Struct && !PyType_Check(Struct)) { + PyErr_SetString(PyExc_AssertionError, "Assertion failed: " + "isinstance(dbus.data.Struct, type)"); + Struct = NULL; } -finally: - Py_XDECREF(parent_repr); - Py_XDECREF(sig_repr); - return my_repr; + if (Dictionary && !PyType_Check(Dictionary)) { + PyErr_SetString(PyExc_AssertionError, "Assertion failed: " + "isinstance(dbus.data.Dictionary, type)"); + Dictionary = NULL; + } + + return (Array != NULL && Struct != NULL && Dictionary != NULL); } -static PyObject * -Dict_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs) +int +DBusPyArray_Check(PyObject *o) { - DBusPyDict *self = (DBusPyDict *)(PyDict_Type.tp_new)(cls, args, kwargs); - PyObject *variant_level = NULL; - - /* variant_level is immutable, so handle it in __new__ rather than - __init__ */ - if (!self) return NULL; - Py_INCREF(Py_None); - self->signature = Py_None; - self->variant_level = 0; - if (kwargs) { - variant_level = PyDict_GetItem(kwargs, dbus_py_variant_level_const); - } - if (variant_level) { - self->variant_level = PyInt_AsLong(variant_level); - if (PyErr_Occurred()) { - Py_DECREF((PyObject *)self); - return NULL; - } - } - return (PyObject *)self; + if (!Array && !do_import()) + return 0; + return PyObject_TypeCheck(o, (PyTypeObject *)Array); } -static int -Dict_tp_init(DBusPyDict *self, PyObject *args, PyObject *kwargs) +PyObject * +DBusPyArray_New(const char *signature, long variant_level) { - PyObject *obj = dbus_py_empty_tuple; - PyObject *signature = NULL; - PyObject *tuple; - PyObject *variant_level; /* ignored here - __new__ uses it */ - static char *argnames[] = {"mapping_or_iterable", "signature", - "variant_level", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOO:__init__", argnames, - &obj, &signature, &variant_level)) { - return -1; - } + PyObject *kwargs = NULL; + PyObject *ret = NULL; - /* convert signature from a borrowed ref of unknown type to an owned ref - of type Signature (or None) */ - if (!signature) signature = Py_None; - if (signature == Py_None - || PyObject_IsInstance(signature, (PyObject *)&DBusPySignature_Type)) { - Py_INCREF(signature); - } - else { - signature = PyObject_CallFunction((PyObject *)&DBusPySignature_Type, - "(O)", signature); - if (!signature) return -1; - } + if (!Array && !do_import()) + return NULL; - if (signature != Py_None) { - const char *c_str = PyString_AS_STRING(signature); - - switch (c_str[0]) { - case DBUS_TYPE_BYTE: - case DBUS_TYPE_BOOLEAN: - case DBUS_TYPE_INT16: - case DBUS_TYPE_UINT16: - case DBUS_TYPE_INT32: - case DBUS_TYPE_UINT32: - case DBUS_TYPE_INT64: - case DBUS_TYPE_UINT64: - case DBUS_TYPE_DOUBLE: -#ifdef WITH_DBUS_FLOAT32 - case DBUS_TYPE_FLOAT: -#endif - case DBUS_TYPE_STRING: - case DBUS_TYPE_OBJECT_PATH: - case DBUS_TYPE_SIGNATURE: - break; - default: - Py_DECREF(signature); - PyErr_SetString(PyExc_ValueError, - "The key type in a Dictionary's signature " - "must be a primitive type"); - return -1; - } - - if (!dbus_signature_validate_single(c_str + 1, NULL)) { - Py_DECREF(signature); - PyErr_SetString(PyExc_ValueError, - "There must be exactly two complete types in " - "a Dictionary's signature parameter"); - return -1; - } + if (variant_level != 0) { + kwargs = DBusPy_BuildConstructorKeywordArgs(variant_level, signature); + if (!kwargs) + goto finally; } - tuple = Py_BuildValue("(O)", obj); - if (!tuple) { - Py_DECREF(signature); - return -1; - } + ret = PyObject_Call(Array, dbus_py_empty_tuple, kwargs); - if ((PyDict_Type.tp_init((PyObject *)self, tuple, NULL)) < 0) { - Py_DECREF(tuple); - Py_DECREF(signature); - return -1; - } - Py_DECREF(tuple); - - Py_XDECREF(self->signature); - self->signature = signature; - return 0; +finally: + Py_XDECREF(kwargs); + return ret; } -PyTypeObject DBusPyDict_Type = { - PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type)) - 0, - "dbus.Dictionary", - sizeof(DBusPyDict), - 0, - (destructor)Dict_tp_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)Dict_tp_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - Dict_tp_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - Dict_tp_members, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Dict_tp_init, /* tp_init */ - 0, /* tp_alloc */ - Dict_tp_new, /* tp_new */ -}; - -/* Struct =========================================================== */ +/* Dict ============================================================= */ -static PyObject *struct_signatures; - -PyDoc_STRVAR(Struct_tp_doc, -"An structure containing items of possibly distinct types.\n" -"\n" -"Constructor::\n" -"\n" -" dbus.Struct(iterable, signature=None, variant_level=0) -> Struct\n" -"\n" -"D-Bus structs may not be empty, so the iterable argument is required and\n" -"may not be an empty iterable.\n" -"\n" -"``signature`` is either None, or a string representing the contents of the\n" -"struct as one or more complete type signatures. The overall signature of\n" -"the struct will be the given signature enclosed in parentheses, ``()``.\n" -"\n" -"If the signature is None (default) it will be guessed\n" -"from the types of the items during construction.\n" -"\n" -"``variant_level`` must be non-negative; the default is 0.\n" -"\n" -":IVariables:\n" -" `variant_level` : int\n" -" Indicates how many nested Variant containers this object\n" -" is contained in: if a message's wire format has a variant containing a\n" -" variant containing a struct, this is represented in Python by a\n" -" Struct with variant_level==2.\n" -); - -static PyObject * -Struct_tp_repr(PyObject *self) +int +DBusPyDictionary_Check(PyObject *o) { - PyObject *parent_repr = (PyTuple_Type.tp_repr)((PyObject *)self); - PyObject *sig; - PyObject *sig_repr = NULL; - PyObject *key; - long variant_level; - PyObject *my_repr = NULL; - - if (!parent_repr) goto finally; - key = PyLong_FromVoidPtr(self); - if (!key) goto finally; - sig = PyDict_GetItem(struct_signatures, key); - Py_DECREF(key); - if (!sig) sig = Py_None; - sig_repr = PyObject_Repr(sig); - if (!sig_repr) goto finally; - variant_level = dbus_py_variant_level_get(self); - if (variant_level > 0) { - my_repr = PyString_FromFormat("%s(%s, signature=%s, " - "variant_level=%ld)", - self->ob_type->tp_name, - PyString_AS_STRING(parent_repr), - PyString_AS_STRING(sig_repr), - variant_level); - } - else { - my_repr = PyString_FromFormat("%s(%s, signature=%s)", - self->ob_type->tp_name, - PyString_AS_STRING(parent_repr), - PyString_AS_STRING(sig_repr)); - } - -finally: - Py_XDECREF(parent_repr); - Py_XDECREF(sig_repr); - return my_repr; + if (!Dictionary && !do_import()) + return 0; + return PyObject_TypeCheck(o, (PyTypeObject *)Dictionary); } -static PyObject * -Struct_tp_new (PyTypeObject *cls, PyObject *args, PyObject *kwargs) +PyObject * +DBusPyDictionary_New(const char *signature, long variant_level) { - PyObject *signature = NULL; - long variantness = 0; - PyObject *self, *key; - static char *argnames[] = {"signature", "variant_level", NULL}; - - if (PyTuple_Size(args) != 1) { - PyErr_SetString(PyExc_TypeError, - "__new__ takes exactly one positional parameter"); - return NULL; - } - if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs, - "|Ol:__new__", argnames, - &signature, &variantness)) { - return NULL; - } - if (variantness < 0) { - PyErr_SetString(PyExc_ValueError, - "variant_level must be non-negative"); - return NULL; - } + PyObject *kwargs = NULL; + PyObject *ret = NULL; - self = (PyTuple_Type.tp_new)(cls, args, NULL); - if (!self) + if (!Dictionary && !do_import()) return NULL; - if (PyTuple_Size(self) < 1) { - PyErr_SetString(PyExc_ValueError, "D-Bus structs may not be empty"); - Py_DECREF(self); - return NULL; - } - if (!dbus_py_variant_level_set(self, variantness)) { - Py_DECREF(self); - return NULL; + if (variant_level != 0) { + kwargs = DBusPy_BuildConstructorKeywordArgs(variant_level, signature); + if (!kwargs) + goto finally; } - /* convert signature from a borrowed ref of unknown type to an owned ref - of type Signature (or None) */ - if (!signature) signature = Py_None; - if (signature == Py_None - || PyObject_IsInstance(signature, (PyObject *)&DBusPySignature_Type)) { - Py_INCREF(signature); - } - else { - signature = PyObject_CallFunction((PyObject *)&DBusPySignature_Type, - "(O)", signature); - if (!signature) { - Py_DECREF(self); - return NULL; - } - } + ret = PyObject_Call(Dictionary, dbus_py_empty_tuple, kwargs); - key = PyLong_FromVoidPtr(self); - if (!key) { - Py_DECREF(self); - Py_DECREF(signature); - return NULL; - } - if (PyDict_SetItem(struct_signatures, key, signature) < 0) { - Py_DECREF(key); - Py_DECREF(self); - Py_DECREF(signature); - return NULL; - } - - Py_DECREF(key); - Py_DECREF(signature); - return self; +finally: + Py_XDECREF(kwargs); + return ret; } -static void -Struct_tp_dealloc(PyObject *self) -{ - PyObject *et, *ev, *etb, *key; - - dbus_py_variant_level_clear(self); - PyErr_Fetch(&et, &ev, &etb); - - key = PyLong_FromVoidPtr(self); - if (key) { - if (PyDict_GetItem(struct_signatures, key)) { - if (PyDict_DelItem(struct_signatures, key) < 0) { - /* should never happen */ - PyErr_WriteUnraisable(self); - } - } - Py_DECREF(key); - } - else { - /* not enough memory to free all the memory... leak the signature, - * there's not much else we could do here */ - PyErr_WriteUnraisable(self); - } +/* Struct =========================================================== */ - PyErr_Restore(et, ev, etb); - (PyTuple_Type.tp_dealloc)(self); +int +DBusPyStruct_Check(PyObject *o) +{ + if (!Struct && !do_import()) + return 0; + return PyObject_TypeCheck(o, (PyTypeObject *)Struct); } PyObject * -Struct_tp_getattro(PyObject *obj, PyObject *name) +DBusPyStruct_New(PyObject *iterable, long variant_level) { - PyObject *key, *value; + PyObject *args = NULL; + PyObject *kwargs = NULL; + PyObject *ret = NULL; - if (PyString_Check(name)) { - Py_INCREF(name); - } - else if (PyUnicode_Check(name)) { - name = PyUnicode_AsEncodedString(name, NULL, NULL); - if (!name) { - return NULL; - } - } - else { - PyErr_SetString(PyExc_TypeError, "attribute name must be string"); + if (!Struct && !do_import()) return NULL; - } - if (strcmp(PyString_AS_STRING(name), "signature")) { - value = dbus_py_variant_level_getattro(obj, name); - Py_DECREF(name); - return value; + if (variant_level != 0) { + kwargs = DBusPy_BuildConstructorKeywordArgs(variant_level, NULL); + if (!kwargs) + goto finally; } - Py_DECREF(name); - - key = PyLong_FromVoidPtr(obj); - - if (!key) { - return NULL; - } + args = Py_BuildValue("(O)", iterable); + if (!args) + goto finally; - value = PyDict_GetItem(struct_signatures, key); - Py_DECREF(key); + ret = PyObject_Call(Struct, args, kwargs); - if (!value) - value = Py_None; - Py_INCREF(value); - return value; +finally: + Py_XDECREF(args); + Py_XDECREF(kwargs); + return ret; } -PyTypeObject DBusPyStruct_Type = { - PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type)) - 0, - "dbus.Struct", - 0, - 0, - Struct_tp_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)Struct_tp_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - Struct_tp_getattro, /* tp_getattro */ - dbus_py_immutable_setattro, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - Struct_tp_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - Struct_tp_new, /* tp_new */ -}; - dbus_bool_t dbus_py_init_container_types(void) { - struct_signatures = PyDict_New(); - if (!struct_signatures) return 0; - - DBusPyArray_Type.tp_base = &PyList_Type; - if (PyType_Ready(&DBusPyArray_Type) < 0) return 0; - DBusPyArray_Type.tp_print = NULL; - - DBusPyDict_Type.tp_base = &PyDict_Type; - if (PyType_Ready(&DBusPyDict_Type) < 0) return 0; - DBusPyDict_Type.tp_print = NULL; - - DBusPyStruct_Type.tp_base = &PyTuple_Type; - if (PyType_Ready(&DBusPyStruct_Type) < 0) return 0; - DBusPyStruct_Type.tp_print = NULL; - return 1; } dbus_bool_t -dbus_py_insert_container_types(PyObject *this_module) +dbus_py_insert_container_types(PyObject *this_module UNUSED) { - Py_INCREF(&DBusPyArray_Type); - if (PyModule_AddObject(this_module, "Array", - (PyObject *)&DBusPyArray_Type) < 0) return 0; - - Py_INCREF(&DBusPyDict_Type); - if (PyModule_AddObject(this_module, "Dictionary", - (PyObject *)&DBusPyDict_Type) < 0) return 0; - - Py_INCREF(&DBusPyStruct_Type); - if (PyModule_AddObject(this_module, "Struct", - (PyObject *)&DBusPyStruct_Type) < 0) return 0; - return 1; } diff --git a/_dbus_bindings/dbus_bindings-internal.h b/_dbus_bindings/dbus_bindings-internal.h index 1dfd6b2..6ffbc37 100644 --- a/_dbus_bindings/dbus_bindings-internal.h +++ b/_dbus_bindings/dbus_bindings-internal.h @@ -74,32 +74,6 @@ extern dbus_bool_t dbus_py_init_exception_types(void); extern dbus_bool_t dbus_py_insert_exception_types(PyObject *this_module); /* types */ -extern PyTypeObject DBusPyBoolean_Type; -DEFINE_CHECK(DBusPyBoolean) -extern PyTypeObject DBusPyObjectPath_Type, DBusPySignature_Type; -DEFINE_CHECK(DBusPyObjectPath) -DEFINE_CHECK(DBusPySignature) -extern PyTypeObject DBusPyArray_Type, DBusPyDict_Type, DBusPyStruct_Type; -DEFINE_CHECK(DBusPyArray) -DEFINE_CHECK(DBusPyDict) -DEFINE_CHECK(DBusPyStruct) -extern PyTypeObject DBusPyByte_Type, DBusPyByteArray_Type; -DEFINE_CHECK(DBusPyByteArray) -DEFINE_CHECK(DBusPyByte) -extern PyTypeObject DBusPyUTF8String_Type, DBusPyString_Type; -DEFINE_CHECK(DBusPyUTF8String) -DEFINE_CHECK(DBusPyString) -extern PyTypeObject DBusPyDouble_Type; -DEFINE_CHECK(DBusPyDouble) -extern PyTypeObject DBusPyInt16_Type, DBusPyUInt16_Type; -DEFINE_CHECK(DBusPyInt16) -DEFINE_CHECK(DBusPyUInt16) -extern PyTypeObject DBusPyInt32_Type, DBusPyUInt32_Type; -DEFINE_CHECK(DBusPyInt32) -DEFINE_CHECK(DBusPyUInt32) -extern PyTypeObject DBusPyInt64_Type, DBusPyUInt64_Type; -DEFINE_CHECK(DBusPyInt64) -DEFINE_CHECK(DBusPyUInt64) extern dbus_bool_t dbus_py_init_abstract(void); extern dbus_bool_t dbus_py_init_signature(void); extern dbus_bool_t dbus_py_init_int_types(void); @@ -115,6 +89,63 @@ extern dbus_bool_t dbus_py_insert_float_types(PyObject *this_module); extern dbus_bool_t dbus_py_insert_container_types(PyObject *this_module); extern dbus_bool_t dbus_py_insert_byte_types(PyObject *this_module); +int DBusPySignature_Check(PyObject *o); +PyObject *DBusPySignature_FromString(const char *str); +PyObject *DBusPySignature_FromStringObject(PyObject *o, int allow_none); +PyObject *DBusPySignature_FromStringAndSize(const char *str, Py_ssize_t size); +PyObject *DBusPySignature_FromStringAndVariantLevel(const char *str, + long variant_level); +PyObject *dbus_py_get_signature_iter(PyObject *unused, PyObject *sig); + +int DBusPyBoolean_Check(PyObject *o); +PyObject *DBusPyBoolean_New(int is_true, long variant_level); + +int DBusPyByte_Check(PyObject *o); +PyObject *DBusPyByte_New(unsigned char value, long variant_level); + +int DBusPyByteArray_Check(PyObject *o); +PyObject *DBusPyByteArray_New(const char *bytes, Py_ssize_t count, + long variant_level); + +int DBusPyArray_Check(PyObject *o); +PyObject *DBusPyArray_New(const char *signature, long variant_level); + +int DBusPyDictionary_Check(PyObject *o); +PyObject *DBusPyDictionary_New(const char *signature, long variant_level); + +int DBusPyStruct_Check(PyObject *o); +PyObject *DBusPyStruct_New(PyObject *iterable, long variant_level); + +int DBusPyUTF8String_Check(PyObject *o); +PyObject *DBusPyUTF8String_New(const char *utf8, long variant_level); + +int DBusPyString_Check(PyObject *o); +PyObject *DBusPyString_New(const char *utf8, long variant_level); + +int DBusPyObjectPath_Check(PyObject *o); +PyObject *DBusPyObjectPath_New(const char *utf8, long variant_level); + +int DBusPyDouble_Check(PyObject *o); +PyObject *DBusPyDouble_New(double val, long variant_level); + +int DBusPyInt16_Check(PyObject *o); +PyObject *DBusPyInt16_New(dbus_int16_t val, long variant_level); + +int DBusPyUInt16_Check(PyObject *o); +PyObject *DBusPyUInt16_New(dbus_uint16_t val, long variant_level); + +int DBusPyInt32_Check(PyObject *o); +PyObject *DBusPyInt32_New(dbus_int32_t val, long variant_level); + +int DBusPyUInt32_Check(PyObject *o); +PyObject *DBusPyUInt32_New(dbus_uint32_t val, long variant_level); + +int DBusPyInt64_Check(PyObject *o); +PyObject *DBusPyInt64_New(dbus_int64_t val, long variant_level); + +int DBusPyUInt64_Check(PyObject *o); +PyObject *DBusPyUInt64_New(dbus_uint64_t val, long variant_level); + /* generic */ extern void dbus_py_take_gil_and_xdecref(PyObject *); extern int dbus_py_immutable_setattro(PyObject *, PyObject *, PyObject *); @@ -124,6 +155,8 @@ extern PyObject *dbus_py_tp_richcompare_by_pointer(PyObject *, extern long dbus_py_tp_hash_by_pointer(PyObject *self); extern PyObject *dbus_py_empty_tuple; extern dbus_bool_t dbus_py_init_generic(void); +PyObject *DBusPy_BuildConstructorKeywordArgs(long variant_level, + const char *signature); /* message.c */ extern DBusMessage *DBusPyMessage_BorrowDBusMessage(PyObject *msg); @@ -155,6 +188,7 @@ dbus_bool_t dbus_py_validate_object_path(const char *path); #define dbus_py_validate_error_name dbus_py_validate_interface_name /* debugging support */ + void _dbus_py_assertion_failed(const char *); #define DBUS_PY_RAISE_VIA_NULL_IF_FAIL(assertion) \ do { if (!(assertion)) { \ diff --git a/_dbus_bindings/float.c b/_dbus_bindings/float.c index 5826ec3..8bafce9 100644 --- a/_dbus_bindings/float.c +++ b/_dbus_bindings/float.c @@ -31,128 +31,84 @@ #include "dbus_bindings-internal.h" #include "types-internal.h" -PyDoc_STRVAR(Double_tp_doc, -"A double-precision floating point number (a subtype of float)."); - -#ifdef WITH_DBUS_FLOAT32 -PyDoc_STRVAR(Float_tp_doc, -"A single-precision floating point number (a subtype of float)."); -#endif - -PyTypeObject DBusPyDouble_Type = { - PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type)) - 0, - "dbus.Double", - 0, - 0, - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - Double_tp_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - DEFERRED_ADDRESS(&DBusPythonFloatType), /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ -}; - -#ifdef WITH_DBUS_FLOAT32 - -PyTypeObject DBusPyFloat_Type = { - PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type)) - 0, - "dbus.Float", - 0, - 0, - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - Float_tp_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - DEFERRED_ADDRESS(&DBusPythonFloatType), /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ -}; -#endif /* defined(WITH_DBUS_FLOAT32) */ +static PyObject *Double = NULL; -dbus_bool_t -dbus_py_init_float_types(void) +static dbus_bool_t +do_import(void) { - DBusPyDouble_Type.tp_base = &DBusPyFloatBase_Type; - if (PyType_Ready(&DBusPyDouble_Type) < 0) return 0; - DBusPyDouble_Type.tp_print = NULL; + PyObject *name; + PyObject *module; -#ifdef WITH_DBUS_FLOAT32 - DBusPyFloat_Type.tp_base = &DBusPyFloatBase_Type; - if (PyType_Ready(&DBusPyFloat_Type) < 0) return 0; - DBusPyFloat_Type.tp_print = NULL; -#endif + if (Double != NULL) + return TRUE; - return 1; + Py_CLEAR(Double); + + name = PyString_FromString("dbus.data"); + if (!name) + return FALSE; + + module = PyImport_Import(name); + Py_DECREF(name); + if (!module) + return FALSE; + + Double = PyObject_GetAttrString(module, "Double"); + Py_DECREF(module); + + if (Double && !PyType_Check(Double)) { + PyErr_SetString(PyExc_AssertionError, "Assertion failed: " + "isinstance(dbus.data.Double, type)"); + Double = NULL; + } + + return (Double != NULL); +} + +int +DBusPyDouble_Check(PyObject *o) +{ + if (!Double && !do_import()) + return 0; + return PyObject_TypeCheck(o, (PyTypeObject *)Double); +} + +PyObject * +DBusPyDouble_New(double value, long variant_level) +{ + PyObject *args = NULL; + PyObject *kwargs = NULL; + PyObject *ret = NULL; + + if (!Double && !do_import()) + return NULL; + + if (variant_level != 0) { + kwargs = DBusPy_BuildConstructorKeywordArgs(variant_level, NULL); + if (!kwargs) + goto finally; + } + + args = Py_BuildValue("(d)", value); + if (!args) + goto finally; + + ret = PyObject_Call(Double, args, kwargs); + +finally: + Py_XDECREF(args); + Py_XDECREF(kwargs); + return ret; } dbus_bool_t -dbus_py_insert_float_types(PyObject *this_module) +dbus_py_init_float_types(void) { - Py_INCREF(&DBusPyDouble_Type); - if (PyModule_AddObject(this_module, "Double", - (PyObject *)&DBusPyDouble_Type) < 0) return 0; -#ifdef WITH_DBUS_FLOAT32 - Py_INCREF(&DBusPyFloat_Type); - if (PyModule_AddObject(this_module, "Float", - (PyObject *)&DBusPyFloat_Type) < 0) return 0; -#endif + return 1; +} +dbus_bool_t +dbus_py_insert_float_types(PyObject *this_module UNUSED) +{ return 1; } diff --git a/_dbus_bindings/int.c b/_dbus_bindings/int.c index b669d57..3806d40 100644 --- a/_dbus_bindings/int.c +++ b/_dbus_bindings/int.c @@ -25,130 +25,201 @@ #include "types-internal.h" -/* Specific types =================================================== */ - -/* Boolean, a subclass of DBusPythonInt ============================= */ - -PyDoc_STRVAR(Boolean_tp_doc, -"A boolean, represented as a subtype of `int` (not `bool`, because `bool`\n" -"cannot be subclassed).\n" -"\n" -"Constructor::\n" -"\n" -" dbus.Boolean(value[, variant_level]) -> Boolean\n" -"\n" -"``value`` is converted to 0 or 1 as if by ``int(bool(value))``.\n" -"\n" -"``variant_level`` must be non-negative; the default is 0.\n" -"\n" -":IVariables:\n" -" `variant_level` : int\n" -" Indicates how many nested Variant containers this object\n" -" is contained in: if a message's wire format has a variant containing a\n" -" variant containing a boolean, this is represented in Python by a\n" -" Boolean with variant_level==2.\n" -); - -static PyObject * -Boolean_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs) +static PyObject *DBusPyBoolean = NULL; +static PyObject *Int16 = NULL; +static PyObject *UInt16 = NULL; +static PyObject *Int32 = NULL; +static PyObject *UInt32 = NULL; +static PyObject *Int64 = NULL; +static PyObject *UInt64 = NULL; + +static dbus_bool_t +do_import(void) { - PyObject *tuple, *self, *value = Py_None; - long variantness = 0; - static char *argnames[] = {"_", "variant_level", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Ol:__new__", argnames, - &value, &variantness)) return NULL; - if (variantness < 0) { - PyErr_SetString(PyExc_ValueError, - "variant_level must be non-negative"); - return NULL; + PyObject *name; + PyObject *module; + + if (DBusPyBoolean && Int16 && UInt16 && Int32 && UInt32 && + Int64 && UInt64) + return TRUE; + + Py_CLEAR(DBusPyBoolean); + Py_CLEAR(Int16); + Py_CLEAR(UInt16); + Py_CLEAR(Int32); + Py_CLEAR(UInt32); + Py_CLEAR(Int64); + Py_CLEAR(UInt64); + + name = PyString_FromString("dbus.data"); + if (!name) + return FALSE; + + module = PyImport_Import(name); + Py_DECREF(name); + if (!module) + return FALSE; + + DBusPyBoolean = PyObject_GetAttrString(module, "Boolean"); + Int16 = PyObject_GetAttrString(module, "Int16"); + UInt16 = PyObject_GetAttrString(module, "UInt16"); + Int32 = PyObject_GetAttrString(module, "Int32"); + UInt32 = PyObject_GetAttrString(module, "UInt32"); + Int64 = PyObject_GetAttrString(module, "Int64"); + UInt64 = PyObject_GetAttrString(module, "UInt64"); + Py_DECREF(module); + + if (DBusPyBoolean && !PyType_Check(DBusPyBoolean)) { + PyErr_SetString(PyExc_AssertionError, "Assertion failed: " + "isinstance(dbus.data.Boolean, type)"); + DBusPyBoolean = NULL; + } + if (Int16 && !PyType_Check(Int16)) { + PyErr_SetString(PyExc_AssertionError, "Assertion failed: " + "isinstance(dbus.data.Int16, type)"); + Int16 = NULL; + } + if (UInt16 && !PyType_Check(UInt16)) { + PyErr_SetString(PyExc_AssertionError, "Assertion failed: " + "isinstance(dbus.data.UInt16, type)"); + UInt16 = NULL; + } + if (Int32 && !PyType_Check(Int32)) { + PyErr_SetString(PyExc_AssertionError, "Assertion failed: " + "isinstance(dbus.data.Int32, type)"); + Int32 = NULL; + } + if (UInt32 && !PyType_Check(UInt32)) { + PyErr_SetString(PyExc_AssertionError, "Assertion failed: " + "isinstance(dbus.data.UInt32, type)"); + UInt32 = NULL; + } + if (Int64 && !PyType_Check(Int64)) { + PyErr_SetString(PyExc_AssertionError, "Assertion failed: " + "isinstance(dbus.data.Int64, type)"); + Int64 = NULL; } - tuple = Py_BuildValue("(i)", PyObject_IsTrue(value) ? 1 : 0); - if (!tuple) return NULL; - self = (DBusPyIntBase_Type.tp_new)(cls, tuple, kwargs); - Py_DECREF(tuple); - return self; + if (UInt64 && !PyType_Check(UInt64)) { + PyErr_SetString(PyExc_AssertionError, "Assertion failed: " + "isinstance(dbus.data.UInt64, type)"); + UInt64 = NULL; + } + + return DBusPyBoolean && Int16 && UInt16 && Int32 && UInt32 && Int64 && + UInt64; +} + +int +DBusPyBoolean_Check(PyObject *o) +{ + if (!DBusPyBoolean && !do_import()) + return 0; + return PyObject_TypeCheck(o, (PyTypeObject *)DBusPyBoolean); } -static PyObject * -Boolean_tp_repr (PyObject *self) +PyObject * +DBusPyBoolean_New(int is_true, long variant_level) { - long variant_level = ((DBusPyIntBase *)self)->variant_level; - if (variant_level > 0) { - return PyString_FromFormat("%s(%s, variant_level=%ld)", - self->ob_type->tp_name, - PyInt_AsLong(self) ? "True" : "False", - variant_level); + PyObject *args = NULL; + PyObject *kwargs = NULL; + PyObject *ret = NULL; + + if (!DBusPyBoolean && !do_import()) + return NULL; + + if (variant_level != 0) { + kwargs = DBusPy_BuildConstructorKeywordArgs(variant_level, NULL); + if (!kwargs) + goto finally; } - return PyString_FromFormat("%s(%s)", - self->ob_type->tp_name, - PyInt_AsLong(self) ? "True" : "False"); + + args = Py_BuildValue("(i)", is_true); + if (!args) + goto finally; + + ret = PyObject_Call(DBusPyBoolean, args, kwargs); + +finally: + Py_XDECREF(args); + Py_XDECREF(kwargs); + return ret; } -PyTypeObject DBusPyBoolean_Type = { - PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type)) - 0, - "dbus.Boolean", - 0, - 0, - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - Boolean_tp_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - Boolean_tp_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - DEFERRED_ADDRESS(&DBusPyIntBase_Type), /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - Boolean_tp_new, /* tp_new */ -}; - -/* Int16 ============================================================ */ - -PyDoc_STRVAR(Int16_tp_doc, -"A signed 16-bit integer between -0x8000 and +0x7FFF, represented as\n" -"a subtype of `int`.\n" -"\n" -"Constructor::\n" -"\n" -" dbus.Int16(value: int[, variant_level: int]) -> Int16\n" -"\n" -"value must be within the allowed range, or OverflowError will be\n" -"raised.\n" -"\n" -" variant_level must be non-negative; the default is 0.\n" -"\n" -":IVariables:\n" -" `variant_level` : int\n" -" Indicates how many nested Variant containers this object\n" -" is contained in: if a message's wire format has a variant containing a\n" -" variant containing an int16, this is represented in Python by an\n" -" Int16 with variant_level==2.\n" -); +int +DBusPyInt16_Check(PyObject *o) +{ + if (!Int16 && !do_import()) + return 0; + return PyObject_TypeCheck(o, (PyTypeObject *)Int16); +} + +int +DBusPyUInt16_Check(PyObject *o) +{ + if (!UInt16 && !do_import()) + return 0; + return PyObject_TypeCheck(o, (PyTypeObject *)UInt16); +} + +int +DBusPyInt32_Check(PyObject *o) +{ + if (!Int32 && !do_import()) + return 0; + return PyObject_TypeCheck(o, (PyTypeObject *)Int32); +} + +int +DBusPyUInt32_Check(PyObject *o) +{ + if (!UInt32 && !do_import()) + return 0; + return PyObject_TypeCheck(o, (PyTypeObject *)UInt32); +} + +int +DBusPyInt64_Check(PyObject *o) +{ + if (!Int64 && !do_import()) + return 0; + return PyObject_TypeCheck(o, (PyTypeObject *)Int64); +} + +int +DBusPyUInt64_Check(PyObject *o) +{ + if (!UInt64 && !do_import()) + return 0; + return PyObject_TypeCheck(o, (PyTypeObject *)UInt64); +} + +PyObject * +DBusPyInt16_New(dbus_int16_t value, long variant_level) +{ + PyObject *args = NULL; + PyObject *kwargs = NULL; + PyObject *ret = NULL; + + if (!Int16 && !do_import()) + return NULL; + + if (variant_level != 0) { + kwargs = DBusPy_BuildConstructorKeywordArgs(variant_level, NULL); + if (!kwargs) + goto finally; + } + + args = Py_BuildValue("(i)", (int)value); + if (!args) + goto finally; + + ret = PyObject_Call(Int16, args, kwargs); + +finally: + Py_XDECREF(args); + Py_XDECREF(kwargs); + return ret; +} dbus_int16_t dbus_py_int16_range_check(PyObject *obj) @@ -163,81 +234,33 @@ dbus_py_int16_range_check(PyObject *obj) return i; } -static PyObject * -Int16_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs) +PyObject * +DBusPyUInt16_New(dbus_uint16_t value, long variant_level) { - PyObject *self = (DBusPyIntBase_Type.tp_new)(cls, args, kwargs); - if (self && dbus_py_int16_range_check(self) == -1 && PyErr_Occurred()) { - Py_DECREF(self); + PyObject *args = NULL; + PyObject *kwargs = NULL; + PyObject *ret = NULL; + + if (!UInt16 && !do_import()) return NULL; + + if (variant_level != 0) { + kwargs = DBusPy_BuildConstructorKeywordArgs(variant_level, NULL); + if (!kwargs) + goto finally; } - return self; -} -PyTypeObject DBusPyInt16_Type = { - PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type)) - 0, - "dbus.Int16", - 0, - 0, - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - Int16_tp_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - DEFERRED_ADDRESS(&DBusPyIntBase_Type), /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - Int16_tp_new, /* tp_new */ -}; - -/* UInt16 =========================================================== */ - -PyDoc_STRVAR(UInt16_tp_doc, -"An unsigned 16-bit integer between 0 and 0xFFFF, represented as\n" -"a subtype of `int`.\n" -"\n" -"Constructor::\n" -"\n" -" dbus.UInt16(value: int[, variant_level: int]) -> UInt16\n" -"\n" -"``value`` must be within the allowed range, or `OverflowError` will be\n" -"raised.\n" -"\n" -"``variant_level`` must be non-negative; the default is 0.\n" -"\n" -":IVariables:\n" -" `variant_level` : int\n" -" Indicates how many nested Variant containers this object\n" -" is contained in: if a message's wire format has a variant containing a\n" -" variant containing a uint16, this is represented in Python by a\n" -" UInt16 with variant_level==2.\n" -); + args = Py_BuildValue("(I)", (unsigned int)value); + if (!args) + goto finally; + + ret = PyObject_Call(UInt16, args, kwargs); + +finally: + Py_XDECREF(args); + Py_XDECREF(kwargs); + return ret; +} dbus_uint16_t dbus_py_uint16_range_check(PyObject *obj) @@ -252,82 +275,33 @@ dbus_py_uint16_range_check(PyObject *obj) return i; } -static PyObject * -UInt16_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs) +PyObject * +DBusPyInt32_New(dbus_int32_t value, long variant_level) { - PyObject *self = (DBusPyIntBase_Type.tp_new)(cls, args, kwargs); - if (self && dbus_py_uint16_range_check(self) == (dbus_uint16_t)(-1) - && PyErr_Occurred()) { - Py_DECREF (self); + PyObject *args = NULL; + PyObject *kwargs = NULL; + PyObject *ret = NULL; + + if (!Int32 && !do_import()) return NULL; + + if (variant_level != 0) { + kwargs = DBusPy_BuildConstructorKeywordArgs(variant_level, NULL); + if (!kwargs) + goto finally; } - return self; -} -PyTypeObject DBusPyUInt16_Type = { - PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type)) - 0, - "dbus.UInt16", - 0, - 0, - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - UInt16_tp_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - DEFERRED_ADDRESS(&DBusPyIntBase_Type), /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - UInt16_tp_new, /* tp_new */ -}; - -/* Int32 ============================================================ */ - -PyDoc_STRVAR(Int32_tp_doc, -"A signed 32-bit integer between -0x8000 0000 and +0x7FFF FFFF, represented as\n" -"a subtype of `int`.\n" -"\n" -"Constructor::\n" -"\n" -" dbus.Int32(value: int[, variant_level: int]) -> Int32\n" -"\n" -"``value`` must be within the allowed range, or `OverflowError` will be\n" -"raised.\n" -"\n" -"``variant_level`` must be non-negative; the default is 0.\n" -"\n" -":IVariables:\n" -" `variant_level` : int\n" -" Indicates how many nested Variant containers this object\n" -" is contained in: if a message's wire format has a variant containing a\n" -" variant containing an int32, this is represented in Python by an\n" -" Int32 with variant_level==2.\n" -); + args = Py_BuildValue("(l)", (long)value); + if (!args) + goto finally; + + ret = PyObject_Call(Int32, args, kwargs); + +finally: + Py_XDECREF(args); + Py_XDECREF(kwargs); + return ret; +} dbus_int32_t dbus_py_int32_range_check(PyObject *obj) @@ -342,84 +316,33 @@ dbus_py_int32_range_check(PyObject *obj) return i; } -static PyObject * -Int32_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs) +PyObject * +DBusPyUInt32_New(dbus_uint32_t value, long variant_level) { - PyObject *self = (DBusPyIntBase_Type.tp_new)(cls, args, kwargs); - if (self && dbus_py_int32_range_check(self) == -1 && PyErr_Occurred()) { - Py_DECREF(self); + PyObject *args = NULL; + PyObject *kwargs = NULL; + PyObject *ret = NULL; + + if (!UInt32 && !do_import()) return NULL; + + if (variant_level != 0) { + kwargs = DBusPy_BuildConstructorKeywordArgs(variant_level, NULL); + if (!kwargs) + goto finally; } - return self; -} -PyTypeObject DBusPyInt32_Type = { - PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type)) - 0, - "dbus.Int32", - 0, - 0, - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - Int32_tp_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - DEFERRED_ADDRESS(&DBusPyIntBase_Type), /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - Int32_tp_new, /* tp_new */ -}; - -/* UInt32 =========================================================== */ - -PyDoc_STRVAR(UInt32_tp_doc, -"An unsigned 32-bit integer between 0 and 0xFFFF FFFF, represented as a\n" -"subtype of `long`.\n" -"\n" -"Note that this may be changed in future to be a subtype of `int` on\n" -"64-bit platforms; applications should not rely on either behaviour.\n" -"\n" -"Constructor::\n" -"\n" -" dbus.UInt32(value: long[, variant_level: int]) -> UInt32\n" -"\n" -"``value`` must be within the allowed range, or `OverflowError` will be\n" -"raised.\n" -"\n" -"``variant_level`` must be non-negative; the default is 0.\n" -"\n" -":IVariables:\n" -" `variant_level` : int\n" -" Indicates how many nested Variant containers this object\n" -" is contained in: if a message's wire format has a variant containing a\n" -" variant containing a uint32, this is represented in Python by a\n" -" UInt32 with variant_level==2.\n" -); + args = Py_BuildValue("(k)", (unsigned long)value); + if (!args) + goto finally; + + ret = PyObject_Call(UInt32, args, kwargs); + +finally: + Py_XDECREF(args); + Py_XDECREF(kwargs); + return ret; +} dbus_uint32_t dbus_py_uint32_range_check(PyObject *obj) @@ -443,88 +366,33 @@ dbus_py_uint32_range_check(PyObject *obj) return i; } -static PyObject * -UInt32_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs) +PyObject * +DBusPyInt64_New(dbus_int64_t value, long variant_level) { - PyObject *self = (DBusPyLongBase_Type.tp_new)(cls, args, kwargs); - if (self && dbus_py_uint32_range_check(self) == (dbus_uint32_t)(-1) - && PyErr_Occurred()) { - Py_DECREF(self); + PyObject *args = NULL; + PyObject *kwargs = NULL; + PyObject *ret = NULL; + + if (!Int64 && !do_import()) return NULL; + + if (variant_level != 0) { + kwargs = DBusPy_BuildConstructorKeywordArgs(variant_level, NULL); + if (!kwargs) + goto finally; } - return self; -} -PyTypeObject DBusPyUInt32_Type = { - PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type)) - 0, - "dbus.UInt32", - 0, - 0, - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - UInt32_tp_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - DEFERRED_ADDRESS(&DBusPyLongBase_Type), /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - UInt32_tp_new, /* tp_new */ -}; - -/* Int64 =========================================================== */ - -PyDoc_STRVAR(Int64_tp_doc, -"A signed 64-bit integer between -0x8000 0000 0000 0000 and\n" -"+0x7FFF FFFF FFFF FFFF, represented as a subtype of `long`.\n" -"\n" -"Note that this may be changed in future to be a subtype of `int` on\n" -"64-bit platforms; applications should not rely on either behaviour.\n" -"\n" -"This type only works on platforms where the C compiler has suitable\n" -"64-bit types, such as C99 ``long long``.\n" -"\n" -"Constructor::\n" -"\n" -" dbus.Int64(value: long[, variant_level: int]) -> Int64\n" -"\n" -"``value`` must be within the allowed range, or `OverflowError` will be\n" -"raised.\n" -"\n" -"``variant_level`` must be non-negative; the default is 0.\n" -"\n" -":IVariables:\n" -" `variant_level` : int\n" -" Indicates how many nested Variant containers this object\n" -" is contained in: if a message's wire format has a variant containing a\n" -" variant containing an int64, this is represented in Python by an\n" -" Int64 with variant_level==2.\n" -); + args = Py_BuildValue("(L)", (PY_LONG_LONG)value); + if (!args) + goto finally; + + ret = PyObject_Call(Int64, args, kwargs); + +finally: + Py_XDECREF(args); + Py_XDECREF(kwargs); + return ret; +} #ifdef DBUS_PYTHON_64_BIT_WORKS dbus_int64_t @@ -549,230 +417,66 @@ dbus_py_int64_range_check(PyObject *obj) } #endif -static PyObject * -Int64_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs) +PyObject * +DBusPyUInt64_New(dbus_uint64_t value, long variant_level) { -#ifdef DBUS_PYTHON_64_BIT_WORKS - PyObject *self = (DBusPyLongBase_Type.tp_new)(cls, args, kwargs); - if (self && dbus_py_int64_range_check(self) == -1 && PyErr_Occurred()) { - Py_DECREF(self); + PyObject *args = NULL; + PyObject *kwargs = NULL; + PyObject *ret = NULL; + + if (!UInt64 && !do_import()) return NULL; + + if (variant_level != 0) { + kwargs = DBusPy_BuildConstructorKeywordArgs(variant_level, NULL); + if (!kwargs) + goto finally; } - return self; -#else - PyErr_SetString(PyExc_NotImplementedError, - "64-bit types are not available on this platform"); - return NULL; -#endif -} -PyTypeObject DBusPyInt64_Type = { - PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type)) - 0, - "dbus.Int64", - 0, - 0, - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - Int64_tp_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - DEFERRED_ADDRESS(&DBusPyLongBase_Type), /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - Int64_tp_new, /* tp_new */ -}; - -/* UInt64 =========================================================== */ - -PyDoc_STRVAR(UInt64_tp_doc, -"An unsigned 64-bit integer between 0 and 0xFFFF FFFF FFFF FFFF,\n" -"represented as a subtype of `long`.\n" -"\n" -"This type only exists on platforms where the C compiler has suitable\n" -"64-bit types, such as C99 ``unsigned long long``.\n" -"\n" -"Constructor::\n" -"\n" -" dbus.UInt64(value: long[, variant_level: int]) -> UInt64\n" -"\n" -"``value`` must be within the allowed range, or `OverflowError` will be\n" -"raised.\n" -"\n" -"``variant_level`` must be non-negative; the default is 0.\n" -"\n" -":IVariables:\n" -" `variant_level` : int\n" -" Indicates how many nested Variant containers this object\n" -" is contained in: if a message's wire format has a variant containing a\n" -" variant containing a uint64, this is represented in Python by a\n" -" UInt64 with variant_level==2.\n" -); + args = Py_BuildValue("(K)", (unsigned PY_LONG_LONG)value); + if (!args) + goto finally; + ret = PyObject_Call(UInt64, args, kwargs); + +finally: + Py_XDECREF(args); + Py_XDECREF(kwargs); + return ret; +} + +#ifdef DBUS_PYTHON_64_BIT_WORKS dbus_uint64_t dbus_py_uint64_range_check(PyObject *obj) { unsigned PY_LONG_LONG i; PyObject *long_obj = PyNumber_Long(obj); - if (!long_obj) return (dbus_uint64_t)(-1); + if (!long_obj) return -1; i = PyLong_AsUnsignedLongLong(long_obj); - if (i == (unsigned PY_LONG_LONG)(-1) && PyErr_Occurred()) { + if (i == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred()) { Py_DECREF(long_obj); - return (dbus_uint64_t)(-1); + return -1; } if (i > UINT64_MAX) { PyErr_SetString(PyExc_OverflowError, "Value out of range for UInt64"); Py_DECREF(long_obj); - return (dbus_uint64_t)(-1); + return -1; } Py_DECREF(long_obj); return i; } - -static PyObject * -UInt64_tp_new (PyTypeObject *cls, PyObject *args, PyObject *kwargs) -{ -#ifdef DBUS_PYTHON_64_BIT_WORKS - PyObject *self = (DBusPyLongBase_Type.tp_new)(cls, args, kwargs); - if (self && dbus_py_uint64_range_check(self) == (dbus_uint64_t)(-1) - && PyErr_Occurred()) { - Py_DECREF(self); - return NULL; - } - return self; -#else - PyErr_SetString(PyExc_NotImplementedError, - "64-bit integer types are not supported on this platform"); - return NULL; #endif -} - -PyTypeObject DBusPyUInt64_Type = { - PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type)) - 0, - "dbus.UInt64", - 0, - 0, - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - UInt64_tp_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - DEFERRED_ADDRESS(&DBusPyLongBase_Type), /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - UInt64_tp_new, /* tp_new */ -}; dbus_bool_t dbus_py_init_int_types(void) { - DBusPyInt16_Type.tp_base = &DBusPyIntBase_Type; - if (PyType_Ready(&DBusPyInt16_Type) < 0) return 0; - /* disable the tp_print copied from PyInt_Type, so tp_repr gets called as - desired */ - DBusPyInt16_Type.tp_print = NULL; - - DBusPyUInt16_Type.tp_base = &DBusPyIntBase_Type; - if (PyType_Ready(&DBusPyUInt16_Type) < 0) return 0; - DBusPyUInt16_Type.tp_print = NULL; - - DBusPyInt32_Type.tp_base = &DBusPyIntBase_Type; - if (PyType_Ready(&DBusPyInt32_Type) < 0) return 0; - DBusPyInt32_Type.tp_print = NULL; - - DBusPyUInt32_Type.tp_base = &DBusPyLongBase_Type; - if (PyType_Ready(&DBusPyUInt32_Type) < 0) return 0; - DBusPyUInt32_Type.tp_print = NULL; - -#if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG) - DBusPyInt64_Type.tp_base = &DBusPyLongBase_Type; - if (PyType_Ready(&DBusPyInt64_Type) < 0) return 0; - DBusPyInt64_Type.tp_print = NULL; - - DBusPyUInt64_Type.tp_base = &DBusPyLongBase_Type; - if (PyType_Ready(&DBusPyUInt64_Type) < 0) return 0; - DBusPyUInt64_Type.tp_print = NULL; -#endif return 1; } dbus_bool_t -dbus_py_insert_int_types(PyObject *this_module) +dbus_py_insert_int_types(PyObject *this_module UNUSED) { - Py_INCREF(&DBusPyInt16_Type); - Py_INCREF(&DBusPyUInt16_Type); - Py_INCREF(&DBusPyInt32_Type); - Py_INCREF(&DBusPyUInt32_Type); - Py_INCREF(&DBusPyInt64_Type); - Py_INCREF(&DBusPyUInt64_Type); - Py_INCREF(&DBusPyBoolean_Type); - if (PyModule_AddObject(this_module, "Int16", - (PyObject *)&DBusPyInt16_Type) < 0) return 0; - if (PyModule_AddObject(this_module, "UInt16", - (PyObject *)&DBusPyUInt16_Type) < 0) return 0; - if (PyModule_AddObject(this_module, "Int32", - (PyObject *)&DBusPyInt32_Type) < 0) return 0; - if (PyModule_AddObject(this_module, "UInt32", - (PyObject *)&DBusPyUInt32_Type) < 0) return 0; - if (PyModule_AddObject(this_module, "Int64", - (PyObject *)&DBusPyInt64_Type) < 0) return 0; - if (PyModule_AddObject(this_module, "UInt64", - (PyObject *)&DBusPyUInt64_Type) < 0) return 0; - if (PyModule_AddObject(this_module, "Boolean", - (PyObject *)&DBusPyBoolean_Type) < 0) return 0; - return 1; } diff --git a/_dbus_bindings/message-append.c b/_dbus_bindings/message-append.c index 93b76c7..b161d08 100644 --- a/_dbus_bindings/message-append.c +++ b/_dbus_bindings/message-append.c @@ -28,35 +28,69 @@ #include "types-internal.h" #include "message-internal.h" +static PyObject *DBusPyTypeMixin = NULL; + +static dbus_bool_t +do_import(void) +{ + PyObject *name; + PyObject *module; + + if (DBusPyTypeMixin) + return TRUE; + + Py_CLEAR(DBusPyTypeMixin); + + name = PyString_FromString("dbus.data"); + if (!name) + return FALSE; + + module = PyImport_Import(name); + Py_DECREF(name); + if (!module) + return FALSE; + + DBusPyTypeMixin = PyObject_GetAttrString(module, "_DBusTypeMixin"); + Py_DECREF(module); + + return (DBusPyTypeMixin != NULL); +} + +/* When the types actually become pure-Python, this will only check for the + * common superclass DBusTypeMixin. During a transitional period, not all + * types subclass it, though. + */ +static int +DBusTypeMixin_Check(PyObject *o) +{ + if (!DBusPyTypeMixin) + do_import(); + + if (DBusPyTypeMixin && PyObject_TypeCheck(o, + (PyTypeObject *)DBusPyTypeMixin)) + return 1; + + return (DBusPyStruct_Check(o) || DBusPyDictionary_Check(o) + || DBusPySignature_Check(o)); +} + /* Return the number of variants wrapping the given object. Return 0 * if the object is not a D-Bus type. */ static long get_variant_level(PyObject *obj) { - if (DBusPyIntBase_Check(obj)) { - return ((DBusPyIntBase *)obj)->variant_level; - } - else if (DBusPyFloatBase_Check(obj)) { - return ((DBusPyFloatBase *)obj)->variant_level; - } - else if (DBusPyArray_Check(obj)) { - return ((DBusPyArray *)obj)->variant_level; - } - else if (DBusPyDict_Check(obj)) { - return ((DBusPyDict *)obj)->variant_level; - } - else if (DBusPyString_Check(obj)) { - return ((DBusPyString *)obj)->variant_level; - } - else if (DBusPyLongBase_Check(obj) || - DBusPyStrBase_Check(obj) || - DBusPyStruct_Check(obj)) { - return dbus_py_variant_level_get(obj); - } - else { - return 0; + long ret = 0; + + if (DBusTypeMixin_Check(obj)) { + PyObject *attr = PyObject_GetAttrString(obj, "variant_level"); + + if (attr && PyInt_Check(attr)) { + ret = PyInt_AS_LONG(attr); + } + Py_XDECREF(attr); } + return ret; } char dbus_py_Message_append__doc__[] = ( @@ -298,10 +332,15 @@ _signature_string_from_pyobject(PyObject *obj, long *variant_level_ptr) else if (PyList_Check(obj)) { PyObject *tmp; PyObject *ret = PyString_FromString(DBUS_TYPE_ARRAY_AS_STRING); - if (!ret) return NULL; - if (DBusPyArray_Check(obj) && PyString_Check(((DBusPyArray *)obj)->signature)) { - PyString_Concat(&ret, ((DBusPyArray *)obj)->signature); - return ret; + if (!ret) + return NULL; + if (DBusPyArray_Check(obj)) { + PyObject *sig = PyObject_GetAttr(obj, dbus_py_signature_const); + + if (sig != NULL && PyString_Check(sig)) { + PyString_Concat(&ret, sig); + return ret; + } } if (PyList_GET_SIZE(obj) == 0) { /* No items, so fail. Or should we guess "av"? */ @@ -320,14 +359,16 @@ _signature_string_from_pyobject(PyObject *obj, long *variant_level_ptr) Py_ssize_t pos = 0; PyObject *ret = NULL; - if (DBusPyDict_Check(obj) && PyString_Check(((DBusPyDict *)obj)->signature)) { - const char *sig = PyString_AS_STRING(((DBusPyDict *)obj)->signature); + if (DBusPyDictionary_Check(obj)) { + PyObject *sig = PyObject_GetAttr(obj, dbus_py_signature_const); - return PyString_FromFormat((DBUS_TYPE_ARRAY_AS_STRING - DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING - "%s" - DBUS_DICT_ENTRY_END_CHAR_AS_STRING), - sig); + if (sig != NULL && PyString_Check(sig)) { + return PyString_FromFormat((DBUS_TYPE_ARRAY_AS_STRING + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + "%s" + DBUS_DICT_ENTRY_END_CHAR_AS_STRING), + PyString_AS_STRING(sig)); + } } if (!PyDict_Next(obj, &pos, &key, &value)) { /* No items, so fail. Or should we guess "a{vv}"? */ @@ -384,7 +425,7 @@ dbus_py_Message_guess_signature(PyObject *unused UNUSED, PyObject *args) /* if there were no args, easy */ if (PyTuple_GET_SIZE(args) == 0) { DBG("%s", "Message_guess_signature: no args, so return Signature('')"); - return PyObject_CallFunction((PyObject *)&DBusPySignature_Type, "(s)", ""); + return DBusPySignature_FromString(""); } /* if there were args, the signature we want is, by construction, @@ -402,9 +443,8 @@ dbus_py_Message_guess_signature(PyObject *unused UNUSED, PyObject *args) Py_DECREF(tmp); return NULL; } - ret = PyObject_CallFunction((PyObject *)&DBusPySignature_Type, "(s#)", - PyString_AS_STRING(tmp) + 1, - PyString_GET_SIZE(tmp) - 2); + ret = DBusPySignature_FromStringAndSize(PyString_AS_STRING(tmp) + 1, + PyString_GET_SIZE(tmp) - 2); DBG("Message_guess_signature: returning Signature at %p \"%s\"", ret, ret ? PyString_AS_STRING(ret) : "(NULL)"); Py_DECREF(tmp); @@ -659,13 +699,14 @@ _message_iter_append_multi(DBusMessageIter *appender, * variants, we want to produce an array of variants containing * bytes, not strings. */ - PyObject *args = Py_BuildValue("(O)", contents); PyObject *byte; - if (!args) + if (!PyString_Check(contents)) { + PyErr_BadArgument(); break; - byte = PyObject_Call((PyObject *)&DBusPyByte_Type, args, NULL); - Py_DECREF(args); + } + byte = DBusPyByte_New( + (unsigned char)PyString_AS_STRING(contents)[0], 0); if (!byte) break; ret = _message_iter_append_variant(&sub_appender, byte); diff --git a/_dbus_bindings/message-get-args.c b/_dbus_bindings/message-get-args.c index 7d55ffd..fd020d4 100644 --- a/_dbus_bindings/message-get-args.c +++ b/_dbus_bindings/message-get-args.c @@ -113,32 +113,26 @@ _message_iter_append_all_to_list(DBusMessageIter *iter, PyObject *list, static inline PyObject * _message_iter_get_dict(DBusMessageIter *iter, Message_get_args_options *opts, - PyObject *kwargs) + long variant_level) { DBusMessageIter entries; char *sig_str = dbus_message_iter_get_signature(iter); PyObject *sig; PyObject *ret; - int status; if (!sig_str) { PyErr_NoMemory(); return NULL; } - sig = PyObject_CallFunction((PyObject *)&DBusPySignature_Type, - "(s#)", sig_str+2, - (Py_ssize_t)strlen(sig_str)-3); + /* drop the trailing '}' and the leading 'a{' */ + sig = DBusPySignature_FromStringAndSize(sig_str+2, + (Py_ssize_t)strlen(sig_str)-3); dbus_free(sig_str); if (!sig) { return NULL; } - status = PyDict_SetItem(kwargs, dbus_py_signature_const, sig); - Py_DECREF(sig); - if (status < 0) { - return NULL; - } - ret = PyObject_Call((PyObject *)&DBusPyDict_Type, dbus_py_empty_tuple, kwargs); + ret = DBusPyDictionary_New (PyString_AS_STRING (sig), variant_level); if (!ret) { return NULL; } @@ -148,6 +142,7 @@ _message_iter_get_dict(DBusMessageIter *iter, PyObject *key = NULL; PyObject *value = NULL; DBusMessageIter kv; + int status; DBG("%s", "dict entry..."); @@ -203,33 +198,8 @@ _message_iter_get_pyobject(DBusMessageIter *iter, #endif } u; int type = dbus_message_iter_get_arg_type(iter); - PyObject *args = NULL; - PyObject *kwargs = NULL; PyObject *ret = NULL; - /* If the variant-level is >0, prepare a dict for the kwargs. - * For variant wrappers optimize slightly by skipping this. - */ - if (variant_level > 0 && type != DBUS_TYPE_VARIANT) { - PyObject *variant_level_int; - - variant_level_int = PyInt_FromLong(variant_level); - if (!variant_level_int) { - return NULL; - } - kwargs = PyDict_New(); - if (!kwargs) { - Py_DECREF(variant_level_int); - return NULL; - } - if (PyDict_SetItem(kwargs, dbus_py_variant_level_const, - variant_level_int) < 0) { - Py_DECREF(variant_level_int); - Py_DECREF(kwargs); - return NULL; - } - Py_DECREF(variant_level_int); - } /* From here down you need to break from the switch to exit, so the * dict is freed if necessary */ @@ -239,104 +209,75 @@ _message_iter_get_pyobject(DBusMessageIter *iter, DBG("%s", "found a string"); dbus_message_iter_get_basic(iter, &u.s); if (opts->utf8_strings) { - args = Py_BuildValue("(s)", u.s); - if (!args) break; - ret = PyObject_Call((PyObject *)&DBusPyUTF8String_Type, - args, kwargs); + ret = DBusPyUTF8String_New (u.s, variant_level); } else { - args = Py_BuildValue("(N)", PyUnicode_DecodeUTF8(u.s, - strlen(u.s), - NULL)); - if (!args) { - break; - } - ret = PyObject_Call((PyObject *)&DBusPyString_Type, - args, kwargs); + ret = DBusPyString_New (u.s, variant_level); } break; case DBUS_TYPE_SIGNATURE: DBG("%s", "found a signature"); dbus_message_iter_get_basic(iter, &u.s); - args = Py_BuildValue("(s)", u.s); - if (!args) break; - ret = PyObject_Call((PyObject *)&DBusPySignature_Type, args, kwargs); + ret = DBusPySignature_FromStringAndVariantLevel(u.s, + variant_level); break; case DBUS_TYPE_OBJECT_PATH: DBG("%s", "found an object path"); dbus_message_iter_get_basic(iter, &u.s); - args = Py_BuildValue("(s)", u.s); - if (!args) break; - ret = PyObject_Call((PyObject *)&DBusPyObjectPath_Type, args, kwargs); + ret = DBusPyObjectPath_New (u.s, variant_level); break; case DBUS_TYPE_DOUBLE: DBG("%s", "found a double"); dbus_message_iter_get_basic(iter, &u.d); - args = Py_BuildValue("(f)", u.d); - if (!args) break; - ret = PyObject_Call((PyObject *)&DBusPyDouble_Type, args, kwargs); + ret = DBusPyDouble_New (u.d, variant_level); break; #ifdef WITH_DBUS_FLOAT32 case DBUS_TYPE_FLOAT: DBG("%s", "found a float"); dbus_message_iter_get_basic(iter, &u.f); - args = Py_BuildValue("(f)", (double)u.f); - if (!args) break; - ret = PyObject_Call((PyObject *)&DBusPyFloat_Type, args, kwargs); + ret = DBusPyFloat_New (u.f, variant_level); break; #endif case DBUS_TYPE_INT16: DBG("%s", "found an int16"); dbus_message_iter_get_basic(iter, &u.i16); - args = Py_BuildValue("(i)", (int)u.i16); - if (!args) break; - ret = PyObject_Call((PyObject *)&DBusPyInt16_Type, args, kwargs); + ret = DBusPyInt16_New (u.i16, variant_level); break; case DBUS_TYPE_UINT16: DBG("%s", "found a uint16"); dbus_message_iter_get_basic(iter, &u.u16); - args = Py_BuildValue("(i)", (int)u.u16); - if (!args) break; - ret = PyObject_Call((PyObject *)&DBusPyUInt16_Type, args, kwargs); + ret = DBusPyUInt16_New (u.u16, variant_level); break; case DBUS_TYPE_INT32: DBG("%s", "found an int32"); dbus_message_iter_get_basic(iter, &u.i32); - args = Py_BuildValue("(l)", (long)u.i32); - if (!args) break; - ret = PyObject_Call((PyObject *)&DBusPyInt32_Type, args, kwargs); + ret = DBusPyInt32_New (u.i32, variant_level); break; case DBUS_TYPE_UINT32: DBG("%s", "found a uint32"); dbus_message_iter_get_basic(iter, &u.u32); - args = Py_BuildValue("(k)", (unsigned long)u.u32); - if (!args) break; - ret = PyObject_Call((PyObject *)&DBusPyUInt32_Type, args, kwargs); + ret = DBusPyUInt32_New (u.u32, variant_level); break; #if defined(DBUS_HAVE_INT64) && defined(HAVE_LONG_LONG) case DBUS_TYPE_INT64: DBG("%s", "found an int64"); dbus_message_iter_get_basic(iter, &u.i64); - args = Py_BuildValue("(L)", (PY_LONG_LONG)u.i64); - if (!args) break; - ret = PyObject_Call((PyObject *)&DBusPyInt64_Type, args, kwargs); + ret = DBusPyInt64_New (u.i64, variant_level); break; case DBUS_TYPE_UINT64: DBG("%s", "found a uint64"); dbus_message_iter_get_basic(iter, &u.u64); - args = Py_BuildValue("(K)", (unsigned PY_LONG_LONG)u.u64); - if (!args) break; - ret = PyObject_Call((PyObject *)&DBusPyUInt64_Type, args, kwargs); + ret = DBusPyUInt64_New (u.u64, variant_level); break; #else case DBUS_TYPE_INT64: @@ -350,19 +291,13 @@ _message_iter_get_pyobject(DBusMessageIter *iter, case DBUS_TYPE_BYTE: DBG("%s", "found a byte"); dbus_message_iter_get_basic(iter, &u.y); - args = Py_BuildValue("(l)", (long)u.y); - if (!args) - break; - ret = PyObject_Call((PyObject *)&DBusPyByte_Type, args, kwargs); + ret = DBusPyByte_New(u.y, variant_level); break; case DBUS_TYPE_BOOLEAN: DBG("%s", "found a bool"); dbus_message_iter_get_basic(iter, &u.b); - args = Py_BuildValue("(l)", (long)u.b); - if (!args) - break; - ret = PyObject_Call((PyObject *)&DBusPyBoolean_Type, args, kwargs); + ret = DBusPyBoolean_New(u.b, variant_level); break; case DBUS_TYPE_ARRAY: @@ -372,11 +307,7 @@ _message_iter_get_pyobject(DBusMessageIter *iter, type = dbus_message_iter_get_element_type(iter); if (type == DBUS_TYPE_DICT_ENTRY) { DBG("%s", "no, actually it's a dict..."); - if (!kwargs) { - kwargs = PyDict_New(); - if (!kwargs) break; - } - ret = _message_iter_get_dict(iter, opts, kwargs); + ret = _message_iter_get_dict(iter, opts, variant_level); } else if (opts->byte_arrays && type == DBUS_TYPE_BYTE) { DBusMessageIter sub; @@ -387,34 +318,23 @@ _message_iter_get_pyobject(DBusMessageIter *iter, dbus_message_iter_get_fixed_array(&sub, (const unsigned char **)&u.s, &n); - args = Py_BuildValue("(s#)", u.s, (Py_ssize_t)n); - if (!args) break; - ret = PyObject_Call((PyObject *)&DBusPyByteArray_Type, - args, kwargs); + ret = DBusPyByteArray_New(u.s, n, variant_level); } else { DBusMessageIter sub; char *sig; PyObject *sig_obj; - int status; DBG("%s", "a normal array..."); - if (!kwargs) { - kwargs = PyDict_New(); - if (!kwargs) break; - } dbus_message_iter_recurse(iter, &sub); sig = dbus_message_iter_get_signature(&sub); if (!sig) break; - sig_obj = PyObject_CallFunction((PyObject *)&DBusPySignature_Type, - "(s)", sig); + sig_obj = DBusPySignature_FromString(sig); dbus_free(sig); if (!sig_obj) break; - status = PyDict_SetItem(kwargs, dbus_py_signature_const, sig_obj); + ret = DBusPyArray_New(PyString_AS_STRING(sig_obj), + variant_level); Py_DECREF(sig_obj); - if (status < 0) break; - ret = PyObject_Call((PyObject *)&DBusPyArray_Type, - dbus_py_empty_tuple, kwargs); if (!ret) break; if (_message_iter_append_all_to_list(&sub, ret, opts) < 0) { Py_DECREF(ret); @@ -427,7 +347,6 @@ _message_iter_get_pyobject(DBusMessageIter *iter, { DBusMessageIter sub; PyObject *list = PyList_New(0); - PyObject *tuple; DBG("%s", "found a struct..."); if (!list) break; @@ -436,16 +355,9 @@ _message_iter_get_pyobject(DBusMessageIter *iter, Py_DECREF(list); break; } - tuple = Py_BuildValue("(O)", list); - if (tuple) { - ret = PyObject_Call((PyObject *)&DBusPyStruct_Type, tuple, kwargs); - } - else { - ret = NULL; - } + ret = DBusPyStruct_New(list, variant_level); /* whether successful or not, we take the same action: */ Py_DECREF(list); - Py_XDECREF(tuple); } break; @@ -464,8 +376,6 @@ _message_iter_get_pyobject(DBusMessageIter *iter, "message", type); } - Py_XDECREF(args); - Py_XDECREF(kwargs); return ret; } diff --git a/_dbus_bindings/message.c b/_dbus_bindings/message.c index 8da8ffc..ec14f92 100644 --- a/_dbus_bindings/message.c +++ b/_dbus_bindings/message.c @@ -463,7 +463,7 @@ Message_get_path(Message *self, PyObject *unused UNUSED) if (!c_str) { Py_RETURN_NONE; } - return PyObject_CallFunction((PyObject *)&DBusPyObjectPath_Type, "(s)", c_str); + return DBusPyObjectPath_New(c_str, 0); } PyDoc_STRVAR(Message_get_path_decomposed__doc__, @@ -546,9 +546,9 @@ Message_get_signature(Message *self, PyObject *unused UNUSED) if (!self->msg) return DBusPy_RaiseUnusableMessage(); c_str = dbus_message_get_signature(self->msg); if (!c_str) { - return PyObject_CallFunction((PyObject *)&DBusPySignature_Type, "(s)", ""); + c_str = ""; } - return PyObject_CallFunction((PyObject *)&DBusPySignature_Type, "(s)", c_str); + return DBusPySignature_FromString(c_str); } PyDoc_STRVAR(Message_has_signature__doc__, diff --git a/_dbus_bindings/module.c b/_dbus_bindings/module.c index ddeb1f0..8dd756c 100644 --- a/_dbus_bindings/module.c +++ b/_dbus_bindings/module.c @@ -149,6 +149,25 @@ validate_object_path(PyObject *unused UNUSED, PyObject *args) Py_RETURN_NONE; } +PyDoc_STRVAR(validate_signature__doc__, +"validate_signature(signature)\n\n" +"Raise ValueError if the given string is not a valid signature.\n"); + +static PyObject * +validate_signature(PyObject *unused UNUSED, PyObject *args) +{ + const char *s; + + if (!PyArg_ParseTuple(args, "s:validate_signature", &s)) { + return NULL; + } + if (!dbus_signature_validate(s, NULL)) { + PyErr_SetString(PyExc_ValueError, "Corrupt type signature"); + return NULL; + } + Py_RETURN_NONE; +} + /* Global functions - main loop =====================================*/ /* The main loop if none is passed to the constructor */ @@ -224,11 +243,13 @@ static PyMethodDef module_functions[] = { ENTRY(validate_member_name, METH_VARARGS), ENTRY(validate_bus_name, METH_VARARGS|METH_KEYWORDS), ENTRY(validate_object_path, METH_VARARGS), + ENTRY(validate_signature, METH_VARARGS), ENTRY(set_default_main_loop, METH_VARARGS), ENTRY(get_default_main_loop, METH_NOARGS), /* validate_error_name is just implemented as validate_interface_name */ {"validate_error_name", validate_interface_name, METH_VARARGS, validate_error_name__doc__}, + {"get_signature_iter", dbus_py_get_signature_iter, METH_O, ""}, #undef ENTRY {NULL, NULL, 0, NULL} }; diff --git a/_dbus_bindings/signature.c b/_dbus_bindings/signature.c index 6b31ab4..fef9a27 100644 --- a/_dbus_bindings/signature.c +++ b/_dbus_bindings/signature.c @@ -31,27 +31,37 @@ #include "dbus_bindings-internal.h" #include "types-internal.h" -PyDoc_STRVAR(Signature_tp_doc, -"A string subclass whose values are restricted to valid D-Bus\n" -"signatures. When iterated over, instead of individual characters it\n" -"produces Signature instances representing single complete types.\n" -"\n" -"Constructor::\n" -"\n" -" ``Signature(value: str or unicode[, variant_level: int]) -> Signature``\n" -"\n" -"``value`` must be a valid D-Bus signature (zero or more single complete\n" -"types).\n" -"\n" -"``variant_level`` must be non-negative; the default is 0.\n" -"\n" -":IVariables:\n" -" `variant_level` : int\n" -" Indicates how many nested Variant containers this object\n" -" is contained in: if a message's wire format has a variant containing a\n" -" variant containing a signature, this is represented in Python by a\n" -" Signature with variant_level==2.\n" -); +static PyObject *Signature = NULL; + +static dbus_bool_t +do_import(void) +{ + PyObject *name; + PyObject *module; + + if (Signature != NULL) + return TRUE; + + name = PyString_FromString("dbus.data"); + if (!name) + return FALSE; + + module = PyImport_Import(name); + Py_DECREF(name); + if (!module) + return FALSE; + + Signature = PyObject_GetAttrString(module, "Signature"); + Py_DECREF(module); + + if (Signature && !PyType_Check(Signature)) { + PyErr_SetString(PyExc_AssertionError, "Assertion failed: " + "isinstance(dbus.data.Signature, type)"); + Signature = NULL; + } + + return (Signature != NULL); +} typedef struct { PyObject_HEAD @@ -78,7 +88,7 @@ SignatureIter_tp_iternext (SignatureIter *self) sig = dbus_signature_iter_get_signature(&(self->iter)); if (!sig) return PyErr_NoMemory(); - obj = PyObject_CallFunction((PyObject *)&DBusPySignature_Type, "s", sig); + obj = PyObject_CallFunction(Signature, "s", sig); dbus_free(sig); if (!obj) return NULL; @@ -142,16 +152,24 @@ static PyTypeObject SignatureIterType = { 0, /* tp_free */ }; -static PyObject * -Signature_tp_iter (PyObject *self) +PyObject * +dbus_py_get_signature_iter (PyObject *unused UNUSED, PyObject *sig) { - SignatureIter *iter = PyObject_New(SignatureIter, &SignatureIterType); - if (!iter) return NULL; + SignatureIter *iter; + + if (!DBusPySignature_Check (sig)) { + PyErr_SetString(PyExc_TypeError, "A dbus.data.Signature is required"); + } - if (PyString_AS_STRING (self)[0]) { - Py_INCREF(self); - iter->string = self; - dbus_signature_iter_init(&(iter->iter), PyString_AS_STRING(self)); + iter = PyObject_New(SignatureIter, &SignatureIterType); + + if (!iter) + return NULL; + + if (PyString_AS_STRING (sig)[0]) { + Py_INCREF(sig); + iter->string = sig; + dbus_signature_iter_init(&(iter->iter), PyString_AS_STRING(sig)); } else { /* this is a null string, make a null iterator */ @@ -160,83 +178,66 @@ Signature_tp_iter (PyObject *self) return (PyObject *)iter; } -static PyObject * -Signature_tp_new (PyTypeObject *cls, PyObject *args, PyObject *kwargs) +PyObject * +DBusPySignature_FromStringObject(PyObject *o, int allow_none) { - const char *str = NULL; - PyObject *ignored; - static char *argnames[] = {"object_path", "variant_level", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|O:__new__", argnames, - &str, &ignored)) return NULL; - if (!dbus_signature_validate(str, NULL)) { - PyErr_SetString(PyExc_ValueError, "Corrupt type signature"); + if (!Signature && !do_import()) return NULL; + + if (allow_none && o == Py_None) { + Py_INCREF(o); + return o; + } + if (PyObject_TypeCheck(o, (PyTypeObject *)Signature)) { + Py_INCREF(o); + return o; } - return (DBusPyStrBase_Type.tp_new)(cls, args, kwargs); + return PyObject_CallFunction(Signature, "(O)", o); } -PyTypeObject DBusPySignature_Type = { - PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type)) - 0, - "dbus.Signature", - 0, - 0, - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - Signature_tp_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - Signature_tp_iter, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - DEFERRED_ADDRESS(&DBusPythonStringType), /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - Signature_tp_new, /* tp_new */ - 0, /* tp_free */ -}; +PyObject * +DBusPySignature_FromStringAndVariantLevel(const char *str, long variant_level) +{ + if (!Signature && !do_import()) + return NULL; + return PyObject_CallFunction(Signature, "(sl)", str, variant_level); +} + +PyObject * +DBusPySignature_FromStringAndSize(const char *str, Py_ssize_t size) +{ + if (!Signature && !do_import()) + return NULL; + return PyObject_CallFunction(Signature, "(s#)", str, size); +} + +PyObject * +DBusPySignature_FromString(const char *str) +{ + if (!Signature && !do_import()) + return NULL; + return PyObject_CallFunction(Signature, "(s)", str); +} + +int +DBusPySignature_Check(PyObject *o) +{ + if (!Signature && !do_import()) + return 0; + return PyObject_TypeCheck(o, (PyTypeObject *)Signature); +} dbus_bool_t dbus_py_init_signature(void) { if (PyType_Ready(&SignatureIterType) < 0) return 0; - DBusPySignature_Type.tp_base = &DBusPyStrBase_Type; - if (PyType_Ready(&DBusPySignature_Type) < 0) return 0; - DBusPySignature_Type.tp_print = NULL; - return 1; } dbus_bool_t dbus_py_insert_signature(PyObject *this_module) { - Py_INCREF(&DBusPySignature_Type); - if (PyModule_AddObject(this_module, "Signature", - (PyObject *)&DBusPySignature_Type) < 0) return 0; Py_INCREF(&SignatureIterType); if (PyModule_AddObject(this_module, "_SignatureIter", (PyObject *)&SignatureIterType) < 0) return 0; diff --git a/_dbus_bindings/string.c b/_dbus_bindings/string.c index 19eab2c..1aa1825 100644 --- a/_dbus_bindings/string.c +++ b/_dbus_bindings/string.c @@ -26,354 +26,173 @@ #include "types-internal.h" #include <structmember.h> -/* UTF-8 string representation ====================================== */ - -PyDoc_STRVAR(UTF8String_tp_doc, -"A string represented using UTF-8 - a subtype of `str`.\n" -"\n" -"All strings on D-Bus are required to be valid Unicode; in the \"wire\n" -"protocol\" they're transported as UTF-8.\n" -"\n" -"By default, when byte arrays are converted from D-Bus to Python, they\n" -"come out as a `dbus.String`, which is a subtype of `unicode`.\n" -"If you prefer to get UTF-8 strings (as instances of this class) or you\n" -"want to avoid the conversion overhead of going from UTF-8 to Python's\n" -"internal Unicode representation, you can pass the ``utf8_strings=True``\n" -"keyword argument to any of these methods:\n" -"\n" -"* any D-Bus method proxy, or ``connect_to_signal``, on the objects returned\n" -" by `Bus.get_object`\n" -"* any D-Bus method on a `dbus.Interface`\n" -"* `dbus.Interface.connect_to_signal`\n" -"* `Bus.add_signal_receiver`\n" -"\n" -"\n" -"Constructor::\n" -"\n" -" dbus.UTF8String(value: str or unicode[, variant_level: int]) -> UTF8String\n" -"\n" -"If value is a str object it must be valid UTF-8.\n" -"\n" -"variant_level must be non-negative; the default is 0.\n" -"\n" -":IVariables:\n" -" `variant_level` : int\n" -" Indicates how many nested Variant containers this object\n" -" is contained in: if a message's wire format has a variant containing a\n" -" variant containing a string, this is represented in Python by a\n" -" String or UTF8String with variant_level==2.\n" -":Since: 0.80 (in older versions, use dbus.String)\n" -); - -static PyObject * -UTF8String_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs) +static PyObject *String = NULL; +static PyObject *UTF8String = NULL; +static PyObject *ObjectPath = NULL; + +static dbus_bool_t +do_import(void) { - const char *str = NULL; - long variantness = 0; - static char *argnames[] = {"value", "variant_level", NULL}; - PyObject *unicode; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|l:__new__", argnames, - &str, &variantness)) return NULL; - unicode = PyUnicode_DecodeUTF8(str, strlen(str), NULL); - if (!unicode) return NULL; - Py_DECREF(unicode); - return (DBusPyStrBase_Type.tp_new)(cls, args, kwargs); + PyObject *name; + PyObject *module; + + if (String && ObjectPath && UTF8String) + return TRUE; + + Py_CLEAR(String); + Py_CLEAR(UTF8String); + Py_CLEAR(ObjectPath); + + name = PyString_FromString("dbus.data"); + if (!name) + return FALSE; + + module = PyImport_Import(name); + Py_DECREF(name); + if (!module) + return FALSE; + + String = PyObject_GetAttrString(module, "String"); + UTF8String = PyObject_GetAttrString(module, "UTF8String"); + ObjectPath = PyObject_GetAttrString(module, "ObjectPath"); + Py_DECREF(module); + + if (String && !PyType_Check(String)) { + PyErr_SetString(PyExc_AssertionError, "Assertion failed: " + "isinstance(dbus.data.String, type)"); + String = NULL; + } + if (UTF8String && !PyType_Check(UTF8String)) { + PyErr_SetString(PyExc_AssertionError, "Assertion failed: " + "isinstance(dbus.data.UTF8String, type)"); + UTF8String = NULL; + } + if (ObjectPath && !PyType_Check(ObjectPath)) { + PyErr_SetString(PyExc_AssertionError, "Assertion failed: " + "isinstance(dbus.data.ObjectPath, type)"); + ObjectPath = NULL; + } + + return (String != NULL && UTF8String != NULL && ObjectPath != NULL); } -PyTypeObject DBusPyUTF8String_Type = { - PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type)) - 0, - "dbus.UTF8String", - 0, - 0, - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - UTF8String_tp_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - DEFERRED_ADDRESS(&DBusPyStrBase_Type), /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - UTF8String_tp_new, /* tp_new */ -}; - -/* Object path ====================================================== */ - -PyDoc_STRVAR(ObjectPath_tp_doc, -"A D-Bus object path, such as '/com/example/MyApp/Documents/abc'.\n" -"\n" -"ObjectPath is a subtype of str, and object-paths behave like strings.\n" -"\n" -"Constructor::\n" -"\n" -" dbus.ObjectPath(path: str, variant_level: int) -> ObjectPath\n" -"\n" -"path must be an ASCII string following the syntax of object paths.\n" -"variant_level must be non-negative; the default is 0.\n" -"\n" -":IVariables:\n" -" `variant_level` : int\n" -" Indicates how many nested Variant containers this object\n" -" is contained in: if a message's wire format has a variant containing a\n" -" variant containing an object path, this is represented in Python by an\n" -" ObjectPath with variant_level==2.\n" -); - -static PyObject * -ObjectPath_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs) +int +DBusPyString_Check(PyObject *o) { - const char *str = NULL; - long variantness = 0; - static char *argnames[] = {"object_path", "variant_level", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|l:__new__", argnames, - &str, &variantness)) return NULL; - if (!dbus_py_validate_object_path(str)) { - return NULL; - } - return (DBusPyStrBase_Type.tp_new)(cls, args, kwargs); + if (!String && !do_import()) + return 0; + return PyObject_TypeCheck(o, (PyTypeObject *)String); } -PyTypeObject DBusPyObjectPath_Type = { - PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type)) - 0, - "dbus.ObjectPath", - 0, - 0, - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - ObjectPath_tp_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - DEFERRED_ADDRESS(&DBusPyStrBase_Type), /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - ObjectPath_tp_new, /* tp_new */ -}; - -/* Unicode string representation ==================================== */ - -PyDoc_STRVAR(String_tp_doc, -"A string represented using Unicode - a subtype of `unicode`.\n" -"\n" -"All strings on D-Bus are required to be valid Unicode; in the \"wire\n" -"protocol\" they're transported as UTF-8.\n" -"\n" -"By default, when strings are converted from D-Bus to Python, they\n" -"come out as this class. If you prefer to get UTF-8 strings (as instances\n" -"of a subtype of `str`) or you want to avoid the conversion overhead of\n" -"going from UTF-8 to Python's internal Unicode representation, see the\n" -"documentation for `dbus.UTF8String`.\n" -"\n" -"Constructor::\n" -"\n" -" String(value: str or unicode[, variant_level: int]) -> String\n" -"\n" -"variant_level must be non-negative; the default is 0.\n" -"\n" -":IVariables:\n" -" `variant_level` : int\n" -" Indicates how many nested Variant containers this object\n" -" is contained in: if a message's wire format has a variant containing a\n" -" variant containing a string, this is represented in Python by a\n" -" String or UTF8String with variant_level==2.\n" -); - -static PyMemberDef String_tp_members[] = { - {"variant_level", T_LONG, offsetof(DBusPyString, variant_level), - READONLY, - "The number of nested variants wrapping the real data. " - "0 if not in a variant"}, - {NULL}, -}; - -static PyObject * -String_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs) +PyObject * +DBusPyString_New(const char *utf8, long variant_level) { - PyObject *self; - long variantness = 0; - static char *argnames[] = {"variant_level", NULL}; + PyObject *args = NULL; + PyObject *kwargs = NULL; + PyObject *ret = NULL; - if (PyTuple_Size(args) > 1) { - PyErr_SetString(PyExc_TypeError, - "__new__ takes at most one positional parameter"); - return NULL; - } - if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs, - "|l:__new__", argnames, - &variantness)) return NULL; - if (variantness < 0) { - PyErr_SetString(PyExc_ValueError, - "variant_level must be non-negative"); + if (!String && !do_import()) return NULL; + + if (variant_level != 0) { + kwargs = DBusPy_BuildConstructorKeywordArgs(variant_level, NULL); + if (!kwargs) + goto finally; } - self = (PyUnicode_Type.tp_new)(cls, args, NULL); - if (self) { - ((DBusPyString *)self)->variant_level = variantness; - } - return self; + + args = Py_BuildValue("(s)", utf8); + if (!args) + goto finally; + + ret = PyObject_Call(String, args, kwargs); + +finally: + Py_XDECREF(args); + Py_XDECREF(kwargs); + return ret; +} + +int +DBusPyObjectPath_Check(PyObject *o) +{ + if (!ObjectPath && !do_import()) + return 0; + return PyObject_TypeCheck(o, (PyTypeObject *)ObjectPath); } -static PyObject * -String_tp_repr(PyObject *self) +PyObject * +DBusPyObjectPath_New(const char *utf8, long variant_level) { - PyObject *parent_repr = (PyUnicode_Type.tp_repr)(self); - PyObject *my_repr; + PyObject *args = NULL; + PyObject *kwargs = NULL; + PyObject *ret = NULL; - if (!parent_repr) { + if (!ObjectPath && !do_import()) return NULL; + + if (variant_level != 0) { + kwargs = DBusPy_BuildConstructorKeywordArgs(variant_level, NULL); + if (!kwargs) + goto finally; } - if (((DBusPyString *)self)->variant_level > 0) { - my_repr = PyString_FromFormat("%s(%s, variant_level=%ld)", - self->ob_type->tp_name, - PyString_AS_STRING(parent_repr), - ((DBusPyString *)self)->variant_level); - } - else { - my_repr = PyString_FromFormat("%s(%s)", self->ob_type->tp_name, - PyString_AS_STRING(parent_repr)); - } - /* whether my_repr is NULL or not: */ - Py_DECREF(parent_repr); - return my_repr; -} -PyTypeObject DBusPyString_Type = { - PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type)) - 0, - "dbus.String", - sizeof(DBusPyString), - 0, - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - String_tp_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - dbus_py_immutable_setattro, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - String_tp_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - String_tp_members, /* tp_members */ - 0, /* tp_getset */ - DEFERRED_ADDRESS(&PyUnicode_Type), /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - String_tp_new, /* tp_new */ -}; + args = Py_BuildValue("(s)", utf8); + if (!args) + goto finally; -dbus_bool_t -dbus_py_init_string_types(void) + ret = PyObject_Call(ObjectPath, args, kwargs); + +finally: + Py_XDECREF(args); + Py_XDECREF(kwargs); + return ret; +} + +int +DBusPyUTF8String_Check(PyObject *o) { - /* don't need to do strange contortions for unicode, since it's not a - * "variable-size" object (it has a pointer to its data instead) - */ - if (PyUnicode_Type.tp_itemsize != 0) { - fprintf(stderr, "dbus-python is not compatible with this version of " - "Python (unicode objects are assumed to be fixed-size)"); + if (!UTF8String && !do_import()) return 0; + return PyObject_TypeCheck(o, (PyTypeObject *)UTF8String); +} + +PyObject * +DBusPyUTF8String_New(const char *utf8, long variant_level) +{ + PyObject *args = NULL; + PyObject *kwargs = NULL; + PyObject *ret = NULL; + + if (!UTF8String && !do_import()) + return NULL; + + if (variant_level != 0) { + kwargs = DBusPy_BuildConstructorKeywordArgs(variant_level, NULL); + if (!kwargs) + goto finally; } - DBusPyString_Type.tp_base = &PyUnicode_Type; - if (PyType_Ready(&DBusPyString_Type) < 0) return 0; - DBusPyString_Type.tp_print = NULL; - DBusPyUTF8String_Type.tp_base = &DBusPyStrBase_Type; - if (PyType_Ready(&DBusPyUTF8String_Type) < 0) return 0; - DBusPyUTF8String_Type.tp_print = NULL; + args = Py_BuildValue("(s)", utf8); + if (!args) + goto finally; - DBusPyObjectPath_Type.tp_base = &DBusPyStrBase_Type; - if (PyType_Ready(&DBusPyObjectPath_Type) < 0) return 0; - DBusPyObjectPath_Type.tp_print = NULL; + ret = PyObject_Call(UTF8String, args, kwargs); - DBusPyBoolean_Type.tp_base = &DBusPyIntBase_Type; - if (PyType_Ready(&DBusPyBoolean_Type) < 0) return 0; - DBusPyBoolean_Type.tp_print = NULL; +finally: + Py_XDECREF(args); + Py_XDECREF(kwargs); + return ret; +} +dbus_bool_t +dbus_py_init_string_types(void) +{ return 1; } dbus_bool_t -dbus_py_insert_string_types(PyObject *this_module) +dbus_py_insert_string_types(PyObject *this_module UNUSED) { - Py_INCREF(&DBusPyObjectPath_Type); - Py_INCREF(&DBusPyUTF8String_Type); - Py_INCREF(&DBusPyString_Type); - if (PyModule_AddObject(this_module, "ObjectPath", - (PyObject *)&DBusPyObjectPath_Type) < 0) return 0; - if (PyModule_AddObject(this_module, "UTF8String", - (PyObject *)&DBusPyUTF8String_Type) < 0) return 0; - if (PyModule_AddObject(this_module, "String", - (PyObject *)&DBusPyString_Type) < 0) return 0; - return 1; } diff --git a/_dbus_bindings/types-internal.h b/_dbus_bindings/types-internal.h index a5c8147..67f84c2 100644 --- a/_dbus_bindings/types-internal.h +++ b/_dbus_bindings/types-internal.h @@ -31,30 +31,6 @@ #ifndef DBUS_BINDINGS_TYPES_INTERNAL_H #define DBUS_BINDINGS_TYPES_INTERNAL_H -extern PyTypeObject DBusPyIntBase_Type; -DEFINE_CHECK(DBusPyIntBase) - -typedef struct { - PyIntObject base; - long variant_level; -} DBusPyIntBase; - -extern PyTypeObject DBusPyLongBase_Type; -DEFINE_CHECK(DBusPyLongBase) - -extern PyTypeObject DBusPyFloatBase_Type; -DEFINE_CHECK(DBusPyFloatBase) - -typedef struct { - PyFloatObject base; - long variant_level; -} DBusPyFloatBase; - -typedef struct { - PyUnicodeObject unicode; - long variant_level; -} DBusPyString; - extern PyTypeObject DBusPyStrBase_Type; DEFINE_CHECK(DBusPyStrBase) @@ -75,18 +51,6 @@ extern PyObject *dbus_py_variant_level_const; extern PyObject *dbus_py_signature_const; extern PyObject *dbus_py__dbus_object_path__const; -typedef struct { - PyListObject super; - PyObject *signature; - long variant_level; -} DBusPyArray; - -typedef struct { - PyDictObject super; - PyObject *signature; - long variant_level; -} DBusPyDict; - PyObject *dbus_py_variant_level_getattro(PyObject *obj, PyObject *name); dbus_bool_t dbus_py_variant_level_set(PyObject *obj, long variant_level); void dbus_py_variant_level_clear(PyObject *obj); diff --git a/configure.ac b/configure.ac index dd7c32c..79e21e2 100644 --- a/configure.ac +++ b/configure.ac @@ -9,7 +9,7 @@ m4_define(dbus_python_minor_version, 82) m4_define(dbus_python_micro_version, 3) m4_define(dbus_python_maybe_datestamp, - m4_esyscmd([if test x]dbus_python_released[ != x1; then date +.%Y%m%d | tr -d '\n\r'; fi])) + m4_esyscmd([if test x]dbus_python_released[ != x1; then date +.purity%Y%m%d | tr -d '\n\r'; fi])) m4_define(dbus_python_version, dbus_python_major_version.dbus_python_minor_version.dbus_python_micro_version[]dbus_python_maybe_datestamp) diff --git a/dbus/__init__.py b/dbus/__init__.py index e990ec3..c8c38d9 100644 --- a/dbus/__init__.py +++ b/dbus/__init__.py @@ -76,7 +76,7 @@ except ImportError: # OLPC Sugar compatibility import dbus.exceptions as exceptions -import dbus.types as types +import dbus.data as types from _dbus_bindings import get_default_main_loop, set_default_main_loop,\ validate_interface_name, validate_member_name,\ @@ -93,10 +93,10 @@ from dbus.exceptions import MissingErrorHandlerException, \ UnknownMethodException, \ NameExistsException, \ DBusException -from _dbus_bindings import ObjectPath, ByteArray, Signature, Byte, Boolean,\ - Int16, UInt16, Int32, UInt32, Int64, UInt64,\ - Double, String, Array, Struct, Dictionary, \ - UTF8String +from dbus.data import ObjectPath, ByteArray, Signature, Byte, Boolean,\ + Int16, UInt16, Int32, UInt32, Int64, UInt64,\ + Double, String, Array, Struct, Dictionary, \ + UTF8String from dbus._dbus import Bus, SystemBus, SessionBus, StarterBus from dbus.proxies import Interface diff --git a/dbus/_dbus.py b/dbus/_dbus.py index 18747c0..2b1c20f 100644 --- a/dbus/_dbus.py +++ b/dbus/_dbus.py @@ -37,13 +37,14 @@ from traceback import print_exc from dbus.exceptions import DBusException from _dbus_bindings import BUS_DAEMON_NAME, BUS_DAEMON_PATH,\ - BUS_DAEMON_IFACE, UTF8String,\ + BUS_DAEMON_IFACE,\ validate_member_name, validate_interface_name,\ validate_bus_name, validate_object_path,\ BUS_SESSION, BUS_SYSTEM, BUS_STARTER,\ DBUS_START_REPLY_SUCCESS, \ DBUS_START_REPLY_ALREADY_RUNNING from dbus.bus import BusConnection +from dbus.data import UTF8String from dbus.lowlevel import SignalMessage try: diff --git a/dbus/connection.py b/dbus/connection.py index 3a551ea..ca61c5a 100644 --- a/dbus/connection.py +++ b/dbus/connection.py @@ -31,20 +31,27 @@ except ImportError: import weakref from _dbus_bindings import Connection as _Connection, \ - LOCAL_PATH, LOCAL_IFACE, \ + LOCAL_PATH, LOCAL_IFACE, PEER_IFACE, \ validate_interface_name, validate_member_name,\ validate_bus_name, validate_object_path,\ - validate_error_name, \ - UTF8String + validate_error_name +from _dbus_bindings import DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ + as _INTROSPECT_DOCTYPE +from dbus.data import UTF8String, ObjectPath from dbus.exceptions import DBusException from dbus.lowlevel import ErrorMessage, MethodCallMessage, SignalMessage, \ - MethodReturnMessage, HANDLER_RESULT_NOT_YET_HANDLED + MethodReturnMessage, \ + HANDLER_RESULT_NOT_YET_HANDLED, \ + HANDLER_RESULT_HANDLED from dbus.proxies import ProxyObject _logger = logging.getLogger('dbus.connection') +_ROOT = ObjectPath('/') + + def _noop(*args, **kwargs): pass @@ -253,7 +260,23 @@ class Connection(_Connection): self._signals_lock = thread.allocate_lock() """Lock used to protect signal data structures""" - self.add_message_filter(self.__class__._signal_func) + self._object_tree_lock = thread.allocate_lock() + """Lock used to protect _object_paths and _object_tree""" + + self._object_paths = {} + """Dict mapping object path to one of: + + - a tuple (on_message, on_unregister, fallback) + - a tuple (None, None, False), meaning this is a "synthetic" + object created as a parent or ancestor for a real object + """ + + self._object_children = {} + """Dict mapping object paths to sets of children""" + + self._filters = [] + + super(Connection, self).add_message_filter(self.__class__._filter) def activate_name_owner(self, bus_name): """Return the unique name for the given bus name, activating it @@ -493,23 +516,6 @@ class Connection(_Connection): # Now called without the signals lock held (it was held in <= 0.81.0) pass - def _signal_func(self, message): - """D-Bus filter function. Handle signals by dispatching to Python - callbacks kept in the match-rule tree. - """ - - if not isinstance(message, SignalMessage): - return HANDLER_RESULT_NOT_YET_HANDLED - - dbus_interface = message.get_interface() - path = message.get_path() - signal_name = message.get_member() - - for match in self._iter_easy_matches(path, dbus_interface, - signal_name): - match.maybe_handle_message(message) - return HANDLER_RESULT_NOT_YET_HANDLED - def call_async(self, bus_name, object_path, dbus_interface, method, signature, args, reply_handler, error_handler, timeout=-1.0, utf8_strings=False, byte_arrays=False, @@ -612,3 +618,250 @@ class Connection(_Connection): return args_list[0] else: return tuple(args_list) + + # Export functionality + + def _register_object_path(self, path, on_message, on_unregister=None, + fallback=False): + """Register a callback to be called when messages arrive at the given + object-path. Used to export objects' methods on the bus in a low-level + way. Use `dbus.service.Object` instead. + + :Parameters: + `path` : dbus.ObjectPath or other str + Object path to be acted on + `on_message` : callable + Called when a message arrives at the given object-path, with + two positional parameters: the first is this Connection, + the second is the incoming `dbus.lowlevel.Message`. + `on_unregister` : callable or None + If not None, called when the callback is unregistered, with + two positional parameters: the first is this Connection, + the second is the path at which the object is no longer + registered. + `fallback` : bool + If True (the default is False), when a message arrives for a + 'subdirectory' of the given path and there is no more specific + handler, use this handler. Normally this handler is only run if + the paths match exactly. + """ + self._require_main_loop() + path = ObjectPath(path) + parent, tail = path.rsplit('/', 1) + if on_message is None: + raise TypeError('None may not be registered as an object-path ' + 'handler') + + self._object_tree_lock.acquire() + paths = self._object_paths + children = self._object_children + try: + if path in paths: + old_on_message, unused, unused = paths[path] + if old_on_message: + raise KeyError("Can't register the object-path handler " + "for %r: there is already a handler" % path) + + while tail: + parent = ObjectPath(parent or _ROOT) + # make sure there's at least a synthetic parent + paths.setdefault(parent, (None, None, False)) + # give the parent an appropriate child + children.setdefault(parent, set()).add(tail) + # walk upwards + parent, tail = parent.rsplit('/', 1) + + paths[path] = (on_message, on_unregister, fallback) + finally: + self._object_tree_lock.release() + + def _unregister_object_path(self, path): + """Remove a previously registered handler for the given object path. + + :Parameters: + `path` : dbus.ObjectPath or other str + The object path whose handler is to be removed + :Raises KeyError: if there is no handler registered for exactly that + object path. + """ + path = ObjectPath(path) + parent, tail = path.rsplit('/', 1) + + self._object_tree_lock.acquire() + paths = self._object_paths + children = self._object_children + try: + unused, on_unregister, unused = paths.pop(path) + + while tail: + parent = ObjectPath(parent or _ROOT) + kids = children.get(parent) + if kids is not None: + kids.discard(tail) + if kids: + # parent still has other children, don't delete it + break + else: + del children[parent] + parent_on_message, unused, unused = paths[parent] + if parent_on_message is not None: + # parent is a real object, don't delete it + break + del paths[parent] + # walk upwards + parent, tail = parent.rsplit('/', 1) + finally: + self._object_tree_lock.release() + + if on_unregister is not None: + on_unregister(self, path) + + def list_exported_child_objects(self, path): + """Return a list of the names of objects exported on this Connection + as direct children of the given object path. + + Each name ``n`` returned may be converted to a valid object path using + ``dbus.ObjectPath('%s%s%s' % (path, (path != '/' and '/' or ''), n))``. + For the purposes of this function, every parent or ancestor of an + exported object is considered to be an exported object, even if it's + only an object synthesized by the library to support introspection. + """ + return list(self._object_children.get(path, ())) + + def _handle_method_call(self, msg): + path = msg.get_path() + on_message = None + absent = True + self._object_tree_lock.acquire() + try: + try: + on_message, on_unregister, fallback = self._object_paths[path] + except KeyError: + parent, tail = path.rsplit('/', 1) + while parent: + on_message, on_unregister, fallback \ + = self._object_paths.get(parent, (None, None, False)) + if fallback: + print "Found fallback handler at %s", parent + absent = False + break + parent, tail = parent.rsplit('/', 1) + else: + print "Found handler at %s", path + absent = False + finally: + self._object_tree_lock.release() + + if absent: + # There's nothing there, and it's not an ancestor of any object + # FIXME: Raise UnknownObject once it's specified + reply = ErrorMessage(msg, + 'org.freedesktop.DBus.Error.UnknownMethod', + 'There is no object at %s' % path) + self.send_message(reply) + elif on_message is None: + # It's a synthetic object that's an ancestor of a real object. + # It supports Introspect and nothing else + reflection_data = _INTROSPECT_DOCTYPE + reflection_data += '<node name="%s">\n' % path + for kid in self._object_children.get(path, ()): + reflection_data += ' <node name="%s"/>\n' % kid + reflection_data += '</node>\n' + reply = MethodReturnMessage(msg) + reply.append(reflection_data, signature='s') + self.send_message(reply) + else: + # It's a real object and can return whatever it likes + try: + on_message(self, msg) + except: + logging.basicConfig() + _logger.error('Error in message handler:', + exc_info=1) + + def _filter(self, message): + try: + self.__filter(message) + except: + logging.basicConfig() + _logger.error('Internal error while filtering message:', + exc_info=1) + + def __filter(self, message): + # Step 1. Pass any method replies to DBusPendingCall or + # send_with_reply_and_block if they're for us. + # - libdbus still does this for us + + # Step 1 1/2. Process the standardized org.freedesktop.DBus.Peer + # interface. libdbus does this before any filters, so so will we. + # FIXME: while we're using libdbus, this code won't ever run + + if (isinstance(message, MethodCallMessage) and + message.get_interface() == PEER_IFACE): + member = message.get_member() + if member == 'Ping': + # send an empty reply + reply = MethodReturnMessage(message) + elif member == 'GetMachineID': + reply = ErrorMessage(message, + 'org.freedesktop.DBus.Error.UnknownMethod', + 'dbus-python does not yet implement Peer.GetMachineID') + else: + reply = ErrorMessage(message, + 'org.freedesktop.DBus.Error.UnknownMethod', + 'Unrecognised Peer method %s' % member) + self.send_message(reply) + return HANDLER_RESULT_HANDLED + + + # Step 2a. Check for signals - this filter always ran first + # in older dbus-pythons, so it runs first here + + if isinstance(message, SignalMessage): + dbus_interface = message.get_interface() + path = message.get_path() + signal_name = message.get_member() + + for match in self._iter_easy_matches(path, dbus_interface, + signal_name): + try: + match.maybe_handle_message(message) + except: + logging.basicConfig() + _logger.error('Internal error handling D-Bus signal:', + exc_info=1) + + # Step 2b. Run user-defined filters + for filter in self._filters: + try: + ret = filter(self, message) + except: + logging.basicConfig() + _logger.error('User-defined message filter raised exception:', + exc_info=1) + ret = NotImplemented + if ret is NotImplemented or ret == HANDLER_RESULT_NOT_YET_HANDLED: + continue + elif ret is None or ret == HANDLER_RESULT_HANDLED: + break + elif isinstance(ret, (int, long)): + _logger.error('Return from message filter should be None, ' + 'NotImplemented, ' + 'dbus.lowlevel.HANDLER_RESULT_HANDLED or ' + 'dbus.lowlevel.HANDLER_RESULT_NOT_YET_HANDLED, ' + 'not %r', ret) + + # Step 3. Pass method calls to registered objects at that path + if isinstance(message, MethodCallMessage): + try: + self._handle_method_call(message) + except: + logging.basicConfig() + _logger.error('Internal error handling method call:', + exc_info=1) + + # We should be the only ones doing anything with messages now, so... + return HANDLER_RESULT_HANDLED + + def add_message_filter(self): + self._filters.append(filter) diff --git a/dbus/data.py b/dbus/data.py new file mode 100644 index 0000000..08cdf60 --- /dev/null +++ b/dbus/data.py @@ -0,0 +1,564 @@ +"""D-Bus data types. + +The module isn't called "types" due to the name clash with the top-level +types module, which is problematic in Scratchbox. +""" + +# Copyright (C) 2007 Collabora Ltd. <http://www.collabora.co.uk/> +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, copy, +# modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +Copyright holders and licensing are indicated in the source files. +__all__ = ('ObjectPath', 'ByteArray', 'Signature', 'Byte', 'Boolean', + 'Int16', 'UInt16', 'Int32', 'UInt32', 'Int64', 'UInt64', + 'Double', 'String', 'Array', 'Struct', 'Dictionary', + 'UTF8String') + +from sys import maxint + +from _dbus_bindings import validate_object_path, validate_signature, \ + get_signature_iter + + +class _DBusTypeMixin(object): + # Base class for D-Bus data types. Must be mixed-in with a class that + # allows a _dbus_variant_level attribute. + # + # Do not use this class, or assume that it exists, outside dbus-python. + + # Slightly odd implementation which deserves a comment: + # + # Some of the types we want to subtype have a layout which + # means we can't use __slots__ and must give them a __dict__. Others + # are fine for __slots__. So, we have to make the decision per-subclass. + # + # Omitting __slots__ here would give all subtypes a __dict__, which would + # be a waste of memory for the ones that don't need it (all mutable types, + # plus unicode). So we give it no slots, and add either a slot or a + # __dict__ (as appropriate) in the subclasses. + + __slots__ = () + + def __new__(cls, value, variant_level=0): + if variant_level < 0: + raise ValueError('variant_level must be non-negative') + self = super(_DBusTypeMixin, cls).__new__(cls, value) + self._dbus_variant_level = variant_level + return self + + @property + def variant_level(self): + """Indicates how many nested Variant containers this object is + contained in: if a message's wire format has a variant containing + a variant containing an `Int32`, this is represented in Python by an + `Int32` object with ``variant_level == 2``. + """ + return self._dbus_variant_level + + def __repr__(self): + variant_level = self._dbus_variant_level + parent_repr = super(_DBusTypeMixin, self).__repr__() + if variant_level: + return '%s(%s, variant_level=%d)' % (self.__class__.__name__, + parent_repr, variant_level) + else: + return '%s(%s)' % (self.__class__.__name__, parent_repr) + + +class ByteArray(_DBusTypeMixin, str): + """ByteArray is a subtype of str which can be used when you want an + efficient immutable representation of a D-Bus byte array (signature 'ay'). + + By default, when byte arrays are converted from D-Bus to Python, they + come out as a `dbus.Array` of `dbus.Byte`. This is just for symmetry with + the other D-Bus types - in practice, what you usually want is the byte + array represented as a string, using this class. To get this, pass the + ``byte_arrays=True`` keyword argument to any of these methods: + + * any D-Bus method proxy, or ``connect_to_signal``, on the objects returned + by `Bus.get_object` + * any D-Bus method on a `dbus.Interface` + * `dbus.Interface.connect_to_signal` + * `Bus.add_signal_receiver` + + Import via:: + + from dbus import ByteArray + + Constructor:: + + ByteArray(value: str) + """ + + +class Byte(_DBusTypeMixin, int): + """An unsigned byte: a subtype of int, with range restricted to [0, 255]. + + A Byte b may be converted to a str of length 1 via str(b) == chr(b). + + Most of the time you don't want to use this class - it mainly exists + for symmetry with the other D-Bus types. See `dbus.ByteArray` for a + better way to handle arrays of Byte. + + Constructor:: + + dbus.Byte(value: integer or str of length 1[, variant_level: integer]) + """ + + def __new__(cls, value=0, variant_level=0): + if isinstance(value, str): + if len(value) != 1: + raise TypeError('A string argument to Byte.__new__() must ' + 'be a single byte, not %r' % value) + value = ord(value) + elif not isinstance(value, (int, long)): + raise TypeError('Argument to Byte.__new__() must be a str, int ' + 'or long, not %r' % value) + + if value < 0 or value > 255: + raise TypeError('Argument %r to Byte.__new__() not in range(256)' + % value) + + return super(Byte, cls).__new__(cls, value, variant_level) + + def __str__(self): + return chr(self) + + +class String(_DBusTypeMixin, unicode): + """A human-readable string: a subtype of `unicode`, with U+0000 disallowed. + + All strings on D-Bus are required to be valid Unicode; in the "wire + protocol" they're transported as UTF-8. + + By default, when strings are converted from D-Bus to Python, they come + out as this class. If you prefer to get UTF-8 strings (as instances of + a subtype of `str`) or you want to avoid the conversion overhead of + going from UTF-8 to Python's internal Unicode representation, see the + documentation for `dbus.UTF8String`. + """ + __slots__ = ('_dbus_variant_level',) + + def __new__(cls, value=u'', variant_level=0): + + if isinstance(value, str): + try: + value = value.decode('utf8') + except UnicodeError, e: + raise UnicodeError('A str argument to String.__new__ must be ' + 'UTF-8: %s', e) + elif not isinstance(value, unicode): + raise TypeError('String.__new__ requires a unicode or UTF-8 str, ' + 'not %r' % value) + + if u'\0' in value: + raise TypeError(r'D-Bus strings cannot contain u"\0", but %r does' + % value) + + return super(String, cls).__new__(cls, value, variant_level) + + +class UTF8String(_DBusTypeMixin, str): + r"""A human-readable string represented as UTF-8; a subtype of `str`, + with '\0' disallowed. + + By default, when byte arrays are converted from D-Bus to Python, they + come out as a `dbus.String`, which is a subtype of `unicode`. + If you prefer to get UTF-8 strings (as instances of this class) or you + want to avoid the conversion overhead of going from UTF-8 to Python's + internal Unicode representation, you can pass the ``utf8_strings=True`` + keyword argument to any of these methods: + + * any D-Bus method proxy, or ``connect_to_signal``, on the objects returned + by `Bus.get_object` + * any D-Bus method on a `dbus.Interface` + * `dbus.Interface.connect_to_signal` + * `Bus.add_signal_receiver` + + :Since: 0.80 (in older versions, use dbus.String) + """ + + def __new__(cls, value='', variant_level=0): + + if isinstance(value, str): + try: + # evaluating for its side-effect of performing validation + value.decode('utf8') + except UnicodeError, e: + raise UnicodeError('A str argument to UTF8String.__new__ must ' + 'be UTF-8: %s', e) + elif isinstance(value, unicode): + value = value.encode('utf8') + else: + raise TypeError('UTF8String.__new__ requires a unicode or UTF-8 ' + 'str, not %r' % value) + + if '\0' in value: + raise TypeError(r'D-Bus strings cannot contain "\0", but %r does' + % value) + + return super(UTF8String, cls).__new__(cls, value, variant_level) + + +class ObjectPath(_DBusTypeMixin, str): + """A D-Bus object path, such as '/com/example/MyApp/Documents/abc'. + + ObjectPath is a subtype of str, and object-paths behave like strings. + """ + + def __new__(cls, value, variant_level=0): + if isinstance(value, unicode): + value = value.encode('ascii') + elif not isinstance(value, str): + raise TypeError('ObjectPath.__new__ requires a unicode or ' + 'str instance, not %r' % value) + + validate_object_path(value) + + return super(ObjectPath, cls).__new__(cls, value, variant_level) + + +class Boolean(_DBusTypeMixin, int): + """A boolean, represented as a subtype of `int` (not `bool`, because + `bool` cannot be subclassed). + """ + + __slots__ = ('_dbus_variant_level',) + + def __new__(cls, value=False, variant_level=0): + return super(Boolean, cls).__new__(cls, bool(value), variant_level) + + def __repr__(self): + variant_level = self._dbus_variant_level + bool_repr = self and 'True' or 'False' + if variant_level: + return '%s(%s, variant_level=%d)' % (self.__class__.__name__, + bool_repr, variant_level) + else: + return '%s(%s)' % (self.__class__.__name__, bool_repr) + + +if maxint >= 0x7FFFFFFFFFFFFFFFL: + _I64 = int + if maxint >= 0xFFFFFFFFFFFFFFFFL: + _U64 = int + else: + _U64 = long +else: + _I64 = long + _U64 = long + +class Int16(_DBusTypeMixin, int): + """A signed 16-bit integer between -0x8000 and +0x7FFF, represented as a + subtype of `int`. + """ + + __slots__ = ('_dbus_variant_level',) + + def __new__(cls, value=0, variant_level=0): + self = super(Int16, cls).__new__(cls, value, variant_level) + if self < -0x8000 or self > 0x7FFF: + raise OverflowError('Value %r out of range for Int16' + % value) + return self + +class UInt16(_DBusTypeMixin, int): + """An unsigned 16-bit integer between 0 and +0xFFFF, represented as a + subtype of `int`. + """ + + __slots__ = ('_dbus_variant_level',) + + def __new__(cls, value=0, variant_level=0): + self = super(UInt16, cls).__new__(cls, value, variant_level) + if self < 0 or self > 0xFFFF: + raise OverflowError('Value %r out of range for UInt16' + % value) + return self + +class Int32(_DBusTypeMixin, int): + """A signed 32-bit integer between -0x8000 0000 and +0x7FFF FFFF, + represented as a subtype of `int`. + """ + + __slots__ = ('_dbus_variant_level',) + + def __new__(cls, value=0, variant_level=0): + self = super(Int32, cls).__new__(cls, value, variant_level) + if self < -0x80000000 or self > 0x7FFFFFFF: + raise OverflowError('Value %r out of range for Int32' + % value) + return self + +class UInt32(_DBusTypeMixin, _I64): + """An unsigned 32-bit integer between 0 and +0xFFFF FFFF, represented as a + subtype of either `int` or `long` (platform-dependent and subject to + change). + """ + + if _I64 is int: + __slots__ = ('_dbus_variant_level',) + + def __new__(cls, value=0, variant_level=0): + self = super(UInt32, cls).__new__(cls, value, variant_level) + if self < 0 or self > 0xFFFFFFFFL: + raise OverflowError('Value %r out of range for UInt32' + % value) + return self + +class Int64(_DBusTypeMixin, _I64): + """A signed 64-bit integer between -0x8000 0000 0000 0000 and + +0x7FFF FFFF FFFF FFFF, + represented as a subtype of `int`. + """ + + if _I64 is int: + __slots__ = ('_dbus_variant_level',) + + def __new__(cls, value=0, variant_level=0): + self = super(Int64, cls).__new__(cls, value, variant_level) + if self < -0x8000000000000000L or self > 0x7FFFFFFFFFFFFFFFL: + raise OverflowError('Value %r out of range for Int64' + % value) + return self + +class UInt64(_DBusTypeMixin, _U64): + """An unsigned 64-bit integer between 0 and +0xFFFF FFFF FFFF FFFF, + represented as a subtype of either `int` or `long` (platform-dependent and + subject to change). + """ + + if _U64 is int: + __slots__ = ('_dbus_variant_level',) + + def __new__(cls, value=0, variant_level=0): + self = super(UInt64, cls).__new__(cls, value, variant_level) + if self < 0 or self > 0xFFFFFFFFFFFFFFFFL: + raise OverflowError('Value %r out of range for UInt64' + % value) + return self + +class Double(_DBusTypeMixin, float): + """A double-precision floating-point number, represented as a subtype + of `float`.""" + + __slots__ = ('_dbus_variant_level',) + + def __new__(cls, value=0.0, variant_level=0): + return super(Double, cls).__new__(cls, value, variant_level) + +class Array(_DBusTypeMixin, list): + """An array of items of the same type, implemented as a subtype of + list. + + As currently implemented, an Array behaves just like a list, but with + the addition of a ``signature`` property set by the constructor; + conversion of its items to D-Bus types is only done when it's sent + in a Message. This might change in future so validation is done earlier. + """ + + __slots__ = ('_dbus_variant_level', '_signature') + + @property + def signature(self): + """The D-Bus signature of each element of this Array (a Signature + instance), or None if unspecified. Read-only. + + The signature of an Array ``arr`` is given by ``'a' + arr.signature``. + + If None, when the Array is sent over D-Bus, the signature will be + guessed from the first element. Try to avoid this if possible. + """ + return self._signature + + def __new__(cls, iterable=(), signature=None, variant_level=0): + """""" + + if signature is not None: + signature = Signature(signature) + + if len(tuple(signature)) != 1: + raise ValueError("There must be exactly one complete type " + "in an Array's signature parameter") + + self = super(Array, cls).__new__(cls, iterable, + variant_level=variant_level) + self._signature = signature + return self + + def __init__(self, iterable=(), signature=None, variant_level=0): + super(Array, self).__init__(iterable) + +def TypedArray(inner_signature): + inner_signature = Signature(inner_signature) + + class Subclass(Array): + signature = inner_signature + + def __new__(self, iterable=(), variant_level=0): + return super(Subclass, cls).__new__(cls, iterable, + signature=inner_signature, + variant_level=variant_level) + + def __init__(self, iterable=(), variant_level=0): + return super(Subclass, cls).__new__(cls, iterable, + signature=inner_signature, + variant_level=variant_level) + + Subclass.__name__ = "TypedArray('%s')" % inner_signature + return Subclass + + +class Dictionary(_DBusTypeMixin, dict): + """A mapping from keys of consistent types to values of consistent types, + implemented as a subtype of dict. + + As currently implemented, a Dictionary behaves just like a dict, but with + the addition of a ``signature`` property set by the constructor; + conversion of its items to D-Bus types is only done when it's sent + in a Message. This might change in future so validation is done earlier. + """ + + __slots__ = ('_dbus_variant_level', '_signature') + + @property + def signature(self): + """The D-Bus signature of each pair in this Dictionary (a Signature + instance), or None if unspecified. Read-only. + + The signature of a Dictionary ``d`` is given by + ``'a{' + d.signature + '}'``. + + If None, when the Dictionary is sent over D-Bus, the signature will be + guessed from an arbitrarily chosen element. Try to avoid this if + possible. + """ + return self._signature + + def __new__(cls, mapping_or_iterable=(), signature=None, variant_level=0): + """""" + + if signature is not None: + signature = Signature(signature) + + if len(tuple(signature)) != 2: + raise ValueError("There must be exactly two complete types " + "in a Dictionary's signature parameter") + + # FIXME: there should be a better way to do this + if signature[0] not in 'ybnhiutxdsog': + raise ValueError("The key type in a Dictionary's signature " + "must be a primitive type") + + self = super(Dictionary, cls).__new__(cls, mapping_or_iterable, + variant_level=variant_level) + self._signature = signature + return self + + def __init__(self, mapping_or_iterable=(), signature=None, + variant_level=0): + super(Dictionary, self).__init__(mapping_or_iterable) + +def TypedDictionary(inner_signature): + inner_signature = Signature(inner_signature) + + class Subclass(Dictionary): + signature = inner_signature + + def __new__(self, iterable=(), variant_level=0): + return super(Subclass, cls).__new__(cls, iterable, + signature=inner_signature, + variant_level=variant_level) + + def __init__(self, iterable=(), variant_level=0): + return super(Subclass, cls).__new__(cls, iterable, + signature=inner_signature, + variant_level=variant_level) + + Subclass.__name__ = "TypedDictionary('%s')" % inner_signature + return Subclass + + +class Struct(_DBusTypeMixin, tuple): + """A structure containing items of fixed, possibly different types. + + D-Bus structs may not be empty, so the iterable argument is required and + may not be an empty iterable. + """ + + @property + def signature(self): + """The D-Bus signature of each pair in this Dictionary (a Signature + instance), or None if unspecified. Read-only. + + The signature of a Struct ``s`` is given by + ``'(' + s.signature + ')'``. + + If None, when the Struct is sent over D-Bus, the signature will be + guessed from the elements. + """ + return self._signature + + def __new__(cls, iterable, signature=None, variant_level=0): + """""" + + if signature is not None: + signature = Signature(signature) + + if len(tuple(signature)) < 1: + raise ValueError("D-Bus structs cannot be empty") + + self = super(Struct, cls).__new__(cls, iterable, + variant_level=variant_level) + self._signature = signature + return self + +def TypedStruct(inner_signature): + inner_signature = Signature(inner_signature) + + class Subclass(Struct): + signature = inner_signature + + def __new__(self, iterable=(), variant_level=0): + return super(Subclass, cls).__new__(cls, iterable, + signature=inner_signature, + variant_level=variant_level) + + def __init__(self, iterable=(), variant_level=0): + return super(Subclass, cls).__new__(cls, iterable, + signature=inner_signature, + variant_level=variant_level) + + Subclass.__name__ = "TypedStruct('%s')" % inner_signature + return Subclass + + +class Signature(_DBusTypeMixin, str): + """A string subclass whose values are restricted to valid D-Bus signatures. + When iterated over, instead of individual characters it produces + Signature instances representing single complete types.""" + + def __new__(cls, signature, variant_level=0): + validate_signature(signature) + return super(Signature, cls).__new__(cls, signature, variant_level) + + def __iter__(self): + return get_signature_iter(self) diff --git a/dbus/dbus_bindings.py b/dbus/dbus_bindings.py index a45ca9f..e996e7e 100644 --- a/dbus/dbus_bindings.py +++ b/dbus/dbus_bindings.py @@ -20,7 +20,7 @@ from dbus.exceptions import DBusException class ConnectionError(Exception): pass # Types -from dbus.types import * +from dbus.data import * # Messages from _dbus_bindings import Message, SignalMessage as Signal,\ diff --git a/dbus/decorators.py b/dbus/decorators.py index a5ca281..dce493a 100644 --- a/dbus/decorators.py +++ b/dbus/decorators.py @@ -30,9 +30,10 @@ __docformat__ = 'restructuredtext' import inspect -from dbus import validate_interface_name, Signature, validate_member_name -from dbus.lowlevel import SignalMessage +from dbus import validate_interface_name, validate_member_name +from dbus.data import Signature from dbus.exceptions import DBusException +from dbus.lowlevel import SignalMessage def method(dbus_interface, in_signature=None, out_signature=None, diff --git a/dbus/service.py b/dbus/service.py index df9412a..1d104b9 100644 --- a/dbus/service.py +++ b/dbus/service.py @@ -36,8 +36,9 @@ except ImportError: import dummy_thread as thread import _dbus_bindings -from dbus import SessionBus, Signature, Struct, validate_bus_name, \ - validate_object_path, INTROSPECTABLE_IFACE, ObjectPath +from dbus import SessionBus, validate_bus_name, validate_object_path, \ + INTROSPECTABLE_INTERFACE +from dbus.data import Struct, Signature, ObjectPath from dbus.decorators import method, signal from dbus.exceptions import DBusException, \ NameExistsException, \ @@ -630,10 +631,10 @@ class Object(Interface): finally: self._locations_lock.release() - def _unregister_cb(self, connection): + def _unregister_cb(self, connection, path): # there's not really enough information to do anything useful here - _logger.info('Unregistering exported object %r from some path ' - 'on %r', self, connection) + _logger.info('Unregistering exported object %r from %r ' + 'on %r', self, path, connection) def _message_cb(self, connection, message): try: diff --git a/dbus/types.py b/dbus/types.py index cc4a678..d094bd9 100644 --- a/dbus/types.py +++ b/dbus/types.py @@ -1,9 +1,18 @@ +"""dbus.types is deprecated due to a name clash with the types module in the +standard library, which causes problems in Scratchbox. + +For maximum compatibility, import these types from the top-level dbus package +instead. + +:Deprecated: since <unreleased 'purity' branch>.""" + __all__ = ('ObjectPath', 'ByteArray', 'Signature', 'Byte', 'Boolean', 'Int16', 'UInt16', 'Int32', 'UInt32', 'Int64', 'UInt64', 'Double', 'String', 'Array', 'Struct', 'Dictionary', 'UTF8String') -from _dbus_bindings import ObjectPath, ByteArray, Signature, Byte,\ - Int16, UInt16, Int32, UInt32,\ - Int64, UInt64, Dictionary, Array, \ - String, Boolean, Double, Struct, UTF8String +from warnings import warn as _warn + +from dbus.data import * + +_warn(__doc__, DeprecationWarning, stacklevel=2) diff --git a/test/cross-test-client.py b/test/cross-test-client.py index f192167..571098b 100644 --- a/test/cross-test-client.py +++ b/test/cross-test-client.py @@ -27,7 +27,6 @@ import logging import gobject from dbus import SessionBus, Interface, Array, Byte, Double, Boolean, ByteArray, Int16, Int32, Int64, UInt16, UInt32, UInt64, String, UTF8String, Struct, Dictionary -from dbus.service import BusName import dbus.glib from crosstest import CROSS_TEST_PATH, CROSS_TEST_BUS_NAME,\ @@ -379,13 +378,9 @@ class Client(SignalTestsImpl): if __name__ == '__main__': - # FIXME: should be possible to export objects without a bus name - if 0: - client = Client(dbus.SessionBus(), '/Client') - else: - # the Java cross test's interpretation is that the client should be - # at /Test too - client = Client(dbus.SessionBus(), '/Test') + # the Java cross test's interpretation is that the client should be + # at /Test too + client = Client(SessionBus(), '/Test') gobject.idle_add(client.run_client) loop = gobject.MainLoop() diff --git a/test/test-standalone.py b/test/test-standalone.py index 929fc37..27177a0 100755 --- a/test/test-standalone.py +++ b/test/test-standalone.py @@ -37,7 +37,7 @@ pydir = os.path.normpath(os.environ["DBUS_TOP_SRCDIR"]) import _dbus_bindings import dbus -import dbus.types as types +import dbus.data as types # Check that we're using the right versions if not dbus.__file__.startswith(pydir): |