13
13
# See the License for the specific language governing permissions and
14
14
# limitations under the License.
15
15
16
- from inspect import getfullargspec , ismethod , unwrap
16
+ import inspect
17
17
import typing
18
18
19
19
from robot .utils import PY_VERSION
@@ -27,53 +27,64 @@ def __init__(self, type='Keyword'):
27
27
self ._type = type
28
28
29
29
def parse (self , handler , name = None ):
30
- args , varargs , kws , defaults , kwo , kwo_defaults , annotations \
31
- = self ._get_arg_spec (handler )
32
- if ismethod (handler ) or handler .__name__ == '__init__' :
33
- args = args [1 :] # Drop 'self'.
30
+ positional , varargs , kwonly , kwargs , defaults = self ._get_arg_spec (handler )
34
31
spec = ArgumentSpec (
35
32
name ,
36
33
self ._type ,
37
- positional = args ,
34
+ positional = positional ,
38
35
varargs = varargs ,
39
- kwargs = kws ,
40
- kwonlyargs = kwo ,
41
- defaults = self . _get_defaults ( args , defaults , kwo_defaults )
36
+ kwonlyargs = kwonly ,
37
+ kwargs = kwargs ,
38
+ defaults = defaults
42
39
)
43
- spec .types = self ._get_types (handler , annotations , spec )
40
+ spec .types = self ._get_types (handler , spec )
44
41
return spec
45
42
46
43
def _get_arg_spec (self , handler ):
47
- handler = unwrap (handler )
48
44
try :
49
- if handler .__name__ == 'po' :
50
- print (getfullargspec (handler ))
51
- return getfullargspec (handler )
52
- except TypeError : # Can occur w/ C functions (incl. many builtins).
53
- return [], 'args' , None , None , [], None , {}
45
+ signature = inspect .signature (handler )
46
+ except ValueError : # Can occur w/ C functions (incl. many builtins).
47
+ return [], 'args' , [], None , {}
48
+ parameters = list (signature .parameters .values ())
49
+ # `inspect.signature` drops `self` with bound methods and that's the case when
50
+ # inspecting keywords. `__init__` is got directly from class (i.e. isn't bound)
51
+ # so we need to handle that case ourselves.
52
+ if handler .__name__ == '__init__' :
53
+ parameters = parameters [1 :]
54
+ return self ._parse_params (parameters )
54
55
55
- def _get_defaults (self , args , default_values , kwo_defaults ):
56
- if default_values :
57
- defaults = dict (zip (args [- len (default_values ):], default_values ))
58
- else :
59
- defaults = {}
60
- if kwo_defaults :
61
- defaults .update (kwo_defaults )
62
- return defaults
56
+ def _parse_params (self , parameters ):
57
+ positional = []
58
+ varargs = None
59
+ kwonly = []
60
+ kwargs = None
61
+ defaults = {}
62
+ for param in parameters :
63
+ if param .kind in (param .POSITIONAL_ONLY , param .POSITIONAL_OR_KEYWORD ):
64
+ positional .append (param .name )
65
+ elif param .kind == param .VAR_POSITIONAL :
66
+ varargs = param .name
67
+ elif param .kind == param .KEYWORD_ONLY :
68
+ kwonly .append (param .name )
69
+ elif param .kind == param .VAR_KEYWORD :
70
+ kwargs = param .name
71
+ if param .default is not param .empty :
72
+ defaults [param .name ] = param .default
73
+ return positional , varargs , kwonly , kwargs , defaults
63
74
64
- def _get_types (self , handler , annotations , spec ):
75
+ def _get_types (self , handler , spec ):
65
76
types = getattr (handler , 'robot_types' , ())
66
- if types is None :
67
- return None
68
- if types :
77
+ # If types are set using the `@keyword` decorator, use them. Including when
78
+ # types are explicitly disabled with `@keyword(types= None)`.
79
+ if types or types is None :
69
80
return types
70
- return self ._get_type_hints (handler , annotations , spec )
81
+ return self ._get_type_hints (handler , spec )
71
82
72
- def _get_type_hints (self , handler , annotations , spec ):
83
+ def _get_type_hints (self , handler , spec ):
73
84
try :
74
85
type_hints = typing .get_type_hints (handler )
75
86
except Exception : # Can raise pretty much anything
76
- return annotations
87
+ return handler . __annotations__
77
88
self ._remove_mismatching_type_hints (type_hints , spec .argument_names )
78
89
self ._remove_optional_none_type_hints (type_hints , spec .defaults )
79
90
return type_hints
0 commit comments