diff --git a/src/anthropic/_utils/_utils.py b/src/anthropic/_utils/_utils.py index eec7f4a1..d66ea71d 100644 --- a/src/anthropic/_utils/_utils.py +++ b/src/anthropic/_utils/_utils.py @@ -181,6 +181,7 @@ def deepcopy_minimal(item: _T) -> _T: - mappings, e.g. `dict` - list + - tuple This is done for performance reasons. """ @@ -188,6 +189,8 @@ def deepcopy_minimal(item: _T) -> _T: return cast(_T, {k: deepcopy_minimal(v) for k, v in item.items()}) if is_list(item): return cast(_T, [deepcopy_minimal(entry) for entry in item]) + if is_tuple(item): + return cast(_T, tuple(deepcopy_minimal(entry) for entry in item)) return item diff --git a/tests/test_deepcopy.py b/tests/test_deepcopy.py index edbbfb22..03d2bd71 100644 --- a/tests/test_deepcopy.py +++ b/tests/test_deepcopy.py @@ -41,6 +41,22 @@ def test_nested_list() -> None: assert_different_identities(obj1[1], obj2[1]) +def test_simple_tuple() -> None: + obj1 = ("a", "b") + obj2 = deepcopy_minimal(obj1) + assert_different_identities(obj1, obj2) + assert obj1[0] is obj2[0] # immutable strings are same object + assert obj1[1] is obj2[1] + + +def test_nested_tuple() -> None: + obj1 = ("a", {"bar": True}) + obj2 = deepcopy_minimal(obj1) + assert_different_identities(obj1, obj2) + assert_different_identities(obj1[1], obj2[1]) + assert obj1[0] is obj2[0] # immutable string preserved + + class MyObject: ... @@ -52,7 +68,18 @@ def test_ignores_other_types() -> None: assert_different_identities(obj1, obj2) assert obj1["foo"] is my_obj - # tuples - obj3 = ("a", "b") - obj4 = deepcopy_minimal(obj3) - assert obj3 is obj4 + # tuples with lists inside - list should be copied + inner_list = [1, {"x": "y"}] + obj7 = ("z", inner_list) + obj8 = deepcopy_minimal(obj7) + assert obj7 is not obj8 # new tuple created + assert obj7[1] is not obj8[1] # list inside is copied + assert obj7[1][1] is not obj8[1][1] # dict inside that list is also copied + + # deeply nested: tuple -> dict -> list -> dict + obj9 = ({"items": [{"name": "a"}]},) + obj10 = deepcopy_minimal(obj9) + assert obj9 is not obj10 + assert obj9[0] is not obj10[0] # dict in tuple copied + assert obj9[0]["items"] is not obj10[0]["items"] # list in dict copied + assert obj9[0]["items"][0] is not obj10[0]["items"][0] # dict in list copied