Skip to content

Commit

Permalink
Fix unable to set the method args names for methods without return args
Browse files Browse the repository at this point in the history
The default value for D-Bus method argument names is now None
which enables setting the return argument names to an empty
sequence. For example, empty tuple `()`.
  • Loading branch information
igo95862 committed Dec 29, 2023
1 parent 513fd92 commit 1708748
Show file tree
Hide file tree
Showing 3 changed files with 165 additions and 17 deletions.
34 changes: 19 additions & 15 deletions src/sdbus/dbus_common_elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,24 +119,16 @@ def __init__(
original_method: FunctionType,
method_name: Optional[str],
input_signature: str,
input_args_names: Sequence[str],
input_args_names: Optional[Sequence[str]],
result_signature: str,
result_args_names: Sequence[str],
result_args_names: Optional[Sequence[str]],
flags: int):

assert not isinstance(input_args_names, str), (
"Passed a string as input args"
" names. Did you forget to put"
" it in to a tuple ('string', ) ?")

assert not any(' ' in x for x in input_args_names), (
"Can't have spaces in argument input names"
f"Args: {input_args_names}")

assert not any(' ' in x for x in result_args_names), (
"Can't have spaces in argument result names."
f"Args: {result_args_names}")

if method_name is None:
method_name = ''.join(
_method_name_converter(original_method.__name__))
Expand All @@ -162,13 +154,25 @@ def __init__(

self.method_name = method_name
self.input_signature = input_signature
self.input_args_names: Sequence[str] = (
self.args_names
if result_args_names and not input_args_names
else input_args_names)
self.input_args_names: Sequence[str] = ()
if input_args_names is not None:
assert not any(' ' in x for x in input_args_names), (
"Can't have spaces in argument input names"
f"Args: {input_args_names}")

self.input_args_names = input_args_names
elif result_args_names is not None:
self.input_args_names = self.args_names

self.result_signature = result_signature
self.result_args_names = result_args_names
self.result_args_names: Sequence[str] = ()
if result_args_names is not None:
assert not any(' ' in x for x in result_args_names), (
"Can't have spaces in argument result names."
f"Args: {result_args_names}")

self.result_args_names = result_args_names

self.flags = flags

self.__doc__ = original_method.__doc__
Expand Down
4 changes: 2 additions & 2 deletions src/sdbus/dbus_proxy_async_method.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,8 +231,8 @@ def dbus_method_async(
input_signature: str = "",
result_signature: str = "",
flags: int = 0,
result_args_names: Sequence[str] = (),
input_args_names: Sequence[str] = (),
result_args_names: Optional[Sequence[str]] = None,
input_args_names: Optional[Sequence[str]] = None,
method_name: Optional[str] = None,
) -> Callable[[T], T]:

Expand Down
144 changes: 144 additions & 0 deletions test/test_sdbus_async_introspection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# SPDX-License-Identifier: LGPL-2.1-or-later

# Copyright (C) 2023 igo95862

# This file is part of python-sdbus

# This library 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 library 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
# Lesser General Public License for more details.

# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
from __future__ import annotations

from typing import TYPE_CHECKING

from sdbus.unittest import IsolatedDbusTestCase

from sdbus import DbusInterfaceCommonAsync, dbus_method_async

if TYPE_CHECKING:
from typing import Tuple, Type

TEST_SERVICE_NAME = 'org.example.test'


def initialize_object(
interface_class: Type[DbusInterfaceCommonAsync],
) -> Tuple[DbusInterfaceCommonAsync, DbusInterfaceCommonAsync]:
test_object = interface_class()
test_object.export_to_dbus('/')

test_object_connection = interface_class.new_proxy(
TEST_SERVICE_NAME, '/')

return test_object, test_object_connection


class TestIntrospection(IsolatedDbusTestCase):

async def asyncSetUp(self) -> None:
await super().asyncSetUp()
await self.bus.request_name_async("org.example.test", 0)

async def test_method_arg_names_none(self) -> None:
class TestInterface(
DbusInterfaceCommonAsync,
interface_name="org.test.test",
):
@dbus_method_async(
input_signature="ss",
result_signature="i",
)
async def login(
self,
user_name: str,
pin_code: str,
) -> int:
return 0

obj, rem = initialize_object(TestInterface)

introspection = await rem.dbus_introspect()
self.assertNotIn('name="user_name"', introspection)
self.assertNotIn('name="result"', introspection)
self.assertNotIn('name="pin_code"', introspection)

async def test_method_arg_names_result_names_only(self) -> None:
class TestInterface(
DbusInterfaceCommonAsync,
interface_name="org.test.test",
):
@dbus_method_async(
input_signature="ss",
result_signature="i",
result_args_names=("result",)
)
async def login(
self,
user_name: str,
pin_code: str,
) -> int:
return 0

obj, rem = initialize_object(TestInterface)

introspection = await rem.dbus_introspect()
self.assertIn('name="user_name"', introspection)
self.assertIn('name="result"', introspection)
self.assertIn('name="pin_code"', introspection)

async def test_method_arg_names_full(self) -> None:
class TestInterface(
DbusInterfaceCommonAsync,
interface_name="org.test.test",
):
@dbus_method_async(
input_signature="ss",
input_args_names=("UserName", "PinCode"),
result_signature="i",
result_args_names=("Result",)
)
async def login(
self,
user_name: str,
pin_code: str,
) -> int:
return 0

obj, rem = initialize_object(TestInterface)

introspection = await rem.dbus_introspect()
self.assertIn('name="UserName"', introspection)
self.assertIn('name="Result"', introspection)
self.assertIn('name="PinCode"', introspection)

async def test_method_arg_names_no_return_args(self) -> None:
class TestInterface(
DbusInterfaceCommonAsync,
interface_name="org.test.test",
):
@dbus_method_async(
input_signature="ss",
result_args_names=(),
)
async def login(
self,
user_name: str,
pin_code: str,
) -> None:
return None

obj, rem = initialize_object(TestInterface)

introspection = await rem.dbus_introspect()
self.assertIn('name="user_name"', introspection)
self.assertIn('name="pin_code"', introspection)

0 comments on commit 1708748

Please sign in to comment.