88import inspect
99from typing import no_type_check_decorator , Dict , List , Any
1010import copy
11-
12- # TODO: if the user uses `from __future__ import annotations` in their code,
13- # the annotation inspection will not work because of PEP 563. We will get
14- # something that needs to be evaled because type hints will become "forward
15- # definitions". You can do this eval automatically with
16- # typing.get_type_hints(). This fails without the __future__ import on
17- # python 3.7 but will always succeed on python4. I don't know how to tell if
18- # the user has imported the future annotation feature. We might just not
19- # support the future import on python3 for now and do a check for python4
20- # later. I really hope they keep supporting this use case.
11+ import ast
12+
13+
14+ def _parse_annotation (annotation : str ) -> str :
15+ '''
16+ Because of PEP 563, if `from __future__ import annotations` is used in code
17+ or on Python version >=3.10 where this is the default, return annotations
18+ from the `inspect` module will return annotations as "forward definitions".
19+ In this case, we must eval the result which we do only when given a string
20+ constant.
21+ '''
22+ def raise_value_error ():
23+ raise ValueError (f'service annotations must be a string constant (got { annotation } )' )
24+
25+ if not annotation or annotation is inspect .Signature .empty :
26+ return ''
27+ if type (annotation ) is not str :
28+ raise_value_error ()
29+ try :
30+ body = ast .parse (annotation ).body
31+ if len (body ) == 1 and type (body [0 ].value ) is ast .Constant :
32+ if type (body [0 ].value .value ) is not str :
33+ raise_value_error ()
34+ return body [0 ].value .value
35+ except SyntaxError :
36+ pass
37+
38+ return annotation
2139
2240
2341class _Method :
@@ -32,16 +50,17 @@ def __init__(self, fn, name, disabled=False):
3250 if i == 0 :
3351 # first is self
3452 continue
35- if param .annotation is inspect .Signature .empty :
53+ annotation = _parse_annotation (param .annotation )
54+ if not annotation :
3655 raise ValueError (
3756 'method parameters must specify the dbus type string as an annotation' )
38- in_args .append (intr .Arg (param . annotation , intr .ArgDirection .IN , param .name ))
39- in_signature += param . annotation
57+ in_args .append (intr .Arg (annotation , intr .ArgDirection .IN , param .name ))
58+ in_signature += annotation
4059
4160 out_args = []
42- if inspection .return_annotation is not inspect . Signature . empty :
43- out_signature = inspection . return_annotation
44- for type_ in SignatureTree ._get (inspection . return_annotation ).types :
61+ out_signature = _parse_annotation ( inspection .return_annotation )
62+ if out_signature :
63+ for type_ in SignatureTree ._get (out_signature ).types :
4564 out_args .append (intr .Arg (type_ , intr .ArgDirection .OUT ))
4665
4766 self .name = name
@@ -114,8 +133,10 @@ def __init__(self, fn, name, disabled=False):
114133 signature = ''
115134 signature_tree = None
116135
117- if inspection .return_annotation is not inspect .Signature .empty :
118- signature = inspection .return_annotation
136+ return_annotation = _parse_annotation (inspection .return_annotation )
137+
138+ if return_annotation :
139+ signature = return_annotation
119140 signature_tree = SignatureTree ._get (signature )
120141 for type_ in signature_tree .types :
121142 args .append (intr .Arg (type_ , intr .ArgDirection .OUT ))
@@ -214,16 +235,18 @@ def __init__(self, fn, *args, **kwargs):
214235 self .prop_getter = fn
215236 self .prop_setter = None
216237
217- sig = inspect .signature (fn )
218- if len (sig .parameters ) != 1 :
238+ inspection = inspect .signature (fn )
239+ if len (inspection .parameters ) != 1 :
219240 raise ValueError ('the property must only have the "self" input parameter' )
220241
221- if sig .return_annotation is inspect .Signature .empty :
242+ return_annotation = _parse_annotation (inspection .return_annotation )
243+
244+ if not return_annotation :
222245 raise ValueError (
223246 'the property must specify the dbus type string as a return annotation string' )
224247
225- self .signature = sig . return_annotation
226- tree = SignatureTree ._get (sig . return_annotation )
248+ self .signature = return_annotation
249+ tree = SignatureTree ._get (return_annotation )
227250
228251 if len (tree .types ) != 1 :
229252 raise ValueError ('the property signature must be a single complete type' )
0 commit comments