# Connecting to DBus and sending messages

Jeepney can be used with several different frameworks:

- Blocking I/O

- Multi-threading with the threading module

- Trio

- asyncio

For each of these, there is a module in `jeepney.io` providing the integration layer.

Here’s an example of sending a desktop notification, using blocking I/O:

    from jeepney import DBusAddress, new_method_call
    from jeepney.io.blocking import open_dbus_connection

    notifications = DBusAddress('/org/freedesktop/Notifications',
                                bus_name='org.freedesktop.Notifications',
                                interface='org.freedesktop.Notifications')

    connection = open_dbus_connection(bus='SESSION')

    # Construct a new D-Bus message. new_method_call takes the address, the
    # method name, the signature string, and a tuple of arguments.
    msg = new_method_call(notifications, 'Notify', 'susssasa{sv}i',
                          ('jeepney_test',  # App name
                           0,   # Not replacing any previous notification
                           '',  # Icon
                           'Hello, world!',  # Summary
                           'This is an example notification from Jeepney',
                           [], {},  # Actions, hints
                           -1,      # expire_timeout (-1 = default)
                          ))

    # Send the message and wait for the reply
    reply = connection.send_and_get_reply(msg)
    print('Notification ID:', reply.body[0])

    connection.close()

And here is the same thing using asyncio:

    """Send a desktop notification

    See also aio_notify.py, which does the same with the higher-level Proxy API.
    """
    import asyncio

    from jeepney import DBusAddress, new_method_call
    from jeepney.io.asyncio import open_dbus_router

    notifications = DBusAddress('/org/freedesktop/Notifications',
                                bus_name='org.freedesktop.Notifications',
                                interface='org.freedesktop.Notifications')

    async def send_notification():
        msg = new_method_call(notifications, 'Notify', 'susssasa{sv}i',
                                ('jeepney_test',  # App name
                                 0,     # Not replacing any previous notification
                                 '',    # Icon
                                 'Hello, world!',  # Summary
                                 'This is an example notification from Jeepney',
                                 [], {},  # Actions, hints
                                 -1,      # expire_timeout (-1 = default)
                                ))
        # Send the message and await the reply
        async with open_dbus_router() as router:
            reply = await router.send_and_get_reply(msg)
            print('Notification ID:', reply.body[0])

    loop = asyncio.get_event_loop()
    loop.run_until_complete(send_notification())

See the examples folder in Jeepney’s source repository for more examples.

## Connections and Routers

Each integration (except blocking I/O) can create connections and routers.

Routers are useful for calling methods in other processes. Routers let you send a request and wait for a reply, using a proxy or with `router.send_and_get_reply()`. You can also filter incoming messages into queues, e.g. to wait for a specific signal. But if messages arrive faster than they are processed, these queues fill up, and messages may be dropped.

Connections are simpler: they let you send and receive messages, but `conn.receive()` will give you the next message read, whatever that is. You’d use this to write a server which responds to incoming messages. A connection will never discard an incoming message.

Note

For blocking, single-threaded I/O, the connection doubles as a router. Incoming messages while you’re waiting for a reply will be filtered, and you can also filter the next message by calling `conn.recv_messages()`.

Routers for the other integrations receive messages in a background task.

## Message generators and proxies

If you’re calling a number of different methods, you can make a message generator class containing their definitions. Jeepney includes a tool to generate these classes automatically—see Generating D-Bus wrappers.

Message generators define how to construct messages. Proxies are wrappers around message generators which send a message and get the reply back.

Let’s rewrite the example above to use a message generator and a proxy:

    """Send a desktop notification

    See also aio_notify_noproxy.py, which does the same with lower-level APIs
    """
    import asyncio

    from jeepney import MessageGenerator, new_method_call
    from jeepney.io.asyncio import open_dbus_router, Proxy

    # ---- Message generator, created by jeepney.bindgen ----
    class Notifications(MessageGenerator):
        interface = 'org.freedesktop.Notifications'

        def __init__(self, object_path='/org/freedesktop/Notifications',
                     bus_name='org.freedesktop.Notifications'):
            super().__init__(object_path=object_path, bus_name=bus_name)

        def Notify(self, arg_0, arg_1, arg_2, arg_3, arg_4, arg_5, arg_6, arg_7):
            return new_method_call(self, 'Notify', 'susssasa{sv}i',
                                   (arg_0, arg_1, arg_2, arg_3, arg_4, arg_5, arg_6, arg_7))

        def CloseNotification(self, arg_0):
            return new_method_call(self, 'CloseNotification', 'u',
                                   (arg_0,))

        def GetCapabilities(self):
            return new_method_call(self, 'GetCapabilities')

        def GetServerInformation(self):
            return new_method_call(self, 'GetServerInformation')
    # ---- End auto generated code ----

    async def send_notification():
        async with open_dbus_router() as router:
            proxy = Proxy(Notifications(), router)

            resp = await proxy.Notify('jeepney_test',  # App name
                                  0,      # Not replacing any previous notification
                                  '',     # Icon
                                  'Hello, world!',  # Summary
                                  'This is an example notification from Jeepney',
                                  [], {},  # Actions, hints
                                  -1,      # expire_timeout (-1 = default)
                                 )
            print('Notification ID:', resp[0])

    if __name__ == '__main__':
        asyncio.run(send_notification())

This is more code for the simple use case here, but in a larger application collecting the message definitions together like this could make it clearer.

## Sending & receiving file descriptors

Added in version 0.7.

D-Bus allows sending file descriptors - references to open files, sockets, etc. To use this, use the blocking, multi-threading or Trio integration and enable it (`enable_fds=True`) when connecting to D-Bus. If you enable FD support but the message bus can’t or won’t support it, `FDNegotiationError` will be raised.

To send a file descriptor, pass any object with a `.fileno()` method, such as an open file or socket, or a suitable integer. The file descriptor must not be closed before the message is sent.

A received file descriptor will be returned as a `FileDescriptor` object to help avoid leaking FDs. This can easily be converted to a file object (`to_file()`), a socket (`to_socket()`) or a plain integer (`to_raw_fd()`).

    # Send a file descriptor for a temp file (normally not visible in any folder)
    with TemporaryFile() as tf:
        msg = new_method_call(server, 'write_data', 'h', (tf,))
        await router.send_and_get_reply(msg)

    # Receive a file descriptor, use it as a writable file
    msg = await conn.receive()
    fd, = msg.body
    with fd.to_file('w') as f:
        f.write(f'Timestamp: {datetime.now()}')

The snippets above are based on the Trio integration. See the examples directory in the Jeepney repository for complete, working examples.