33"""Tests for function_copy optimization (Issue #1: Lazy deepcopy)."""
44
55from unittest .mock import patch
6+
67import pytest
78
89from semantic_kernel .functions import kernel_function
@@ -15,61 +16,62 @@ def test_func(input: str) -> str:
1516 return f"Result: { input } "
1617
1718 from semantic_kernel .functions .kernel_function_from_method import KernelFunctionFromMethod
19+
1820 return KernelFunctionFromMethod (method = test_func , plugin_name = "test_plugin" )
1921
2022
2123class TestFunctionCopyOptimization :
2224 """Test suite for function_copy lazy deepcopy optimization."""
23-
25+
2426 def test_function_copy_same_plugin_no_deepcopy (self , sample_function ):
2527 """Test that function_copy doesn't deepcopy when plugin_name is same or None.
26-
28+
2729 This tests the optimization where metadata is reused when no plugin_name change.
2830 """
2931 original_plugin = sample_function .plugin_name
30-
32+
3133 # Case 1: No plugin_name provided (should reuse reference)
3234 copy1 = sample_function .function_copy ()
3335 assert copy1 .metadata is sample_function .metadata # Should be same reference
3436 assert copy1 .plugin_name == original_plugin
35-
37+
3638 # Case 2: Same plugin_name provided (should reuse reference)
3739 copy2 = sample_function .function_copy (original_plugin )
3840 assert copy2 .metadata is sample_function .metadata # Should be same reference
39-
41+
4042 def test_function_copy_different_plugin_creates_copy (self , sample_function ):
4143 """Test that function_copy does create a shallow copy when plugin_name changes.
42-
44+
4345 This tests that when we actually need to change the plugin_name,
4446 a shallow copy is created.
4547 """
4648 new_plugin_name = "new_plugin"
4749 copy = sample_function .function_copy (new_plugin_name )
48-
50+
4951 # Metadata should be different object (copied)
5052 assert copy .metadata is not sample_function .metadata
5153 # But should have the new plugin_name
5254 assert copy .metadata .plugin_name == new_plugin_name
5355 # Original should be unchanged
5456 assert sample_function .metadata .plugin_name != new_plugin_name
55-
57+
5658 def test_function_copy_preserves_function_behavior (self , sample_function ):
5759 """Test that copied function still works correctly."""
5860 copy = sample_function .function_copy ()
59-
61+
6062 # Verify function metadata is preserved
6163 assert copy .name == sample_function .name
6264 assert copy .description == sample_function .description
6365 # Verify function is callable (indirectly through having same underlying function)
64- assert hasattr (copy , ' invoke' )
65-
66+ assert hasattr (copy , " invoke" )
67+
6668 @patch (
67- ' semantic_kernel.functions.kernel_function.deepcopy' ,
68- side_effect = AssertionError ("deepcopy should not be called" )
69+ " semantic_kernel.functions.kernel_function.deepcopy" ,
70+ side_effect = AssertionError ("deepcopy should not be called" ),
6971 )
7072 def test_function_copy_no_unnecessary_deepcopy (self , mock_deepcopy , sample_function ):
7173 """Test that deepcopy is NOT called when plugin_name doesn't change.
72-
74+
7375 This is the key optimization test - it verifies that the old problematic
7476 deepcopy is not being called anymore.
7577 """
@@ -83,17 +85,17 @@ def test_function_copy_no_unnecessary_deepcopy(self, mock_deepcopy, sample_funct
8385 if "deepcopy should not be called" in str (e ):
8486 pytest .fail ("function_copy still calls deepcopy unnecessarily" )
8587 raise
86-
88+
8789 def test_function_copy_multiple_calls_same_plugin (self , sample_function ):
8890 """Test that multiple copies with same plugin reuse metadata.
89-
91+
9092 This tests the performance benefit of reusing metadata references
9193 when no change is needed.
9294 """
9395 copy1 = sample_function .function_copy ()
9496 copy2 = sample_function .function_copy ()
9597 copy3 = sample_function .function_copy (sample_function .plugin_name )
96-
98+
9799 # All should reference the same original metadata
98100 assert copy1 .metadata is sample_function .metadata
99101 assert copy2 .metadata is sample_function .metadata
0 commit comments