Skip to content

Commit 5312725

Browse files
committed
Fixing typing hints for varargs and kwargs
1 parent 99030f5 commit 5312725

File tree

4 files changed

+38
-15
lines changed

4 files changed

+38
-15
lines changed

atest/DynamicTypesAnnotationsLibrary.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import List, Union, NewType
1+
from typing import List, Union, NewType, Dict
22

33
from robot.api import logger
44

@@ -111,5 +111,5 @@ def keyword_self_and_types(self: 'DynamicTypesAnnotationsLibrary', mandatory: st
111111
return True
112112

113113
@keyword
114-
def keyword_self_and_keyword_only_types(self: 'DynamicTypesAnnotationsLibrary', mandatory, *varargs, other: bool, **kwargs):
114+
def keyword_self_and_keyword_only_types(x: 'DynamicTypesAnnotationsLibrary', mandatory, *varargs: int, other: bool, **kwargs: Dict[str, int]):
115115
return True

src/robotlibcore.py

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -140,17 +140,8 @@ def __get_keyword(self, keyword_name):
140140
def __get_typing_hints(self, method):
141141
if PY2:
142142
return {}
143-
try:
144-
hints = typing.get_type_hints(method)
145-
except Exception:
146-
hints = method.__annotations__
147-
hints.pop('return', None)
148143
spec = ArgumentSpec.from_function(method)
149-
for arg in hints.copy():
150-
# Drop self
151-
if arg not in spec.positional and arg not in spec.kwonlyargs:
152-
hints.pop(arg)
153-
return hints
144+
return spec.get_typing_hints()
154145

155146
def __join_defaults_with_types(self, method, types):
156147
spec = ArgumentSpec.from_function(method)
@@ -199,6 +190,8 @@ def __init__(self):
199190

200191
class ArgumentSpec(object):
201192

193+
_function = None
194+
202195
def __init__(self, positional=None, defaults=None, varargs=None, kwonlyargs=None,
203196
kwonlydefaults=None, kwargs=None):
204197
self.positional = positional or []
@@ -208,6 +201,17 @@ def __init__(self, positional=None, defaults=None, varargs=None, kwonlyargs=None
208201
self.kwonlydefaults = kwonlydefaults or []
209202
self.kwargs = kwargs
210203

204+
def __contains__(self, item):
205+
if item in self.positional:
206+
return True
207+
if self.varargs and item in self.varargs:
208+
return True
209+
if item in self.kwonlyargs:
210+
return True
211+
if self.kwargs and item in self.kwargs:
212+
return True
213+
return False
214+
211215
def get_arguments(self):
212216
args = self._format_positional(self.positional, self.defaults)
213217
args += self._format_default(self.defaults)
@@ -219,6 +223,23 @@ def get_arguments(self):
219223
args.append('**%s' % self.kwargs)
220224
return args
221225

226+
def get_typing_hints(self):
227+
try:
228+
hints = typing.get_type_hints(self._function)
229+
except Exception:
230+
hints = self._function.__annotations__
231+
for arg in list(hints):
232+
# remove return and self statements
233+
if arg not in self:
234+
hints.pop(arg)
235+
if self.varargs and arg in self.varargs:
236+
hints['*%s' % arg] = hints[arg]
237+
del hints[arg]
238+
if self.kwargs and arg in self.kwargs:
239+
hints['**%s' % arg] = hints[arg]
240+
del hints[arg]
241+
return hints
242+
222243
def _format_positional(self, positional, defaults):
223244
for argument, _ in defaults:
224245
positional.remove(argument)
@@ -231,6 +252,7 @@ def _format_default(self, defaults):
231252

232253
@classmethod
233254
def from_function(cls, function):
255+
cls._function = function
234256
if PY2:
235257
spec = inspect.getargspec(function)
236258
else:

utest/test_get_keyword_types.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from robotlibcore import PY2
55

66
if not PY2:
7-
from typing import List, Union
7+
from typing import List, Union, Dict
88
from DynamicTypesAnnotationsLibrary import DynamicTypesAnnotationsLibrary
99
from DynamicTypesAnnotationsLibrary import CustomObject
1010

@@ -206,7 +206,8 @@ def test_keyword_self_and_types(lib_types):
206206
types = lib_types.get_keyword_types('keyword_self_and_types')
207207
assert types == {'mandatory': str, 'other': bool}
208208

209+
209210
@pytest.mark.skipif(PY2, reason='Only applicable on Python 3')
210211
def test_keyword_self_and_keyword_only_types(lib_types):
211212
types = lib_types.get_keyword_types('keyword_self_and_keyword_only_types')
212-
assert types == {'other': bool}
213+
assert types == {'*varargs': int, 'other': bool, '**kwargs': Dict[str, int]}

utest/test_robotlibcore.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ def test_keyword_only_arguments_for_get_keyword_arguments_rf32():
250250
assert args('keyword_only_arguments_many') == ['*varargs', ('some', 'value'), ('other', None)]
251251
assert args('keyword_only_arguments_no_default') == ['*varargs', 'other']
252252
assert args('keyword_only_arguments_default_and_no_default') == ['*varargs', 'other', ('value', False)]
253-
all_args = [ 'mandatory', ('positional', 1), '*varargs', 'other', ('value', False), '**kwargs']
253+
all_args = ['mandatory', ('positional', 1), '*varargs', 'other', ('value', False), '**kwargs']
254254
assert args('keyword_all_args') == all_args
255255

256256

0 commit comments

Comments
 (0)