Skip to content

Commit 93bbd7c

Browse files
author
Anders Hellerup Madsen
committed
support signatures in method decorator
1 parent f97900e commit 93bbd7c

2 files changed

Lines changed: 46 additions & 23 deletions

File tree

dbus_next/service.py

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,39 @@
66

77
from functools import wraps
88
import inspect
9-
from typing import no_type_check_decorator, Dict, List, Any
9+
from typing import no_type_check_decorator, Dict, List, Any, Optional
1010
import copy
1111
import asyncio
1212

1313

1414
class _Method:
15-
def __init__(self, fn, name, disabled=False):
16-
in_signature = ''
17-
out_signature = ''
15+
def __init__(self, fn, name, disabled=False, in_signature: Optional[str] = None, out_signature: Optional[str] = None):
1816

1917
inspection = inspect.signature(fn)
2018

21-
in_args = []
22-
for i, param in enumerate(inspection.parameters.values()):
23-
if i == 0:
24-
# first is self
25-
continue
26-
annotation = parse_annotation(param.annotation)
27-
if not annotation:
28-
raise ValueError(
29-
'method parameters must specify the dbus type string as an annotation')
30-
in_args.append(intr.Arg(annotation, intr.ArgDirection.IN, param.name))
31-
in_signature += annotation
19+
if in_signature is None:
20+
in_signature = ''
21+
in_args = []
22+
for i, param in enumerate(inspection.parameters.values()):
23+
if i == 0:
24+
# first is self
25+
continue
26+
annotation = parse_annotation(param.annotation)
27+
if not annotation:
28+
raise ValueError(
29+
'method parameters must specify the dbus type string as an annotation')
30+
in_args.append(intr.Arg(annotation, intr.ArgDirection.IN, param.name))
31+
in_signature += annotation
32+
else:
33+
name_iter = iter(inspection.parameters.keys())
34+
next(name_iter) # skip self parameter
35+
in_args = [intr.Arg(type_, intr.ArgDirection.IN, name) for
36+
name, type_ in zip(name_iter, SignatureTree._get(in_signature).types)]
37+
38+
if out_signature is None:
39+
out_signature = parse_annotation(inspection.return_annotation)
3240

3341
out_args = []
34-
out_signature = parse_annotation(inspection.return_annotation)
3542
if out_signature:
3643
for type_ in SignatureTree._get(out_signature).types:
3744
out_args.append(intr.Arg(type_, intr.ArgDirection.OUT))
@@ -41,12 +48,12 @@ def __init__(self, fn, name, disabled=False):
4148
self.disabled = disabled
4249
self.introspection = intr.Method(name, in_args, out_args)
4350
self.in_signature = in_signature
44-
self.out_signature = out_signature
4551
self.in_signature_tree = SignatureTree._get(in_signature)
52+
self.out_signature = out_signature
4653
self.out_signature_tree = SignatureTree._get(out_signature)
4754

4855

49-
def method(name: str = None, disabled: bool = False):
56+
def method(name: str = None, disabled: bool = False, in_signature: Optional[str] = None, out_signature: Optional[str] = None):
5057
"""A decorator to mark a class method of a :class:`ServiceInterface` to be a DBus service method.
5158
5259
The parameters and return value must each be annotated with a signature
@@ -91,7 +98,8 @@ def wrapped(*args, **kwargs):
9198
fn(*args, **kwargs)
9299

93100
fn_name = name if name else fn.__name__
94-
wrapped.__dict__['__DBUS_METHOD'] = _Method(fn, fn_name, disabled=disabled)
101+
_method = _Method(fn, fn_name, disabled=disabled, in_signature=in_signature, out_signature=out_signature)
102+
wrapped.__dict__['__DBUS_METHOD'] = _method
95103

96104
return wrapped
97105

test/service/test_decorators.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from dbus_next import PropertyAccess, introspection as intr
22
from dbus_next.service import method, signal, dbus_property, ServiceInterface
33

4+
from typing import List
5+
46

57
class ExampleInterface(ServiceInterface):
68
def __init__(self):
@@ -17,6 +19,10 @@ def some_method(self, one: 's', two: 's') -> 's':
1719
def another_method(self, eight: 'o', six: 't'):
1820
pass
1921

22+
@method(in_signature="sasu", out_signature="i")
23+
def a_third_method(self, one: str, two: List[str], three) -> int:
24+
return 42
25+
2026
@signal()
2127
def some_signal(self) -> 'as':
2228
return ['result']
@@ -56,16 +62,25 @@ def test_method_decorator():
5662
methods = ServiceInterface._get_methods(interface)
5763
signals = ServiceInterface._get_signals(interface)
5864

59-
assert len(methods) == 2
65+
assert len(methods) == 3
6066

6167
method = methods[0]
68+
assert method.name == 'a_third_method'
69+
assert method.in_signature == 'sasu'
70+
assert method.out_signature == 'i'
71+
assert not method.disabled
72+
assert type(method.introspection) is intr.Method
73+
assert len(method.introspection.in_args) == 3
74+
assert len(method.introspection.out_args) == 1
75+
76+
method = methods[1]
6277
assert method.name == 'renamed_method'
6378
assert method.in_signature == 'ot'
6479
assert method.out_signature == ''
6580
assert method.disabled
6681
assert type(method.introspection) is intr.Method
6782

68-
method = methods[1]
83+
method = methods[2]
6984
assert method.name == 'some_method'
7085
assert method.in_signature == 'ss'
7186
assert method.out_signature == 's'
@@ -142,7 +157,7 @@ def test_interface_introspection():
142157
signals = xml.findall('signal')
143158
properties = xml.findall('property')
144159

145-
assert len(xml) == 4
146-
assert len(methods) == 1
160+
assert len(xml) == 5
161+
assert len(methods) == 2
147162
assert len(signals) == 1
148163
assert len(properties) == 2

0 commit comments

Comments
 (0)