From 91490aa641f0c3a7449a8838104ac77514a403d6 Mon Sep 17 00:00:00 2001 From: nightcityblade Date: Fri, 15 May 2026 11:28:42 +0800 Subject: [PATCH] fix: copy mutable file tuple containers Fixes anthropics/anthropic-sdk-python#1202 --- src/anthropic/_files.py | 14 ++++++++++++++ tests/test_files.py | 13 +++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/anthropic/_files.py b/src/anthropic/_files.py index 42cfbeb99..ba817bebd 100644 --- a/src/anthropic/_files.py +++ b/src/anthropic/_files.py @@ -170,4 +170,18 @@ def _deepcopy_with_paths(item: _T, paths: Sequence[Sequence[str]], index: int) - if not array_paths: return cast(_T, item) return cast(_T, [_deepcopy_with_paths(entry, array_paths, index + 1) for entry in item]) + if is_tuple_t(item): + tuple_item = cast(tuple[object, ...], item) + return cast(_T, _copy_file_container(tuple_item)) + return item + + +def _copy_file_container(item: object) -> object: + if is_mapping(item): + return {key: _copy_file_container(value) for key, value in item.items()} + if is_list(item): + return [_copy_file_container(entry) for entry in item] + if is_tuple_t(item): + entries = cast(tuple[object, ...], item) + return tuple(_copy_file_container(entry) for entry in entries) return item diff --git a/tests/test_files.py b/tests/test_files.py index cbef775f2..a9e9ebce4 100644 --- a/tests/test_files.py +++ b/tests/test_files.py @@ -91,6 +91,19 @@ def test_nested_array_path_copies_list_and_elements(self) -> None: assert_different_identities(result_items[0], elem1) assert_different_identities(result_items[1], elem2) + def test_copies_mutable_file_tuple_entries(self) -> None: + headers = {"x-test": "value"} + file = ("example.txt", b"contents", "text/plain", headers) + original = {"file": file} + + result = deepcopy_with_paths(original, [["file"]]) + + assert_different_identities(result, original) + result_file = result["file"] + assert_different_identities(result_file, file) + assert result_file[:3] == file[:3] + assert_different_identities(result_file[3], headers) + def test_empty_paths_returns_same_object(self) -> None: original = {"foo": "bar"} result = deepcopy_with_paths(original, [])