From 4eeaf2ddc931cfd488a6dc1f4c3972ab8451e632 Mon Sep 17 00:00:00 2001 From: Tatu Aalto Date: Tue, 14 Feb 2023 22:16:52 +0200 Subject: [PATCH] Fix named only arguments Fixes #111 --- atest/DynamicTypesAnnotationsLibrary.py | 16 ++++++++++++++++ atest/Python310Library.py | 1 + atest/tests.robot | 24 ++++++++++++------------ atest/tests_types.robot | 5 ++++- src/robotlibcore.py | 10 +++++++--- tasks.py | 6 ++++++ utest/test_get_keyword_types.py | 5 +++++ utest/test_robotlibcore.py | 7 +++++++ 8 files changed, 58 insertions(+), 16 deletions(-) diff --git a/atest/DynamicTypesAnnotationsLibrary.py b/atest/DynamicTypesAnnotationsLibrary.py index 7b536c4..be721f5 100644 --- a/atest/DynamicTypesAnnotationsLibrary.py +++ b/atest/DynamicTypesAnnotationsLibrary.py @@ -156,3 +156,19 @@ def keyword_optional_with_none(self, arg: Optional[str] = None): @keyword def keyword_union_with_none(self, arg: Union[None, Dict, str] = None): return f"arg: {arg}, type: {type(arg)}" + + @keyword + def kw_with_named_arguments(self, *, arg): + print(arg) + return f"arg: {arg}, type: {type(arg)}" + + @keyword + def kw_with_many_named_arguments(self, *, arg1, arg2): + print(arg1) + print(arg2) + return f"arg1: {arg1}, type: {type(arg1)}, arg2: {arg2}, type: {type(arg2)}" + + @keyword + def kw_with_named_arguments_and_variable_number_args(self, *varargs, arg): + print(arg) + return f"arg: {arg}, type: {type(arg)}" diff --git a/atest/Python310Library.py b/atest/Python310Library.py index d773b0b..5d8aeb3 100644 --- a/atest/Python310Library.py +++ b/atest/Python310Library.py @@ -2,6 +2,7 @@ from robotlibcore import DynamicCore, keyword + class Python310Library(DynamicCore): def __init__(self): diff --git a/atest/tests.robot b/atest/tests.robot index 962adeb..3099c07 100644 --- a/atest/tests.robot +++ b/atest/tests.robot @@ -7,14 +7,14 @@ ${LIBRARY} DynamicLibrary *** Test Cases *** -Keyword names - Keyword in main +Keyword Names + Keyword In Main Function FUNCTION Method - Custom name - Cust omna me - IF $LIBRARY == "ExtendExistingLibrary" Keyword in extending library + Custom Name + Cust Omna Me + IF $LIBRARY == "ExtendExistingLibrary" Keyword In Extending Library Method without @keyword are not keyowrds [Documentation] FAIL GLOB: No keyword with name 'Not keyword' found.* @@ -27,27 +27,27 @@ Arguments 'foo', 2, 3 Defaults foo ${2} 'a', 'b', 'c' Defaults a b c -Named arguments +Named Arguments [Template] Return value should be 'foo', 'bar' Mandatory foo arg2=bar '1', 2 Mandatory arg2=${2} arg1=1 'x', 'default', 'y' Defaults x arg3=y -Varargs and kwargs +Varargs And Kwargs [Template] Return value should be ${EMPTY} Varargs and kwargs 'a', 'b', 'c' Varargs and kwargs a b c a\='1', b\=2 Varargs and kwargs a=1 b=${2} 'a', 'b\=b', c\='c' Varargs and kwargs a b\=b c=c -Embedded arguments - [Documentation] FAIL Work but this fails - Embedded arguments "work" - embeDded ArgumeNtS "Work but this fails" +Embedded Arguments + [Documentation] FAIL Work But This Fails + Embedded Arguments "work" + EmbeDded ArgumeNtS "Work But This Fails" *** Keywords *** -Return value should be +Return Value Should Be [Arguments] ${expected} ${keyword} @{args} &{kwargs} ${result} Run Keyword ${keyword} @{args} &{kwargs} Should Be Equal ${result} ${expected} diff --git a/atest/tests_types.robot b/atest/tests_types.robot index 3337617..23a20fb 100644 --- a/atest/tests_types.robot +++ b/atest/tests_types.robot @@ -52,7 +52,7 @@ Keyword Only Arguments Without VarArg ${return} = DynamicTypesAnnotationsLibrary.Keyword Only Arguments No Vararg other=tidii Should Match ${return} tidii: -Varargs and KeywordArgs With Typing Hints +Varargs And KeywordArgs With Typing Hints ${return} = DynamicTypesAnnotationsLibrary.Keyword Self And Keyword Only Types ... this_is_mandatory # mandatory argument ... 1 2 3 4 # varargs @@ -112,6 +112,9 @@ Python 3.10 New Type Hints Should Be Equal ${types} arg: {"key": 1}, type: END +Keyword With Named Only Arguments + Kw With Named Arguments arg=1 + *** Keywords *** Import DynamicTypesAnnotationsLibrary In Python 3.10 Only diff --git a/src/robotlibcore.py b/src/robotlibcore.py index f95d292..d03619a 100644 --- a/src/robotlibcore.py +++ b/src/robotlibcore.py @@ -229,18 +229,22 @@ def _drop_self_from_args(cls, function, arg_spec): @classmethod def _get_var_args(cls, arg_spec): if arg_spec.varargs: - return ["*%s" % arg_spec.varargs] + return [f"*{arg_spec.varargs}"] return [] @classmethod def _get_kwargs(cls, arg_spec): - return ["**%s" % arg_spec.varkw] if arg_spec.varkw else [] + return [f"**{arg_spec.varkw}"] if arg_spec.varkw else [] @classmethod def _get_kw_only(cls, arg_spec): kw_only_args = [] + kw_only_defaults = arg_spec.kwonlydefaults if arg_spec.kwonlydefaults else [] for arg in arg_spec.kwonlyargs: - if not arg_spec.kwonlydefaults or arg not in arg_spec.kwonlydefaults: + 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) else: value = arg_spec.kwonlydefaults.get(arg, "") diff --git a/tasks.py b/tasks.py index 6d3b45f..140368d 100644 --- a/tasks.py +++ b/tasks.py @@ -132,6 +132,12 @@ def lint(ctx): print(f"Lint Robot files {'in ci' if in_ci else ''}") command = [ "robotidy", + "--transform", + "RenameKeywords", + "--transform", + "RenameTestCases", + "-c", + "RenameTestCases:capitalize_each_word=True", "--lineseparator", "unix", "atest/", diff --git a/utest/test_get_keyword_types.py b/utest/test_get_keyword_types.py index d072f9e..9d790c9 100644 --- a/utest/test_get_keyword_types.py +++ b/utest/test_get_keyword_types.py @@ -192,3 +192,8 @@ def test_keyword_optional_with_none(lib_types): def test_keyword_union_with_none(lib_types): types = lib_types.get_keyword_types("keyword_union_with_none") assert types == {"arg": typing.Union[type(None), typing.Dict, str]} + + +def test_kw_with_named_arguments(lib_types: DynamicTypesAnnotationsLibrary): + types = lib_types.get_keyword_types("kw_with_named_arguments") + assert types == {} diff --git a/utest/test_robotlibcore.py b/utest/test_robotlibcore.py index 1011c13..440a67b 100644 --- a/utest/test_robotlibcore.py +++ b/utest/test_robotlibcore.py @@ -132,6 +132,13 @@ def test_keyword_only_arguments_for_get_keyword_arguments(): assert args("keyword_with_deco_and_signature") == [("arg1", False), ("arg2", False)] +def test_named_only_argumens(): + args = DynamicTypesAnnotationsLibrary(1).get_keyword_arguments + assert args("kw_with_named_arguments") == ["*", "arg"] + assert args("kw_with_many_named_arguments") == ["*", "arg1", "arg2"] + assert args("kw_with_named_arguments_and_variable_number_args") == ["*varargs", "arg"] + + def test_get_keyword_documentation(): doc = DynamicLibrary().get_keyword_documentation assert doc("function") == ""