[PATCH 01/17] Implement o.fd.DBus method wrappers in Python
instead of C.
John (J5) Palmieri
johnp at redhat.com
Mon Apr 30 14:31:59 PDT 2007
You realize that the wrapper functions are creating the D-Bus proxy and
getting introspect data every time you call? Perhaps we should cache
the data or simply tell it not to introspect and wrap all the inputs
with the correct types.
On Mon, 2007-04-30 at 11:20 +0100, Simon McVittie wrote:
> This reduces the need to have _dbus_bindings.BusImplementation and makes
> peer-to-peer connections easier to implement.
>
> diff --git a/_dbus_bindings/bus.c b/_dbus_bindings/bus.c
> index 2ae0383..761b67e 100644
> --- a/_dbus_bindings/bus.c
> +++ b/_dbus_bindings/bus.c
> @@ -131,246 +131,11 @@ Bus_get_unique_name(Connection *self, PyObject *args UNUSED)
> return PyString_FromString(name);
> }
>
> -PyDoc_STRVAR(Bus_get_unix_user__doc__,
> -"get_unix_user(bus_name) -> int\n"
> -"\n"
> -"Get the numeric uid of the process which owns the given bus name\n"
> -"on the connected bus daemon.\n"
> -"\n"
> -":Parameters:\n"
> -" `bus_name` : str\n"
> -" A bus name (may be either a unique name or a well-known name)\n"
> -);
> -static PyObject *
> -Bus_get_unix_user(Connection *self, PyObject *args)
> -{
> - DBusError error;
> - unsigned long uid;
> - const char *bus_name;
> -
> - TRACE(self);
> - DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
> - if (!PyArg_ParseTuple(args, "s:get_unix_user", &bus_name)) {
> - return NULL;
> - }
> -
> - dbus_error_init(&error);
> - Py_BEGIN_ALLOW_THREADS
> - uid = dbus_bus_get_unix_user(self->conn, bus_name, &error);
> - Py_END_ALLOW_THREADS
> - if (uid == (unsigned long)(-1)) return DBusPyException_ConsumeError(&error);
> - return PyLong_FromUnsignedLong(uid);
> -}
> -
> -PyDoc_STRVAR(Bus_start_service_by_name__doc__,
> -"start_service_by_name(bus_name)\n\
> -\n\
> -Start a service which will implement the given bus name on this\n\
> -Bus.\n\
> -\n\
> -:Parameters:\n\
> - `bus_name` : str\n\
> - The well-known bus name for which an implementation is required\n\
> -\n\
> -:Returns: A tuple of 2 elements. The first is always True, the second is\n\
> - either START_REPLY_SUCCESS or START_REPLY_ALREADY_RUNNING.\n\
> -\n\
> -:Raises DBusException: if the service could not be started.\n\
> -\n\
> -FIXME: Fix return signature?\n\
> -");
> -static PyObject *
> -Bus_start_service_by_name(Connection *self, PyObject *args)
> -{
> - DBusError error;
> - const char *bus_name;
> - dbus_uint32_t ret;
> - dbus_bool_t success;
> -
> - TRACE(self);
> - DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
> - if (!PyArg_ParseTuple(args, "s:start_service_by_name", &bus_name)) {
> - return NULL;
> - }
> - dbus_error_init(&error);
> - Py_BEGIN_ALLOW_THREADS
> - success = dbus_bus_start_service_by_name(self->conn, bus_name,
> - 0 /* flags */, &ret, &error);
> - Py_END_ALLOW_THREADS
> - if (!success) {
> - return DBusPyException_ConsumeError(&error);
> - }
> - return Py_BuildValue("(Ol)", Py_True, (long)ret);
> -}
> -
> -/* FIXME: signal IN_QUEUE, EXISTS by exception? */
> -PyDoc_STRVAR(Bus_request_name__doc__, "");
> -static PyObject *
> -Bus_request_name(Connection *self, PyObject *args)
> -{
> - unsigned int flags = 0;
> - const char *bus_name;
> - int ret;
> - DBusError error;
> -
> - TRACE(self);
> - DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
> - if (!PyArg_ParseTuple(args, "s|I:request_name", &bus_name, &flags)) {
> - return NULL;
> - }
> - if (!dbus_py_validate_bus_name(bus_name, 0, 1)) return NULL;
> -
> - dbus_error_init(&error);
> - Py_BEGIN_ALLOW_THREADS
> - ret = dbus_bus_request_name(self->conn, bus_name, flags, &error);
> - Py_END_ALLOW_THREADS
> - if (ret == -1) return DBusPyException_ConsumeError(&error);
> -
> - return PyInt_FromLong(ret);
> -}
> -
> -PyDoc_STRVAR(Bus_release_name__doc__, "");
> -static PyObject *
> -Bus_release_name(Connection *self, PyObject *args)
> -{
> - const char *bus_name;
> - int ret;
> - DBusError error;
> -
> - TRACE(self);
> - DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
> - if (!PyArg_ParseTuple(args, "s:release_name", &bus_name)) return NULL;
> -
> - dbus_error_init(&error);
> - Py_BEGIN_ALLOW_THREADS
> - ret = dbus_bus_release_name(self->conn, bus_name, &error);
> - Py_END_ALLOW_THREADS
> - if (ret == -1) return DBusPyException_ConsumeError(&error);
> -
> - return PyInt_FromLong(ret);
> -}
> -
> -PyDoc_STRVAR(Bus_name_has_owner__doc__,
> -"name_has_owner(bus_name) -> bool\n\n"
> -"Return True if and only if the given bus name has an owner on this bus.\n");
> -static PyObject *
> -Bus_name_has_owner(Connection *self, PyObject *args)
> -{
> - const char *bus_name;
> - int ret;
> - DBusError error;
> -
> - TRACE(self);
> - DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
> - if (!PyArg_ParseTuple(args, "s:name_has_owner", &bus_name)) return NULL;
> - dbus_error_init(&error);
> - Py_BEGIN_ALLOW_THREADS
> - ret = dbus_bus_name_has_owner(self->conn, bus_name, &error);
> - Py_END_ALLOW_THREADS
> - if (dbus_error_is_set(&error)) {
> - return DBusPyException_ConsumeError(&error);
> - }
> - return PyBool_FromLong(ret);
> -}
> -
> -PyDoc_STRVAR(Bus_add_match_string__doc__,
> -"add_match_string(rule)\n\n"
> -"Arrange for this application to receive messages on the bus that match\n"
> -"the given rule. This version will block and raises DBusException on error.\n");
> -static PyObject *
> -Bus_add_match_string(Connection *self, PyObject *args)
> -{
> - const char *rule;
> - DBusError error;
> -
> - TRACE(self);
> - DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
> - if (!PyArg_ParseTuple(args, "s:add_match", &rule)) return NULL;
> - dbus_error_init(&error);
> - Py_BEGIN_ALLOW_THREADS
> - dbus_bus_add_match(self->conn, rule, &error);
> - Py_END_ALLOW_THREADS
> - if (dbus_error_is_set(&error)) {
> - return DBusPyException_ConsumeError(&error);
> - }
> - Py_RETURN_NONE;
> -}
> -
> -PyDoc_STRVAR(Bus_add_match_string_non_blocking__doc__,
> -"add_match_string_non_blocking(rule)\n\n"
> -"Arrange for this application to receive messages on the bus that match\n"
> -"the given rule. This version does not block, but any errors will be\n"
> -"ignored.\n");
> -static PyObject *
> -Bus_add_match_string_non_blocking(Connection *self, PyObject *args)
> -{
> - const char *rule;
> -
> - DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
> - if (!PyArg_ParseTuple(args, "s:add_match", &rule)) return NULL;
> - Py_BEGIN_ALLOW_THREADS
> - dbus_bus_add_match(self->conn, rule, NULL);
> - Py_END_ALLOW_THREADS
> - Py_RETURN_NONE;
> -}
> -
> -PyDoc_STRVAR(Bus_remove_match_string__doc__,
> -"remove_match_string(rule)\n\n"
> -"Remove the given match rule; if it has been added more than once,\n"
> -"remove one of the identical copies, leaving the others active.\n"
> -"This version blocks, and raises DBusException on error.\n");
> -static PyObject *
> -Bus_remove_match_string(Connection *self, PyObject *args)
> -{
> - const char *rule;
> - DBusError error;
> -
> - TRACE(self);
> - DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
> - if (!PyArg_ParseTuple(args, "s:remove_match", &rule)) return NULL;
> - dbus_error_init(&error);
> - Py_BEGIN_ALLOW_THREADS
> - dbus_bus_remove_match(self->conn, rule, &error);
> - Py_END_ALLOW_THREADS
> - if (dbus_error_is_set(&error)) {
> - return DBusPyException_ConsumeError(&error);
> - }
> - Py_RETURN_NONE;
> -}
> -
> -PyDoc_STRVAR(Bus_remove_match_string_non_blocking__doc__,
> -"remove_match_string_non_blocking(rule)\n\n"
> -"Remove the given match rule; if it has been added more than once,\n"
> -"remove one of the identical copies, leaving the others active.\n"
> -"This version does not block, but causes any errors to be ignored.\n");
> -static PyObject *
> -Bus_remove_match_string_non_blocking(Connection *self, PyObject *args)
> -{
> - const char *rule;
> -
> - TRACE(self);
> - DBUS_PY_RAISE_VIA_NULL_IF_FAIL(self->conn);
> - if (!PyArg_ParseTuple(args, "s:remove_match", &rule)) return NULL;
> - Py_BEGIN_ALLOW_THREADS
> - dbus_bus_remove_match(self->conn, rule, NULL);
> - Py_END_ALLOW_THREADS
> - Py_RETURN_NONE;
> -}
> -
> /* Bus type object ================================================== */
>
> static struct PyMethodDef Bus_tp_methods[] = {
> #define ENTRY(name, flags) {#name, (PyCFunction)Bus_##name, flags, Bus_##name##__doc__},
> ENTRY(get_unique_name, METH_NOARGS)
> - ENTRY(get_unix_user, METH_VARARGS)
> - ENTRY(start_service_by_name, METH_VARARGS)
> - ENTRY(request_name, METH_VARARGS)
> - ENTRY(release_name, METH_VARARGS)
> - ENTRY(name_has_owner, METH_VARARGS)
> - ENTRY(add_match_string, METH_VARARGS)
> - ENTRY(add_match_string_non_blocking, METH_VARARGS)
> - ENTRY(remove_match_string, METH_VARARGS)
> - ENTRY(remove_match_string_non_blocking, METH_VARARGS)
> #undef ENTRY
> {NULL},
> };
> diff --git a/dbus/Makefile.am b/dbus/Makefile.am
> index 9059659..53efa89 100644
> --- a/dbus/Makefile.am
> +++ b/dbus/Makefile.am
> @@ -1,6 +1,7 @@
> pythondbusdir = $(pythondir)/dbus
>
> -nobase_pythondbus_PYTHON = dbus_bindings.py \
> +nobase_pythondbus_PYTHON = bus.py \
> + dbus_bindings.py \
> _dbus.py \
> _version.py \
> decorators.py \
> diff --git a/dbus/_dbus.py b/dbus/_dbus.py
> index a54338d..838b223 100644
> --- a/dbus/_dbus.py
> +++ b/dbus/_dbus.py
> @@ -37,6 +37,7 @@ import sys
> import weakref
> from traceback import print_exc
>
> +from dbus.bus import _BusDaemonMixin
> from dbus.proxies import ProxyObject, BUS_DAEMON_NAME, BUS_DAEMON_PATH, \
> BUS_DAEMON_IFACE
>
> @@ -221,7 +222,7 @@ class SignalMatch(object):
> **self._args_match)
>
>
> -class Bus(BusImplementation):
> +class Bus(BusImplementation, _BusDaemonMixin):
> """A connection to a DBus daemon.
>
> One of three possible standard buses, the SESSION, SYSTEM,
> @@ -533,6 +534,7 @@ class Bus(BusImplementation):
> yield m
>
> def _remove_name_owner_changed_for_match(self, named_service, match):
> + # The signals lock must be held.
> notification = self._signal_sender_matches.get(named_service, False)
> if notification:
> try:
> diff --git a/dbus/bus.py b/dbus/bus.py
> new file mode 100644
> index 0000000..20bc97f
> --- /dev/null
> +++ b/dbus/bus.py
> @@ -0,0 +1,191 @@
> +"""Bus mixin, for use within dbus-python only. See `_BusMixin`."""
> +
> +# Copyright (C) 2007 Collabora Ltd. <http://www.collabora.co.uk/>
> +#
> +# Licensed under the Academic Free License version 2.1
> +#
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU Lesser General Public License as published
> +# by the Free Software Foundation; either version 2.1 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program; if not, write to the Free Software
> +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> +
> +from dbus import UInt32, UTF8String
> +from dbus.proxies import BUS_DAEMON_NAME, BUS_DAEMON_PATH, BUS_DAEMON_IFACE
> +
> +from _dbus_bindings import validate_interface_name, validate_member_name,\
> + validate_bus_name, validate_object_path,\
> + validate_error_name
> +
> +def _noop(*args, **kwargs):
> + """A universal no-op function"""
> +
> +class _BusDaemonMixin(object):
> + """This mixin must be mixed-in with something with a get_object method
> + (obviously, it's meant to be the dbus.Bus). It provides simple blocking
> + wrappers for various methods on the org.freedesktop.DBus bus-daemon
> + object, to reduce the amount of C code we need.
> + """
> +
> + def get_unix_user(self, bus_name):
> + """Get the numeric uid of the process owning the given bus name.
> +
> + :Parameters:
> + `bus_name` : str
> + A bus name, either unique or well-known
> + :Returns: a `dbus.UInt32`
> + """
> + validate_bus_name(bus_name)
> + return self.get_object(BUS_DAEMON_NAME,
> + BUS_DAEMON_PATH).GetConnectionUnixUser(bus_name,
> + dbus_interface=BUS_DAEMON_IFACE)
> +
> + def start_service_by_name(self, bus_name, flags=0):
> + """Start a service which will implement the given bus name on this Bus.
> +
> + :Parameters:
> + `bus_name` : str
> + The well-known bus name to be activated.
> + `flags` : dbus.UInt32
> + Flags to pass to StartServiceByName (currently none are
> + defined)
> +
> + :Returns: A tuple of 2 elements. The first is always True, the
> + second is either START_REPLY_SUCCESS or
> + START_REPLY_ALREADY_RUNNING.
> +
> + :Raises DBusException: if the service could not be started.
> + """
> + validate_bus_name(bus_name)
> + ret = self.get_object(BUS_DAEMON_NAME,
> + BUS_DAEMON_PATH).StartServiceByName(bus_name, UInt32(flags),
> + dbus_interface=BUS_DAEMON_IFACE)
> + return (True, ret)
> +
> + # XXX: it might be nice to signal IN_QUEUE, EXISTS by exception,
> + # but this would not be backwards-compatible
> + def request_name(self, name, flags=0):
> + """Request a bus name.
> +
> + :Parameters:
> + `name` : str
> + The well-known name to be requested
> + `flags` : dbus.UInt32
> + A bitwise-OR of 0 or more of the flags
> + `DBUS_NAME_FLAG_ALLOW_REPLACEMENT`,
> + `DBUS_NAME_FLAG_REPLACE_EXISTING`
> + and `DBUS_NAME_FLAG_DO_NOT_QUEUE`
> + :Returns: `DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER`,
> + `DBUS_REQUEST_NAME_REPLY_IN_QUEUE`,
> + `DBUS_REQUEST_NAME_REPLY_EXISTS` or
> + `DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER`
> + :Raises DBusException: if the bus daemon cannot be contacted or
> + returns an error.
> + """
> + validate_bus_name(name, allow_unique=False)
> + return self.get_object(BUS_DAEMON_NAME,
> + BUS_DAEMON_PATH).RequestName(name, UInt32(flags),
> + dbus_interface=BUS_DAEMON_IFACE)
> +
> + def release_name(self, name):
> + """Release a bus name.
> +
> + :Parameters:
> + `name` : str
> + The well-known name to be released
> + :Returns: `DBUS_RELEASE_NAME_REPLY_RELEASED`,
> + `DBUS_RELEASE_NAME_REPLY_NON_EXISTENT`
> + or `DBUS_RELEASE_NAME_REPLY_NOT_OWNER`
> + :Raises DBusException: if the bus daemon cannot be contacted or
> + returns an error.
> + """
> + validate_bus_name(name, allow_unique=False)
> + return self.get_object(BUS_DAEMON_NAME,
> + BUS_DAEMON_PATH).ReleaseName(name,
> + dbus_interface=BUS_DAEMON_IFACE)
> +
> + def name_has_owner(self, bus_name):
> + """Return True iff the given bus name has an owner on this bus.
> +
> + :Parameters:
> + `name` : str
> + The bus name to look up
> + :Returns: a `bool`
> + """
> + return bool(self.get_object(BUS_DAEMON_NAME,
> + BUS_DAEMON_PATH).NameHasOwner(bus_name,
> + dbus_interface=BUS_DAEMON_IFACE))
> +
> + # AddMatchString is not bound here
> + # RemoveMatchString either
> +
> + def add_match_string(self, rule):
> + """Arrange for this application to receive messages on the bus that
> + match the given rule. This version will block.
> +
> + :Parameters:
> + `rule` : str
> + The match rule
> + :Raises: `DBusException` on error.
> + """
> + self.get_object(BUS_DAEMON_NAME,
> + BUS_DAEMON_PATH).AddMatch(rule,
> + dbus_interface=BUS_DAEMON_IFACE)
> +
> + # FIXME: add an async success/error handler capability?
> + # FIXME: tell the bus daemon not to bother sending us a reply
> + # (and the same for remove_...)
> + def add_match_string_non_blocking(self, rule):
> + """Arrange for this application to receive messages on the bus that
> + match the given rule. This version will not block, but any errors
> + will be ignored.
> +
> +
> + :Parameters:
> + `rule` : str
> + The match rule
> + :Raises: `DBusException` on error.
> + """
> + self.get_object(BUS_DAEMON_NAME,
> + BUS_DAEMON_PATH).AddMatch(rule,
> + dbus_interface=BUS_DAEMON_IFACE,
> + reply_handler=_noop,
> + error_handler=_noop)
> +
> + def remove_match_string(self, rule):
> + """Arrange for this application to receive messages on the bus that
> + match the given rule. This version will block.
> +
> + :Parameters:
> + `rule` : str
> + The match rule
> + :Raises: `DBusException` on error.
> + """
> + self.get_object(BUS_DAEMON_NAME,
> + BUS_DAEMON_PATH).RemoveMatch(rule,
> + dbus_interface=BUS_DAEMON_IFACE)
> +
> + def remove_match_string_non_blocking(self, rule):
> + """Arrange for this application to receive messages on the bus that
> + match the given rule. This version will not block, but any errors
> + will be ignored.
> +
> +
> + :Parameters:
> + `rule` : str
> + The match rule
> + :Raises: `DBusException` on error.
> + """
> + self.get_object(BUS_DAEMON_NAME,
> + BUS_DAEMON_PATH).RemoveMatch(rule,
> + dbus_interface=BUS_DAEMON_IFACE,
> + reply_handler=_noop,
> + error_handler=_noop)
> _______________________________________________
> dbus mailing list
> dbus at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dbus
More information about the dbus
mailing list