Skip to content

Commit 958e3cd

Browse files
committed
Support for keyword only arguments
1 parent 739b5d1 commit 958e3cd

File tree

3 files changed

+64
-7
lines changed

3 files changed

+64
-7
lines changed

atest/DynamicTypesAnnotationsLibrary.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,11 @@ def keyword_robot_types_and_bool_defaults(self, arg1, arg2=False):
7373
@keyword
7474
def keyword_exception_annotations(self, arg: 'NotHere'):
7575
return arg
76+
77+
@keyword
78+
def keyword_only_arguments(self, *varargs, some='value'):
79+
return f'{some}: {type(some)}, {varargs}: {type(varargs)}'
80+
81+
@keyword
82+
def keyword_only_arguments_many(self, *varargs, some='value', other=None):
83+
return f'{some}: {type(some)}, {other}: {type(other)}, {varargs}: {type(varargs)}'

src/robotlibcore.py

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -101,36 +101,59 @@ def get_keyword_arguments(self, name):
101101
kw_method = self.__get_keyword(name)
102102
if kw_method is None:
103103
return None
104-
args, defaults, varargs, kwargs = self.__get_arg_spec(kw_method)
105-
if robot_version >= '3.2':
106-
args += self.__new_default_spec(defaults)
107-
else:
104+
args, defaults, varargs, kwargs, kwonlydefaults = self.__get_arg_spec(kw_method)
105+
if self.__rf_31:
108106
args += self.__old_default_spec(defaults)
107+
else:
108+
args += self.__new_default_spec(defaults)
109109
if varargs:
110110
args.append('*%s' % varargs)
111111
if kwargs:
112112
args.append('**%s' % kwargs)
113+
if kwonlydefaults:
114+
args += self.__kwonlydefaults_spec(kwonlydefaults)
113115
return args
114116

117+
@property
118+
def __rf_31(self):
119+
return robot_version < '3.2'
120+
115121
def __new_default_spec(self, defaults):
116122
return [(name, value) for name, value in defaults]
117123

118124
def __old_default_spec(self, defaults):
119125
return ['{}={}'.format(name, value) for name, value in defaults]
120126

127+
def __kwonlydefaults_spec(self, kwonlydefaults):
128+
args = []
129+
for argument, default_value in kwonlydefaults.items():
130+
if self.__rf_31:
131+
args.append(self.__old_kwonlydefaults_spec(argument, default_value))
132+
else:
133+
args.append(self.__new_kwonlydefaults_spec(argument, default_value))
134+
return args
135+
136+
def __new_kwonlydefaults_spec(self, argument, default_value):
137+
return (argument, default_value)
138+
139+
def __old_kwonlydefaults_spec(self, argument, default_value):
140+
return '%s=%s' % (argument, default_value)
141+
121142
def __get_arg_spec(self, kw):
122143
if PY2:
123144
spec = inspect.getargspec(kw)
124145
keywords = spec.keywords
146+
kwonlydefaults = {}
125147
else:
126148
spec = inspect.getfullargspec(kw)
127149
keywords = spec.varkw
150+
kwonlydefaults = spec.kwonlydefaults
128151
args = spec.args[1:] if inspect.ismethod(kw) else spec.args # drop self
129152
defaults = spec.defaults or ()
130153
nargs = len(args) - len(defaults)
131154
mandatory = args[:nargs]
132155
defaults = zip(args[nargs:], defaults)
133-
return mandatory, defaults, spec.varargs, keywords
156+
return mandatory, defaults, spec.varargs, keywords, kwonlydefaults
134157

135158
def get_keyword_tags(self, name):
136159
self.__get_keyword_tags_supported = True
@@ -181,7 +204,7 @@ def __get_typing_hints(self, method):
181204
return hints
182205

183206
def __join_defaults_with_types(self, method, types):
184-
_, defaults, _, _ = self.__get_arg_spec(method)
207+
_, defaults, _, _, _ = self.__get_arg_spec(method)
185208
for name, value in defaults:
186209
if name not in types and isinstance(value, (bool, type(None))):
187210
types[name] = type(value)

utest/test_robotlibcore.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
import pytest
44
from robot import __version__ as robot__version
55

6-
from robotlibcore import HybridCore
6+
from robotlibcore import HybridCore, PY2
77
from HybridLibrary import HybridLibrary
88
from DynamicLibrary import DynamicLibrary
9+
if not PY2:
10+
from DynamicTypesAnnotationsLibrary import DynamicTypesAnnotationsLibrary
911

1012

1113
def test_keyword_names():
@@ -37,8 +39,12 @@ def test_dir():
3739
'_DynamicCore__get_keyword_tags_supported',
3840
'_DynamicCore__get_typing_hints',
3941
'_DynamicCore__join_defaults_with_types',
42+
'_DynamicCore__kwonlydefaults_spec',
4043
'_DynamicCore__new_default_spec',
44+
'_DynamicCore__new_kwonlydefaults_spec',
4145
'_DynamicCore__old_default_spec',
46+
'_DynamicCore__old_kwonlydefaults_spec',
47+
'_DynamicCore__rf_31',
4248
'_HybridCore__get_members',
4349
'_HybridCore__get_members_from_instance',
4450
'_custom_name',
@@ -76,8 +82,12 @@ def test_dir():
7682
'_DynamicCore__get_keyword_path',
7783
'_DynamicCore__get_keyword_tags_supported',
7884
'_DynamicCore__join_defaults_with_types',
85+
'_DynamicCore__kwonlydefaults_spec',
7986
'_DynamicCore__new_default_spec',
87+
'_DynamicCore__new_kwonlydefaults_spec',
8088
'_DynamicCore__old_default_spec',
89+
'_DynamicCore__old_kwonlydefaults_spec',
90+
'_DynamicCore__rf_31',
8191
'get_keyword_arguments',
8292
'get_keyword_documentation',
8393
'get_keyword_source',
@@ -124,6 +134,22 @@ def test_get_keyword_arguments_rf32():
124134
assert args('__foobar__') is None
125135

126136

137+
@pytest.mark.skipif(PY2, reason='Only for Python 3')
138+
@pytest.mark.skipif(robot__version < '3.2', reason='For RF 3.2 or greater')
139+
def test_keyword_only_arguments_for_get_keyword_arguments_rf32():
140+
args = DynamicTypesAnnotationsLibrary(1).get_keyword_arguments
141+
assert args('keyword_only_arguments') == ['*varargs', ('some', 'value')]
142+
assert args('keyword_only_arguments_many') == ['*varargs', ('some', 'value'), ('other', None)]
143+
144+
145+
@pytest.mark.skipif(PY2, reason='Only for Python 3')
146+
@pytest.mark.skipif(robot__version > '3.2', reason='For RF 3.1')
147+
def test_keyword_only_arguments_for_get_keyword_arguments_rf31():
148+
args = DynamicTypesAnnotationsLibrary(1).get_keyword_arguments
149+
assert args('keyword_only_arguments') == ['*varargs', 'some=value']
150+
assert args('keyword_only_arguments_many') == ['*varargs', 'some=value', 'other=None']
151+
152+
127153
def test_get_keyword_documentation():
128154
doc = DynamicLibrary().get_keyword_documentation
129155
assert doc('function') == ''

0 commit comments

Comments
 (0)