From 10186487194e31889f0a255f7986577b169220ac Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Fri, 1 Sep 2006 15:54:47 +0100 Subject: [PATCH] dbus._dbus, _dbus_bindings, dbus.proxies: Add docstrings --- dbus/_dbus.py | 152 ++++++++++++++++++++++++++++++++++++++++++++---- dbus/_dbus_bindings.pyx | 110 +++++++++++++++++++++++++++++++++-- dbus/proxies.py | 39 +++++++++++++ 3 files changed, 287 insertions(+), 14 deletions(-) diff --git a/dbus/_dbus.py b/dbus/_dbus.py index 10a49d0..a7cd2c5 100644 --- a/dbus/_dbus.py +++ b/dbus/_dbus.py @@ -72,6 +72,21 @@ class Bus(object): _shared_instances = weakref.WeakValueDictionary() def __new__(cls, bus_type=TYPE_SESSION, use_default_mainloop=True, private=False): + """Constructor, returning an existing instance where appropriate. + + The returned instance is actually always an instance of `SessionBus`, + `SystemBus` or `StarterBus`. + + :Parameters: + `bus_type` : cls.TYPE_SESSION, cls.TYPE_SYSTEM or cls.TYPE_STARTER + Connect to the appropriate bus + `use_default_mainloop` : bool + If true (default), automatically register the new connection + to be polled by the default main loop, if any + `private` : bool + If true, never return an existing shared instance, but instead + return a private connection + """ if (not private and bus_type in cls._shared_instances): return cls._shared_instances[bus_type] @@ -117,26 +132,43 @@ class Bus(object): pass def close(self): + """Close the connection.""" self._connection.close() def get_connection(self): + """Return the underlying `_dbus_bindings.Connection`.""" return self._connection def get_session(private=False): - """Static method that returns the session bus""" + """Static method that returns a connection to the session bus. + + :Parameters: + `private` : bool + If true, do not return a shared connection. + """ return SessionBus(private=private) get_session = staticmethod(get_session) def get_system(private=False): - """Static method that returns the system bus""" + """Static method that returns a connection to the system bus. + + :Parameters: + `private` : bool + If true, do not return a shared connection. + """ return SystemBus(private=private) get_system = staticmethod(get_system) def get_starter(private=False): - """Static method that returns the starter bus""" + """Static method that returns a connection to the starter bus. + + :Parameters: + `private` : bool + If true, do not return a shared connection. + """ return StarterBus(private=private) get_starter = staticmethod(get_starter) @@ -173,6 +205,37 @@ class Bus(object): named_service=None, path=None, **keywords): + """Arrange for the given function to be called when a signal matching + the parameters is emitted. + + :Parameters: + `handler_function` : callable + The function to be called. + `signal_name` : str + The signal name; None (the default) matches all names + `dbus_interface` : str + The D-Bus interface name with which to qualify the signal; + None (the default) matches all interface names + `named_service` : str + A bus name for the sender, which will be resolved to a + unique name if it is not already; None (the default) matches + any sender + `path` : str + The object path of the object which must have emitted the + signal; None (the default) matches any object path + `sender_keyword` : str + If not None (the default), the handler function will receive + the unique name of the sending endpoint as a keyword + argument with this name + `path_keyword` : str + If not None (the default), the handler function will receive + the object-path of the sending object as a keyword argument + with this name + `keywords` + If there are additional keyword parameters of the form + ``arg``\ *n*, match only signals where the *n*\ th argument + is the value given for that keyword parameter + """ args_dict = self._create_args_dict(keywords) @@ -240,6 +303,13 @@ class Bus(object): self._match_rule_tree.exec_matches(match_rule, message) def start_service_by_name(self, named_service): + """Start a service which will implement the given bus name on this + Bus. + + :Parameters: + `named_service` : str + The well-known bus name for which an implementation is required + """ return _dbus_bindings.bus_start_service_by_name(self._connection, named_service) def __repr__(self): @@ -256,26 +326,54 @@ class Bus(object): __str__ = __repr__ class SystemBus(Bus): - """The system-wide message bus - """ + """The system-wide message bus.""" def __new__(cls, use_default_mainloop=True, private=False): + """Return a connection to the system bus. + + :Parameters: + `use_default_mainloop` : bool + If true (default), automatically register the new connection + to be polled by the default main loop, if any + `private` : bool + If true, never return an existing shared instance, but instead + return a private connection. + """ return Bus.__new__(cls, Bus.TYPE_SYSTEM, use_default_mainloop, private) class SessionBus(Bus): - """The session (current login) message bus - """ + """The session (current login) message bus.""" def __new__(cls, use_default_mainloop=True, private=False): + """Return a connection to the session bus. + + :Parameters: + `use_default_mainloop` : bool + If true (default), automatically register the new connection + to be polled by the default main loop, if any + `private` : bool + If true, never return an existing shared instance, but instead + return a private connection. + """ return Bus.__new__(cls, Bus.TYPE_SESSION, use_default_mainloop, private) class StarterBus(Bus): - """The bus that activated this process (if - this process was launched by DBus activation) + """The bus that activated this process (only valid if + this process was launched by DBus activation). """ def __new__(cls, use_default_mainloop=True, private=False): + """Return a connection to the bus that activated this process. + + :Parameters: + `use_default_mainloop` : bool + If true (default), automatically register the new connection + to be polled by the default main loop, if any + `private` : bool + If true, never return an existing shared instance, but instead + return a private connection. + """ return Bus.__new__(cls, Bus.TYPE_STARTER, use_default_mainloop, private) class Interface: - """An interface into a remote object + """An interface into a remote object. An Interface can be used to wrap ProxyObjects so that calls can be routed to their correct @@ -283,16 +381,50 @@ class Interface: """ def __init__(self, object, dbus_interface): + """Construct a proxy for the given interface on the given object. + + :Parameters: + `object` : `dbus.proxies.ProxyObject` + The remote object + `dbus_interface` : str + An interface the `object` implements + """ self._obj = object self._dbus_interface = dbus_interface def connect_to_signal(self, signal_name, handler_function, dbus_interface = None, **keywords): + """Arrange for a function to be called when the given signal is + emitted. + + :Parameters: + `signal_name` : str + The name of the signal + `handler_function` : callable + A function to be called (FIXME arguments?) when the signal + is emitted by the remote object. + `dbus_interface` : str + Optional interface with which to qualify the signal name. + The default is to use the interface this Interface represents. + `sender_keyword` : str + If not None (the default), the handler function will receive + the unique name of the sending endpoint as a keyword + argument with this name + `path_keyword` : str + If not None (the default), the handler function will receive + the object-path of the sending object as a keyword argument + with this name + `keywords` + If there are additional keyword parameters of the form + ``arg``\ *n*, match only signals where the *n*\ th argument + is the value given for that keyword parameter + """ if not dbus_interface: dbus_interface = self._dbus_interface self._obj.connect_to_signal(signal_name, handler_function, dbus_interface, **keywords) def __getattr__(self, member, **keywords): + # FIXME: this syntax is bizarre. if (keywords.has_key('dbus_interface')): _dbus_interface = keywords['dbus_interface'] else: diff --git a/dbus/_dbus_bindings.pyx b/dbus/_dbus_bindings.pyx index c29dea2..cbfa410 100644 --- a/dbus/_dbus_bindings.pyx +++ b/dbus/_dbus_bindings.pyx @@ -7,6 +7,8 @@ #FIXME: find memory leaks that I am sure exist +__docformat__ = 'restructuredtext' + cdef extern from "sys/types.h": ctypedef size_t ctypedef __int64_t @@ -61,25 +63,40 @@ ctypedef struct DBusObjectPathVTable: void (* dbus_internal_pad4) (void *) class DBusException(Exception): - pass + """Represents any D-Bus-related error.""" class ConnectionError(Exception): - pass + """FIXME: Appears to be unused?""" class ObjectPath(str): + """A D-Bus object path, e.g. ``/org/example/foo/FooBar``.""" def __init__(self, value): str.__init__(self, value) class ByteArray(str): + """A byte array represented as an 8-bit string. + + Used to avoid having to construct a list of integers when passing + byte-array (``ay``) parameters to D-Bus methods. + """ def __init__(self, value): str.__init__(self, value) class SignatureIter(object): + """An iterator over complete types in a D-Bus signature.""" + def __init__(self, string): + """Constructor. + + :Parameters: + `string` : str + A D-Bus signature + """ object.__init__(self) self.remaining = string def next(self): + """Return the next complete type, e.g. ``b``, ``ab`` or ``a{sv}``.""" if self.remaining == '': raise StopIteration @@ -132,64 +149,81 @@ class Signature(str): return str.__init__(self, value) def __iter__(self): + """Return an iterator over complete types in the signature.""" return SignatureIter(self) class VariantSignature(object): - """A fake method signature which when iterated, is an endless stream - of variants (handy with zip()). It has no string representation.""" + """A fake method signature which, when iterated, yields an endless stream + of 'v' characters representing variants (handy with zip()). + + It has no string representation. + """ def __iter__(self): + """Return self.""" return self def next(self): + """Return 'v' whenever called.""" return 'v' class Byte(int): + """An unsigned byte""" def __init__(self, value): int.__init__(self, value) class Boolean(int): + """A Boolean value""" def __init__(self, value): int.__init__(self, value) class Int16(int): + """A signed 16-bit integer""" def __init__(self, value): int.__init__(self, value) class UInt16(int): + """An unsigned 16-bit integer""" def __init__(self, value): if value < 0: raise TypeError('Unsigned integers must not have a negitive value') int.__init__(self, value) class Int32(int): + """An signed 32-bit integer""" def __init__(self, value): int.__init__(self, value) class UInt32(long): + """An unsigned 32-bit integer""" def __init__(self, value): if value < 0: raise TypeError('Unsigned integers must not have a negitive value') long.__init__(self, value) class Int64(long): + """A signed 64-bit integer""" def __init__(self, value): long.__init__(self, value) class UInt64(long): + """An unsigned 64-bit integer""" def __init__(self, value): if value < 0: raise TypeError('Unsigned integers must not have a negitive value') long.__init__(self, value) class Double(float): + """A double-precision floating point number""" def __init__(self, value): float.__init__(self, value) class String(unicode): + """A Unicode string""" def __init__(self, value): unicode.__init__(self, value) class Array(list): + """An array of values of the same type""" def __init__(self, value, type=None, signature=None): if signature and type: raise TypeError('Can not mix type and signature arguments in a D-BUS Array') @@ -199,6 +233,7 @@ class Array(list): list.__init__(self, value) class Variant: + """A generic wrapper for values of any other basic D-Bus type""" def __init__(self, value, type=None, signature=None): self.value = value if signature and type: @@ -214,10 +249,16 @@ class Variant: return str(self.value) class Struct(tuple): + """An immutable structure containing D-Bus values, possibly of + different types. + """ def __init__(self, value): tuple.__init__(self, value) class Dictionary(dict): + """A mapping from distinct keys (all of the same type) to values (all + of the same type, which need not be the same type as the values). + """ def __init__(self, value, key_type=None, value_type=None, signature=None): if key_type and not value_type: raise TypeError('When specifying a key_type you must also have a value_type in a D-BUS Dictionary') @@ -300,6 +341,7 @@ cdef DBusHandlerResult cmessage_function_handler (DBusConnection *connection, cdef class Connection: + """A connection to either the bus daemon or a peer.""" def __init__(self, address=None, Connection _conn=None): cdef DBusConnection *c_conn cdef char *c_address @@ -598,6 +640,7 @@ cdef void _pending_call_free_user_data(void *data): Py_XDECREF(call_tuple) cdef class PendingCall: + """Object representing a method call to which a reply is expected.""" cdef DBusPendingCall *pending_call def __init__(self, PendingCall _pending_call=None): @@ -640,6 +683,7 @@ cdef class PendingCall: cdef class Watch: + """Object representing a file descriptor to be watched""" cdef DBusWatch* watch def __init__(self): @@ -1412,6 +1456,9 @@ cdef class MessageIter: (HANDLER_RESULT_HANDLED, HANDLER_RESULT_NOT_YET_HANDLED, HANDLER_RESULT_NEED_MEMORY) = range(3) cdef class Message: + """A D-Bus message. This may be a method call or reply, a signal, an + error, or some message type yet to be invented. + """ cdef DBusMessage *msg def __init__(self, message_type=MESSAGE_TYPE_INVALID, @@ -1615,26 +1662,32 @@ cdef class Message: # FIXME: all the different dbus_message_*args* methods class Signal(Message): + """Message representing a signal.""" def __init__(self, spath, sinterface, sname): Message.__init__(self, MESSAGE_TYPE_SIGNAL, path=spath, dbus_interface=sinterface, name=sname) class EmptyMessage(Message): + """Message for internal use in _dbus_bindings. Do not instantiate.""" def __init__(self): Message.__init__(self, _create=False) class MethodCall(Message): + """Message representing a method call.""" def __init__(self, mpath, minterface, mmethod): Message.__init__(self, MESSAGE_TYPE_METHOD_CALL, path=mpath, dbus_interface=minterface, method=mmethod) class MethodReturn(Message): + """Message representing a method return.""" def __init__(self, method_call): Message.__init__(self, MESSAGE_TYPE_METHOD_RETURN, method_call=method_call) class Error(Message): + """Message representing an error.""" def __init__(self, reply_to, error_name, error_message): Message.__init__(self, MESSAGE_TYPE_ERROR, reply_to=reply_to, error_name=error_name, error_message=error_message) cdef class Server: + """A server that listens for new connections from other applications.""" cdef DBusServer *server def __init__(self, address): cdef DBusError error @@ -1674,6 +1727,16 @@ BUS_SYSTEM = DBUS_BUS_SYSTEM BUS_STARTER = DBUS_BUS_STARTER def bus_get (bus_type, private=False): + """Return a Connection to the appropriate bus type. + + :Parameters: + `bus_type` : DBUS_BUS_SESSION, DBUS_BUS_SYSTEM or DBUS_BUS_STARTER + The bus to which connection is required. + `private` : bool + If true, a unique Connection will be returned. If false (default) + the Connection may be the same one returned by previous + invocations of bus_get. + """ cdef DBusError error cdef Connection conn cdef DBusConnection *connection @@ -1696,11 +1759,24 @@ def bus_get (bus_type, private=False): return conn def bus_get_unique_name(Connection connection): + """Return the unique name of the calling application on the given + connection, which must be to a bus daemon. + """ cdef DBusConnection *conn conn = connection._get_conn() return dbus_bus_get_unique_name(conn) def bus_get_unix_user(Connection connection, service_name): + """Return the numeric uid of the process which owns the given + bus name. + + :Parameters: + `connection` : Connection + The connection on which the name exists, which must be to a bus + daemon. + `service_name` : str + The bus name to be queried. + """ cdef DBusError error dbus_error_init(&error) cdef int retval @@ -1721,6 +1797,18 @@ DBUS_START_REPLY_SUCCESS = 0 DBUS_START_REPLY_ALREADY_RUNNING = 1 def bus_start_service_by_name(Connection connection, service_name, flags=0): + """Start a service that will request ownership of the given bus name. + + :Parameters: + `connection` : Connection + Connection to a bus daemon. + `service_name` : str + A bus name for which an implementation is required. + `flags` : int + Reserved for future expansion, always use 0 for now. + :Returns: + A tuple containing FIXME + """ cdef DBusError error dbus_error_init(&error) cdef dbus_bool_t retval @@ -1739,6 +1827,9 @@ def bus_start_service_by_name(Connection connection, service_name, flags=0): return (retval, results) def bus_register(Connection connection): + """Register a connection with the bus to which the Connection connects. + If registration succeeds, the unique name will be set. + """ cdef DBusError error dbus_error_init(&error) cdef dbus_bool_t retval @@ -1764,6 +1855,10 @@ REQUEST_NAME_REPLY_EXISTS = 3 REQUEST_NAME_REPLY_ALREADY_OWNER = 4 def bus_request_name(Connection connection, service_name, flags=0): + """Ask the bus to which the Connection is connected to assign the + given name to this connection by invoking the RequestName method + on the bus. + """ cdef DBusError error dbus_error_init(&error) cdef int retval @@ -1786,6 +1881,10 @@ RELEASE_NAME_REPLY_NON_EXISTENT = 2 RELEASE_NAME_REPLY_NOT_OWNER = 3 def bus_release_name(Connection connection, service_name): + """Ask the bus to which the Connection is connected to unassign the + given name to this connection by invoking the ReleaseName method + on the bus. + """ cdef DBusError error dbus_error_init(&error) cdef int retval @@ -1803,6 +1902,9 @@ def bus_release_name(Connection connection, service_name): return retval def bus_name_has_owner(Connection connection, service_name): + """Return True if and only if the given bus name has an owner + on the bus to which the given connection is connected. + """ cdef DBusError error dbus_error_init(&error) cdef dbus_bool_t retval diff --git a/dbus/proxies.py b/dbus/proxies.py index babbcd5..7a34de5 100644 --- a/dbus/proxies.py +++ b/dbus/proxies.py @@ -124,6 +124,20 @@ class ProxyObject: INTROSPECT_STATE_INTROSPECT_DONE = 2 def __init__(self, bus, named_service, object_path, introspect=True): + """Initialize the proxy object. + + :Parameters: + `bus` : `dbus.Bus` + The bus on which to find this object + `named_service` : str + A bus name for the endpoint owning the object (need not + actually be a service name) + `object_path` : str + The object path at which the endpoint exports the object + `introspect` : bool + If true (default), attempt to introspect the remote + object to find out supported methods and their signatures + """ self._bus = bus self._named_service = named_service self._object_path = object_path @@ -144,6 +158,31 @@ class ProxyObject: def connect_to_signal(self, signal_name, handler_function, dbus_interface=None, **keywords): + """Arrange for the given function to be called when the given signal + is received. + + :Parameters: + `signal_name` : str + The name of the signal + `handler_function` : callable + A function to be called (FIXME arguments?) when the signal + is emitted by the remote object. + `dbus_interface` : str + Optional interface with which to qualify the signal name. + The default is to use the interface this Interface represents. + `sender_keyword` : str + If not None (the default), the handler function will receive + the unique name of the sending endpoint as a keyword + argument with this name + `path_keyword` : str + If not None (the default), the handler function will receive + the object-path of the sending object as a keyword argument + with this name + `keywords` + If there are additional keyword parameters of the form + ``arg``\ *n*, match only signals where the *n*\ th argument + is the value given for that keyword parameter + """ self._bus.add_signal_receiver(handler_function, signal_name=signal_name, dbus_interface=dbus_interface, -- 2.11.4.GIT