| 
22 | 22 | import inspect  | 
23 | 23 | import os  | 
24 | 24 | import sys  | 
 | 25 | + | 
25 | 26 | try:  | 
26 | 27 |     import typing  | 
27 | 28 | except ImportError:  | 
28 | 29 |     typing = None  | 
29 | 30 | 
 
  | 
30 |  | - | 
31 | 31 | from robot.api.deco import keyword  # noqa F401  | 
32 | 32 | from robot import __version__ as robot_version  | 
33 | 33 | 
 
  | 
34 | 34 | PY2 = sys.version_info < (3,)  | 
 | 35 | +RF32 = robot_version > '3.2'  | 
35 | 36 | 
 
  | 
36 | 37 | __version__ = '1.0.1.dev1'  | 
37 | 38 | 
 
  | 
@@ -101,36 +102,8 @@ def get_keyword_arguments(self, name):  | 
101 | 102 |         kw_method = self.__get_keyword(name)  | 
102 | 103 |         if kw_method is None:  | 
103 | 104 |             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:  | 
108 |  | -            args += self.__old_default_spec(defaults)  | 
109 |  | -        if varargs:  | 
110 |  | -            args.append('*%s' % varargs)  | 
111 |  | -        if kwargs:  | 
112 |  | -            args.append('**%s' % kwargs)  | 
113 |  | -        return args  | 
114 |  | - | 
115 |  | -    def __new_default_spec(self, defaults):  | 
116 |  | -        return [(name, value) for name, value in defaults]  | 
117 |  | - | 
118 |  | -    def __old_default_spec(self, defaults):  | 
119 |  | -        return ['{}={}'.format(name, value) for name, value in defaults]  | 
120 |  | - | 
121 |  | -    def __get_arg_spec(self, kw):  | 
122 |  | -        if PY2:  | 
123 |  | -            spec = inspect.getargspec(kw)  | 
124 |  | -            keywords = spec.keywords  | 
125 |  | -        else:  | 
126 |  | -            spec = inspect.getfullargspec(kw)  | 
127 |  | -            keywords = spec.varkw  | 
128 |  | -        args = spec.args[1:] if inspect.ismethod(kw) else spec.args  # drop self  | 
129 |  | -        defaults = spec.defaults or ()  | 
130 |  | -        nargs = len(args) - len(defaults)  | 
131 |  | -        mandatory = args[:nargs]  | 
132 |  | -        defaults = zip(args[nargs:], defaults)  | 
133 |  | -        return mandatory, defaults, spec.varargs, keywords  | 
 | 105 | +        spec = ArgumentSpec.from_function(kw_method)  | 
 | 106 | +        return spec.get_arguments()  | 
134 | 107 | 
 
  | 
135 | 108 |     def get_keyword_tags(self, name):  | 
136 | 109 |         self.__get_keyword_tags_supported = True  | 
@@ -181,8 +154,11 @@ def __get_typing_hints(self, method):  | 
181 | 154 |         return hints  | 
182 | 155 | 
 
  | 
183 | 156 |     def __join_defaults_with_types(self, method, types):  | 
184 |  | -        _, defaults, _, _ = self.__get_arg_spec(method)  | 
185 |  | -        for name, value in defaults:  | 
 | 157 | +        spec = ArgumentSpec.from_function(method)  | 
 | 158 | +        for name, value in spec.defaults:  | 
 | 159 | +            if name not in types and isinstance(value, (bool, type(None))):  | 
 | 160 | +                types[name] = type(value)  | 
 | 161 | +        for name, value in spec.kwonlydefaults:  | 
186 | 162 |             if name not in types and isinstance(value, (bool, type(None))):  | 
187 | 163 |                 types[name] = type(value)  | 
188 | 164 |         return types  | 
@@ -220,3 +196,68 @@ class StaticCore(HybridCore):  | 
220 | 196 | 
 
  | 
