From e42f7fabe8ea1200cc2329f19de085d933384ba1 Mon Sep 17 00:00:00 2001 From: Joowon Date: Tue, 22 Aug 2023 07:54:02 +0900 Subject: [PATCH] Python fix native function default parameter (#2474) ### Motivation and Context solve #2473 and add unit test to prevent this from happening again. ### Description ### Contribution Checklist - [ ] The code builds clean without any errors or warnings - [ ] The PR follows the [SK Contribution Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md) and the [pre-submission formatting script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts) raises no violations - [ ] All unit tests pass, and I have added new tests where possible - [ ] I didn't break anyone :smile: --------- Co-authored-by: Abby Harrison <54643756+awharrison-28@users.noreply.github.com> --- .../orchestration/sk_function.py | 1 + .../orchestration/test_native_function.py | 100 ++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 python/tests/unit/orchestration/test_native_function.py diff --git a/python/semantic_kernel/orchestration/sk_function.py b/python/semantic_kernel/orchestration/sk_function.py index 94d3c0b84d..e9cfc87d9a 100644 --- a/python/semantic_kernel/orchestration/sk_function.py +++ b/python/semantic_kernel/orchestration/sk_function.py @@ -82,6 +82,7 @@ class SKFunction(SKFunctionBase): if ( hasattr(method, "__sk_function_input_description__") and method.__sk_function_input_description__ is not None + and method.__sk_function_input_description__ != "" ): input_param = ParameterView( "input", diff --git a/python/tests/unit/orchestration/test_native_function.py b/python/tests/unit/orchestration/test_native_function.py new file mode 100644 index 0000000000..6a133c0aaf --- /dev/null +++ b/python/tests/unit/orchestration/test_native_function.py @@ -0,0 +1,100 @@ +# Copyright (c) Microsoft. All rights reserved. + +from semantic_kernel.orchestration.sk_function import SKFunction +from semantic_kernel.skill_definition.sk_function_decorator import sk_function + + +def test_init_native_function_with_input_description(): + class MockMethodWithInputDescription: + __sk_function__ = True + __sk_function_name__ = "mock_function" + __sk_function_description__ = "Mock description" + __sk_function_input_description__ = "Mock input description" + __sk_function_input_default_value__ = "default_input_value" + __sk_function_context_parameters__ = [ + { + "name": "param1", + "description": "Param 1 description", + "default_value": "default_param1_value", + } + ] + + mock_method = MockMethodWithInputDescription + + native_function = SKFunction.from_native_method(mock_method, "MockSkill") + + assert native_function._function == mock_method + assert native_function._parameters[0].name == "input" + assert native_function._parameters[0].description == "Mock input description" + assert native_function._parameters[0].default_value == "default_input_value" + assert native_function._parameters[1].name == "param1" + assert native_function._parameters[1].description == "Param 1 description" + assert native_function._parameters[1].default_value == "default_param1_value" + + +def test_init_native_function_without_input_description(): + class MockMethodWithoutInputDescription: + __sk_function__ = True + __sk_function_name__ = "mock_function_no_input_desc" + __sk_function_description__ = "Mock description no input desc" + __sk_function_context_parameters__ = [ + { + "name": "param1", + "description": "Param 1 description", + "default_value": "default_param1_value", + } + ] + + mock_method = MockMethodWithoutInputDescription + + native_function = SKFunction.from_native_method(mock_method, "MockSkill") + + assert native_function._function == mock_method + assert native_function._parameters[0].name == "param1" + assert native_function._parameters[0].description == "Param 1 description" + assert native_function._parameters[0].default_value == "default_param1_value" + + +def test_init_native_function_from_sk_function_decorator(): + @sk_function( + description="Test description", + name="test_function", + input_description="Test input description", + input_default_value="test_default_value", + ) + def decorated_function(): + pass + + assert decorated_function.__sk_function__ is True + assert decorated_function.__sk_function_description__ == "Test description" + assert decorated_function.__sk_function_name__ == "test_function" + assert ( + decorated_function.__sk_function_input_description__ == "Test input description" + ) + assert ( + decorated_function.__sk_function_input_default_value__ == "test_default_value" + ) + + native_function = SKFunction.from_native_method(decorated_function, "MockSkill") + + assert native_function._function == decorated_function + assert native_function._parameters[0].name == "input" + assert native_function._parameters[0].description == "Test input description" + assert native_function._parameters[0].default_value == "test_default_value" + + +def test_init_native_function_from_sk_function_decorator_defaults(): + @sk_function() + def decorated_function(): + pass + + assert decorated_function.__sk_function__ is True + assert decorated_function.__sk_function_description__ == "" + assert decorated_function.__sk_function_name__ == "decorated_function" + assert decorated_function.__sk_function_input_description__ == "" + assert decorated_function.__sk_function_input_default_value__ == "" + + native_function = SKFunction.from_native_method(decorated_function, "MockSkill") + + assert native_function._function == decorated_function + assert len(native_function._parameters) == 0