Skip to content

Commit

Permalink
Fixing named argumens with default values
Browse files Browse the repository at this point in the history
Simply logic also

Fixes #118
  • Loading branch information
aaltat committed Feb 17, 2023
1 parent c7ac794 commit 77cac53
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 28 deletions.
9 changes: 9 additions & 0 deletions atest/DynamicTypesAnnotationsLibrary.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,3 +178,12 @@ def kw_with_many_named_arguments_with_default(self, *, arg1, arg2: int):
print(arg1)
print(arg2)
return f"arg1: {arg1}, type: {type(arg1)}, arg2: {arg2}, type: {type(arg2)}"

@keyword
def kw_with_positional_and_named_arguments(self, arg1, *, arg2: int):
return f"arg1: {arg1}, type: {type(arg1)}, arg2: {arg2}, type: {type(arg2)}"

@keyword
def kw_with_positional_and_named_arguments_with_defaults(self, arg1: int = 1, *, arg2: str = "foobar"):
return f"arg1: {arg1}, type: {type(arg1)}, arg2: {arg2}, type: {type(arg2)}"

2 changes: 1 addition & 1 deletion atest/tests.robot
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Keyword Names
IF $LIBRARY == "ExtendExistingLibrary" Keyword In Extending Library

Method Without @keyword Are Not Keyowrds
[Documentation] FAIL GLOB: No keyword with name 'Not keyword' found.*
[Documentation] FAIL GLOB: No keyword with name 'Not Keyword' found.*
Not Keyword

Arguments
Expand Down
47 changes: 21 additions & 26 deletions src/robotlibcore.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@
import inspect
import os
from dataclasses import dataclass
from typing import Any, List, Optional, get_type_hints
from typing import Any, Callable, List, Optional, get_type_hints

from robot.api.deco import keyword # noqa F401
from robot.errors import DataError
from robot.utils import Importer # noqa F401

__version__ = "4.1.1"
__version__ = "4.1.2"


class PythonLibCoreException(Exception):
Expand Down Expand Up @@ -196,20 +196,18 @@ def unwrap(cls, function):
def _get_arguments(cls, function):
unwrap_function = cls.unwrap(function)
arg_spec = cls._get_arg_spec(unwrap_function)
argument_specification = cls._get_default_and_named_args(arg_spec, function)
argument_specification.extend(cls._get_var_args(arg_spec))
kw_only_args = cls._get_kw_only(arg_spec)
if kw_only_args:
argument_specification.extend(kw_only_args)
argument_specification = cls._get_args(arg_spec, function)
argument_specification.extend(cls._get_varargs(arg_spec))
argument_specification.extend(cls._get_named_only_args(arg_spec))
argument_specification.extend(cls._get_kwargs(arg_spec))
return argument_specification

@classmethod
def _get_arg_spec(cls, function):
def _get_arg_spec(cls, function: Callable):
return inspect.getfullargspec(function)

@classmethod
def _get_default_and_named_args(cls, arg_spec, function):
def _get_args(cls, arg_spec: inspect.FullArgSpec, function: Callable):
args = cls._drop_self_from_args(function, arg_spec)
args.reverse()
defaults = list(arg_spec.defaults) if arg_spec.defaults else []
Expand All @@ -223,33 +221,30 @@ def _get_default_and_named_args(cls, arg_spec, function):
return formated_args

@classmethod
def _drop_self_from_args(cls, function, arg_spec):
def _drop_self_from_args(cls, function: Callable, arg_spec: inspect.FullArgSpec):
return arg_spec.args[1:] if inspect.ismethod(function) else arg_spec.args

@classmethod
def _get_var_args(cls, arg_spec):
if arg_spec.varargs:
return [f"*{arg_spec.varargs}"]
return []
def _get_varargs(cls, arg_spec: inspect.FullArgSpec) -> list:
return [f"*{arg_spec.varargs}"] if arg_spec.varargs else []

@classmethod
def _get_kwargs(cls, arg_spec):
def _get_kwargs(cls, arg_spec: inspect.FullArgSpec) -> list:
return [f"**{arg_spec.varkw}"] if arg_spec.varkw else []

@classmethod
def _get_kw_only(cls, arg_spec):
kw_only_args = []
def _get_named_only_args(cls, arg_spec: inspect.FullArgSpec) -> list:
rf_spec = []
kw_only_args = arg_spec.kwonlyargs if arg_spec.kwonlyargs else []
if not arg_spec.varargs and kw_only_args:
rf_spec.append("*")
kw_only_defaults = arg_spec.kwonlydefaults if arg_spec.kwonlydefaults else []
for arg in arg_spec.kwonlyargs:
if not arg_spec.varargs and arg not in kw_only_defaults and not kw_only_args:
kw_only_args.append("*")
kw_only_args.append(arg)
elif arg not in kw_only_defaults:
kw_only_args.append(arg)
for kw_only_arg in kw_only_args:
if kw_only_arg in kw_only_defaults:
rf_spec.append((kw_only_arg, kw_only_defaults[kw_only_arg]))
else:
value = arg_spec.kwonlydefaults.get(arg, "")
kw_only_args.append((arg, value))
return kw_only_args
rf_spec.append(kw_only_arg)
return rf_spec

@classmethod
def _get_types(cls, function):
Expand Down
2 changes: 1 addition & 1 deletion utest/test_keyword_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def test_positional_and_named(lib):
assert spec.argument_specification == ["arg1", "arg2", ("named1", "string1"), ("named2", 123)]


def test_named_only(lib):
def test_named_only_default_only(lib):
spec = KeywordBuilder.build(lib.default_only)
assert spec.argument_specification == [("named1", "string1"), ("named2", 123)]

Expand Down
2 changes: 2 additions & 0 deletions utest/test_robotlibcore.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ def test_named_only_argumens():
assert args("kw_with_many_named_arguments") == ["*", "arg1", "arg2"]
assert args("kw_with_named_arguments_and_variable_number_args") == ["*varargs", "arg"]
assert args("kw_with_many_named_arguments_with_default") == ["*", "arg1", "arg2"]
assert args("kw_with_positional_and_named_arguments") == ["arg1", "*", "arg2"]
assert args("kw_with_positional_and_named_arguments_with_defaults") == [("arg1", 1), "*", ("arg2", "foobar")]


def test_get_keyword_documentation():
Expand Down

0 comments on commit 77cac53

Please sign in to comment.