221 | 197 |     def __init__(self):  | 
222 | 198 |         HybridCore.__init__(self, [])  | 
 | 199 | + | 
 | 200 | + | 
 | 201 | +class ArgumentSpec(object):  | 
 | 202 | + | 
 | 203 | +    def __init__(self, positional=None, defaults=None, varargs=None, kwonlyargs=None,  | 
 | 204 | +                 kwonlydefaults=None, kwargs=None):  | 
 | 205 | +        self.positional = positional or []  | 
 | 206 | +        self.defaults = defaults or []  | 
 | 207 | +        self.varargs = varargs  | 
 | 208 | +        self.kwonlyargs = kwonlyargs or []  | 
 | 209 | +        self.kwonlydefaults = kwonlydefaults or []  | 
 | 210 | +        self.kwargs = kwargs  | 
 | 211 | + | 
 | 212 | +    def get_arguments(self):  | 
 | 213 | +        args = self._format_positional(self.positional, self.defaults)  | 
 | 214 | +        args += self._format_default(self.defaults)  | 
 | 215 | +        if self.varargs:  | 
 | 216 | +            args.append('*%s' % self.varargs)  | 
 | 217 | +        args += self._format_positional(self.kwonlyargs, self.kwonlydefaults)  | 
 | 218 | +        args += self._format_default(self.kwonlydefaults)  | 
 | 219 | +        if self.kwargs:  | 
 | 220 | +            args.append('**%s' % self.kwargs)  | 
 | 221 | +        return args  | 
 | 222 | + | 
 | 223 | +    def _format_positional(self, positional, defaults):  | 
 | 224 | +        for argument, _ in defaults:  | 
 | 225 | +            positional.remove(argument)  | 
 | 226 | +        return positional  | 
 | 227 | + | 
 | 228 | +    def _format_default(self, defaults):  | 
 | 229 | +        if RF32:  | 
 | 230 | +            return [default for default in defaults]  | 
 | 231 | +        return ['%s=%s' % (argument, default) for argument, default in defaults]  | 
 | 232 | + | 
 | 233 | +    @classmethod  | 
 | 234 | +    def from_function(cls, function):  | 
 | 235 | +        if PY2:  | 
 | 236 | +            spec = inspect.getargspec(function)  | 
 | 237 | +        else:  | 
 | 238 | +            spec = inspect.getfullargspec(function)  | 
 | 239 | +        args = spec.args[1:] if inspect.ismethod(function) else spec.args  # drop self  | 
 | 240 | +        defaults = cls._get_defaults(spec)  | 
 | 241 | +        kwonlyargs, kwonlydefaults, kwargs = cls._get_kw_args(spec)  | 
 | 242 | +        return cls(positional=args,  | 
 | 243 | +                   defaults=defaults,  | 
 | 244 | +                   varargs=spec.varargs,  | 
 | 245 | +                   kwonlyargs=kwonlyargs,  | 
 | 246 | +                   kwonlydefaults=kwonlydefaults,  | 
 | 247 | +                   kwargs=kwargs)  | 
 | 248 | + | 
 | 249 | +    @classmethod  | 
 | 250 | +    def _get_defaults(cls, spec):  | 
 | 251 | +        if not spec.defaults:  | 
 | 252 | +            return []  | 
 | 253 | +        names = spec.args[-len(spec.defaults):]  | 
 | 254 | +        return list(zip(names, spec.defaults))  | 
 | 255 | + | 
 | 256 | +    @classmethod  | 
 | 257 | +    def _get_kw_args(cls, spec):  | 
 | 258 | +        if PY2:  | 
 | 259 | +            return [], [], spec.keywords  | 
 | 260 | +        kwonlyargs = spec.kwonlyargs or []  | 
 | 261 | +        defaults = spec.kwonlydefaults or {}  | 
 | 262 | +        kwonlydefaults = [(arg, name) for arg, name in defaults.items()]  | 
 | 263 | +        return kwonlyargs, kwonlydefaults, spec.varkw  | 
0 commit comments