Skip to content

Commit 9302e0d

Browse files
committed
feat: context manager protocol
This makes it easy to disconnect the bus once you are done.
1 parent 5c61e6f commit 9302e0d

File tree

5 files changed

+65
-32
lines changed

5 files changed

+65
-32
lines changed

README.md

Lines changed: 31 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -82,31 +82,31 @@ import asyncio
8282

8383

8484
async def main():
85-
bus = await MessageBus().connect()
86-
# the introspection xml would normally be included in your project, but
87-
# this is convenient for development
88-
introspection = await bus.introspect('org.mpris.MediaPlayer2.vlc', '/org/mpris/MediaPlayer2')
85+
async with MessageBus() as bus:
86+
# the introspection xml would normally be included in your project, but
87+
# this is convenient for development
88+
introspection = await bus.introspect('org.mpris.MediaPlayer2.vlc', '/org/mpris/MediaPlayer2')
8989

90-
obj = bus.get_proxy_object('org.mpris.MediaPlayer2.vlc', '/org/mpris/MediaPlayer2', introspection)
91-
player = obj.get_interface('org.mpris.MediaPlayer2.Player')
92-
properties = obj.get_interface('org.freedesktop.DBus.Properties')
90+
obj = bus.get_proxy_object('org.mpris.MediaPlayer2.vlc', '/org/mpris/MediaPlayer2', introspection)
91+
player = obj.get_interface('org.mpris.MediaPlayer2.Player')
92+
properties = obj.get_interface('org.freedesktop.DBus.Properties')
9393

94-
# call methods on the interface (this causes the media player to play)
95-
await player.call_play()
94+
# call methods on the interface (this causes the media player to play)
95+
await player.call_play()
9696

97-
volume = await player.get_volume()
98-
print(f'current volume: {volume}, setting to 0.5')
97+
volume = await player.get_volume()
98+
print(f'current volume: {volume}, setting to 0.5')
9999

100-
await player.set_volume(0.5)
100+
await player.set_volume(0.5)
101101

102-
# listen to signals
103-
def on_properties_changed(interface_name, changed_properties, invalidated_properties):
104-
for changed, variant in changed_properties.items():
105-
print(f'property changed: {changed} - {variant.value}')
102+
# listen to signals
103+
def on_properties_changed(interface_name, changed_properties, invalidated_properties):
104+
for changed, variant in changed_properties.items():
105+
print(f'property changed: {changed} - {variant.value}')
106106

107-
properties.on_properties_changed(on_properties_changed)
107+
properties.on_properties_changed(on_properties_changed)
108108

109-
await asyncio.Event().wait()
109+
await asyncio.Event().wait()
110110

111111
asyncio.run(main())
112112
```
@@ -155,13 +155,13 @@ class ExampleInterface(ServiceInterface):
155155
return 'hello'
156156

157157
async def main():
158-
bus = await MessageBus().connect()
159-
interface = ExampleInterface('test.interface')
160-
bus.export('/test/path', interface)
161-
# now that we are ready to handle requests, we can request name from D-Bus
162-
await bus.request_name('test.name')
163-
# wait indefinitely
164-
await asyncio.Event().wait()
158+
async with MessageBus() as bus:
159+
interface = ExampleInterface('test.interface')
160+
bus.export('/test/path', interface)
161+
# now that we are ready to handle requests, we can request name from D-Bus
162+
await bus.request_name('test.name')
163+
# wait indefinitely
164+
await asyncio.Event().wait()
165165

166166
asyncio.run(main())
167167
```
@@ -181,13 +181,12 @@ import json
181181

182182

183183
async def main():
184-
bus = await MessageBus().connect()
185-
186-
reply = await bus.call(
187-
Message(destination='org.freedesktop.DBus',
188-
path='/org/freedesktop/DBus',
189-
interface='org.freedesktop.DBus',
190-
member='ListNames'))
184+
async with MessageBus() as bus:
185+
reply = await bus.call(
186+
Message(destination='org.freedesktop.DBus',
187+
path='/org/freedesktop/DBus',
188+
interface='org.freedesktop.DBus',
189+
member='ListNames'))
191190

192191
if reply.message_type == MessageType.ERROR:
193192
raise Exception(reply.body[0])

src/dbus_fast/aio/message_bus.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,12 @@ def __init__(
219219
self._disconnect_future = self._loop.create_future()
220220
self._pending_futures: set[asyncio.Future] = set()
221221

222+
async def __aenter__(self) -> MessageBus:
223+
return await self.connect()
224+
225+
async def __aexit__(self, *args, **kwargs) -> None:
226+
self.disconnect()
227+
222228
async def connect(self) -> MessageBus:
223229
"""Connect this message bus to the DBus daemon.
224230

src/dbus_fast/glib/message_bus.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,12 @@ def __init__(
178178
else:
179179
self._auth = auth
180180

181+
def __enter__(self) -> "MessageBus":
182+
return self.connect_sync()
183+
184+
def __exit__(self, *args, **kwargs) -> None:
185+
self.disconnect()
186+
181187
def _on_message(self, msg: Message) -> None:
182188
try:
183189
self._process_message(msg)

tests/test_disconnect.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,14 @@ def send(self, *args, **kwargs):
7474
bus.disconnect()
7575
with pytest.raises(OSError):
7676
await asyncio.wait_for(bus.wait_for_disconnect(), timeout=1)
77+
78+
79+
@pytest.mark.asyncio
80+
async def test_context_manager():
81+
bus = MessageBus()
82+
83+
assert not bus.connected
84+
async with bus:
85+
assert bus.connected
86+
87+
assert not bus.connected

tests/test_glib_low_level.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,3 +178,14 @@ def message_handler(signal):
178178

179179
bus1.disconnect()
180180
bus2.disconnect()
181+
182+
183+
@pytest.mark.skipif(not has_gi, reason=skip_reason_no_gi)
184+
def test_context_manager():
185+
bus = MessageBus()
186+
187+
assert not bus.connected
188+
with bus:
189+
assert bus.connected
190+
191+
assert not bus.connected

0 commit comments

Comments
 (0)