diff --git a/src/anthropic/_files.py b/src/anthropic/_files.py index f2a6f94e..5bd0cb07 100644 --- a/src/anthropic/_files.py +++ b/src/anthropic/_files.py @@ -25,16 +25,14 @@ def is_base64_file_input(obj: object) -> TypeGuard[Base64FileInput]: def is_file_content(obj: object) -> TypeGuard[FileContent]: - return ( - isinstance(obj, bytes) or isinstance(obj, tuple) or isinstance(obj, io.IOBase) or isinstance(obj, os.PathLike) - ) + return isinstance(obj, bytes) or isinstance(obj, io.IOBase) or isinstance(obj, os.PathLike) def assert_is_file_content(obj: object, *, key: str | None = None) -> None: if not is_file_content(obj): prefix = f"Expected entry at `{key}`" if key is not None else f"Expected file input `{obj!r}`" raise RuntimeError( - f"{prefix} to be bytes, an io.IOBase instance, PathLike or a tuple but received {type(obj)} instead. See https://github.com/anthropics/anthropic-sdk-python/tree/main#file-uploads" + f"{prefix} to be bytes, an io.IOBase instance, or a PathLike but received {type(obj)} instead. See https://github.com/anthropics/anthropic-sdk-python/tree/main#file-uploads" ) from None diff --git a/tests/test_files.py b/tests/test_files.py index 4b118fe0..ead9e279 100644 --- a/tests/test_files.py +++ b/tests/test_files.py @@ -42,6 +42,17 @@ async def test_async_tuple_input() -> None: assert result == IsList(IsTuple("file", IsTuple("README.md", IsBytes()))) +def test_pathlike_in_tuple() -> None: + result = to_httpx_files({"file": ("custom_name.txt", readme_path, "text/plain")}) + assert result == IsDict({"file": IsTuple("custom_name.txt", IsBytes(), "text/plain")}) + + +@pytest.mark.asyncio +async def test_async_pathlike_in_tuple() -> None: + result = await async_to_httpx_files({"file": ("custom_name.txt", readme_path, "text/plain")}) + assert result == IsDict({"file": IsTuple("custom_name.txt", IsBytes(), "text/plain")}) + + def test_string_not_allowed() -> None: with pytest.raises(TypeError, match="Expected file types input to be a FileContent type or to be a tuple"): to_httpx_files(