From 62cf63d4d41a4268209971fdf9ab60e0f50255dd Mon Sep 17 00:00:00 2001 From: Tom Cook Date: Mon, 21 Nov 2022 16:04:10 +0000 Subject: [PATCH 1/8] Fix case where user dbus socket is not in abstract namespace. --- test/test_tcp_address.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/test_tcp_address.py b/test/test_tcp_address.py index a6b6ebb..3e33ba8 100644 --- a/test/test_tcp_address.py +++ b/test/test_tcp_address.py @@ -15,8 +15,12 @@ async def test_tcp_connection_with_forwarding(event_loop): addr_info = parse_address(os.environ.get('DBUS_SESSION_BUS_ADDRESS')) assert addr_info - assert 'abstract' in addr_info[0][1] - path = f'\0{addr_info[0][1]["abstract"]}' + if 'abstract' in addr_info[0][1]: + path = f'\0{addr_info[0][1]["abstract"]}' + elif 'path' in addr_info[0][1]: + path = addr_info[0][1]['path'] + + assert path async def handle_connection(tcp_reader, tcp_writer): unix_reader, unix_writer = await asyncio.open_unix_connection(path) From 00f85b7804cf69084fc2ccfd4dbc3cf378b577f1 Mon Sep 17 00:00:00 2001 From: Tom Cook Date: Mon, 21 Nov 2022 16:17:56 +0000 Subject: [PATCH 2/8] Return method return value from @method decorator. --- dbus_next/service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbus_next/service.py b/dbus_next/service.py index b2a96cf..a241dcb 100644 --- a/dbus_next/service.py +++ b/dbus_next/service.py @@ -88,7 +88,7 @@ def echo_two(self, val1: 's', val2: 'u') -> 'su': def decorator(fn): @wraps(fn) def wrapped(*args, **kwargs): - fn(*args, **kwargs) + return fn(*args, **kwargs) fn_name = name if name else fn.__name__ wrapped.__dict__['__DBUS_METHOD'] = _Method(fn, fn_name, disabled=disabled) From 785fa3a5f2a020e4e0956069b7d211fd5469b124 Mon Sep 17 00:00:00 2001 From: Tom Cook Date: Mon, 21 Nov 2022 18:19:52 +0000 Subject: [PATCH 3/8] Make message information available in current_message proxy. --- .vscode/settings.json | 7 +++++++ dbus_next/message_bus.py | 17 +++++++++++++++++ test/client/test_methods.py | 8 ++++++++ 3 files changed, 32 insertions(+) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..b2b8866 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "python.testing.pytestArgs": [ + "test" + ], + "python.testing.unittestEnabled": false, + "python.testing.pytestEnabled": true +} \ No newline at end of file diff --git a/dbus_next/message_bus.py b/dbus_next/message_bus.py index 8bb830d..3590d8b 100644 --- a/dbus_next/message_bus.py +++ b/dbus_next/message_bus.py @@ -9,6 +9,7 @@ from .proxy_object import BaseProxyObject from . import introspection as intr +import contextvars import inspect import socket import logging @@ -18,6 +19,21 @@ from typing import Type, Callable, Optional, Union +class ContextProxy: + def __init__(self, name): + self._obj = contextvars.ContextVar(name) + + def __getattr__(self, name): + proxy = self._obj.get() + return getattr(proxy, name) + + def set_value(self, value): + self._obj.set(value) + + +current_message = ContextProxy("current_message") + + class BaseMessageBus: """An abstract class to manage a connection to a DBus message bus. @@ -661,6 +677,7 @@ def send_error(self, exc): return SendReply() def _process_message(self, msg): + current_message.set_value(msg) handled = False for handler in self._user_message_handlers: diff --git a/test/client/test_methods.py b/test/client/test_methods.py index 5f2c6c0..8a443db 100644 --- a/test/client/test_methods.py +++ b/test/client/test_methods.py @@ -2,6 +2,7 @@ from dbus_next.service import ServiceInterface, method import dbus_next.introspection as intr from dbus_next import aio, glib, DBusError +from dbus_next.message_bus import current_message from test.util import check_gi_repository, skip_reason_no_gi import pytest @@ -37,6 +38,9 @@ def EchoThree(self, what1: 's', what2: 's', what3: 's') -> 'sss': def ThrowsError(self): raise DBusError('test.error', 'something went wrong') + @method() + def UsesCurrentMessage(self) -> 's': + return current_message.sender @pytest.mark.asyncio async def test_aio_proxy_object(): @@ -79,6 +83,9 @@ async def test_aio_proxy_object(): result = await interface.call_echo_string('no reply', flags=MessageFlag.NO_REPLY_EXPECTED) assert result is None + result = await interface.call_uses_current_message() + assert result + with pytest.raises(DBusError): try: await interface.call_throws_error() @@ -130,3 +137,4 @@ def test_glib_proxy_object(): bus.disconnect() bus2.disconnect() + From a283430d91bc1898ad9c6a14817315bbcca90ebe Mon Sep 17 00:00:00 2001 From: Tom Cook Date: Mon, 21 Nov 2022 18:27:25 +0000 Subject: [PATCH 4/8] Add some docstrings --- dbus_next/message_bus.py | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/dbus_next/message_bus.py b/dbus_next/message_bus.py index 3590d8b..b78b16b 100644 --- a/dbus_next/message_bus.py +++ b/dbus_next/message_bus.py @@ -16,21 +16,49 @@ import xml.etree.ElementTree as ET import traceback -from typing import Type, Callable, Optional, Union +from typing import Type, Callable, Optional, Union, Any -class ContextProxy: - def __init__(self, name): +class ReadOnlyContextProxy: + """ + A convenience class for making a context variable accessible as though it + were a local. Any request for an attribute (other than `set_value`) on the + proxy will be passed through to the underlying variable. Attributes are + immutable. + + :param name: The name of the context variable. + """ + def __init__(self, name:str): self._obj = contextvars.ContextVar(name) - def __getattr__(self, name): + def __getattr__(self, name:str) -> Any: proxy = self._obj.get() return getattr(proxy, name) - def set_value(self, value): + def set_value(self, value:Any): + """ + Set the value of the underlying context variable. + """ self._obj.set(value) +""" +The :class:`Message ` object currently being handled. + +Client code can use this to obtain access to details from the message without +modifying their public API. Typical use is: + +``` +from dbus_next.message_bus import current_message + +@method() +def echo_sender() -> 's': + return current_message.sender +``` + +Attempts to access any attribute of `current_message` outside of a message context +will result in a `LookupError` being raised. +""" current_message = ContextProxy("current_message") From 65b18c528147a1c1611b10307978ecb3843289ad Mon Sep 17 00:00:00 2001 From: Tom Cook Date: Mon, 21 Nov 2022 18:27:54 +0000 Subject: [PATCH 5/8] Fix rename of ContentProxy -> ReadOnlyContentProxy --- dbus_next/message_bus.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbus_next/message_bus.py b/dbus_next/message_bus.py index b78b16b..d169c2e 100644 --- a/dbus_next/message_bus.py +++ b/dbus_next/message_bus.py @@ -59,7 +59,7 @@ def echo_sender() -> 's': Attempts to access any attribute of `current_message` outside of a message context will result in a `LookupError` being raised. """ -current_message = ContextProxy("current_message") +current_message = ReadOnlyContextProxy("current_message") class BaseMessageBus: From aa5e7a727b2510ef5013acd58ac7609719cf171d Mon Sep 17 00:00:00 2001 From: Tom Cook Date: Mon, 21 Nov 2022 18:50:46 +0000 Subject: [PATCH 6/8] Whitespace fixes. --- dbus_next/message_bus.py | 6 +++--- test/client/test_methods.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dbus_next/message_bus.py b/dbus_next/message_bus.py index d169c2e..e1d3bce 100644 --- a/dbus_next/message_bus.py +++ b/dbus_next/message_bus.py @@ -28,14 +28,14 @@ class ReadOnlyContextProxy: :param name: The name of the context variable. """ - def __init__(self, name:str): + def __init__(self, name: str): self._obj = contextvars.ContextVar(name) - def __getattr__(self, name:str) -> Any: + def __getattr__(self, name: str) -> Any: proxy = self._obj.get() return getattr(proxy, name) - def set_value(self, value:Any): + def set_value(self, value: Any): """ Set the value of the underlying context variable. """ diff --git a/test/client/test_methods.py b/test/client/test_methods.py index 8a443db..e74e864 100644 --- a/test/client/test_methods.py +++ b/test/client/test_methods.py @@ -42,6 +42,7 @@ def ThrowsError(self): def UsesCurrentMessage(self) -> 's': return current_message.sender + @pytest.mark.asyncio async def test_aio_proxy_object(): bus_name = 'aio.client.test.methods' @@ -137,4 +138,3 @@ def test_glib_proxy_object(): bus.disconnect() bus2.disconnect() - From f68ec96b13e32b823887e5971de7c4966c31c7a6 Mon Sep 17 00:00:00 2001 From: Tom Cook Date: Mon, 21 Nov 2022 18:57:40 +0000 Subject: [PATCH 7/8] Remove VScode settings --- .gitignore | 3 +++ .vscode/settings.json | 7 ------- 2 files changed, 3 insertions(+), 7 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.gitignore b/.gitignore index 8793551..293aaa9 100644 --- a/.gitignore +++ b/.gitignore @@ -124,3 +124,6 @@ dmypy.json # vim *.swp + +# vscode +.vscode/ diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index b2b8866..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "python.testing.pytestArgs": [ - "test" - ], - "python.testing.unittestEnabled": false, - "python.testing.pytestEnabled": true -} \ No newline at end of file From 1d12c6d02a7aefdd7df50a1d41dcb63a19e8acd2 Mon Sep 17 00:00:00 2001 From: Tom Cook Date: Mon, 21 Nov 2022 19:03:16 +0000 Subject: [PATCH 8/8] Add current_message test for signals. --- test/client/test_signals.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/client/test_signals.py b/test/client/test_signals.py index 848265d..94b14cb 100644 --- a/test/client/test_signals.py +++ b/test/client/test_signals.py @@ -3,6 +3,7 @@ from dbus_next import Message from dbus_next.introspection import Node from dbus_next.constants import RequestNameReply +from dbus_next.message_bus import current_message import pytest @@ -53,6 +54,7 @@ def single_handler(value): nonlocal single_counter nonlocal err assert value == 'hello' + assert current_message.sender single_counter += 1 except Exception as e: err = e @@ -65,6 +67,7 @@ def multiple_handler(value1, value2): try: assert value1 == 'hello' assert value2 == 'world' + assert current_message.sender multiple_counter += 1 except Exception as e: err = e