diff --git a/api.md b/api.md index e0237803de..a7ee177411 100644 --- a/api.md +++ b/api.md @@ -87,6 +87,7 @@ Methods: - client.files.retrieve(file_id) -> FileObject - client.files.list(\*\*params) -> SyncPage[FileObject] - client.files.delete(file_id) -> FileDeleted +- client.files.content(file_id) -> HttpxBinaryResponseContent - client.files.retrieve_content(file_id) -> str - client.files.wait_for_processing(\*args) -> FileObject diff --git a/src/openai/resources/files.py b/src/openai/resources/files.py index b317845c3a..a6f75e5a4c 100644 --- a/src/openai/resources/files.py +++ b/src/openai/resources/files.py @@ -3,6 +3,7 @@ from __future__ import annotations import time +import typing_extensions from typing import TYPE_CHECKING, Mapping, cast from typing_extensions import Literal @@ -14,7 +15,11 @@ from .._resource import SyncAPIResource, AsyncAPIResource from .._response import to_raw_response_wrapper, async_to_raw_response_wrapper from ..pagination import SyncPage, AsyncPage -from .._base_client import AsyncPaginator, make_request_options +from .._base_client import ( + AsyncPaginator, + HttpxBinaryResponseContent, + make_request_options, +) if TYPE_CHECKING: from .._client import OpenAI, AsyncOpenAI @@ -197,6 +202,38 @@ def delete( cast_to=FileDeleted, ) + def content( + self, + file_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> HttpxBinaryResponseContent: + """ + Returns the contents of the specified file. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + f"/files/{file_id}/content", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=HttpxBinaryResponseContent, + ) + + @typing_extensions.deprecated("The `.content()` method should be used instead") def retrieve_content( self, file_id: str, @@ -428,6 +465,38 @@ async def delete( cast_to=FileDeleted, ) + async def content( + self, + file_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> HttpxBinaryResponseContent: + """ + Returns the contents of the specified file. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + f"/files/{file_id}/content", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=HttpxBinaryResponseContent, + ) + + @typing_extensions.deprecated("The `.content()` method should be used instead") async def retrieve_content( self, file_id: str, @@ -498,8 +567,11 @@ def __init__(self, files: Files) -> None: self.delete = to_raw_response_wrapper( files.delete, ) - self.retrieve_content = to_raw_response_wrapper( - files.retrieve_content, + self.content = to_raw_response_wrapper( + files.content, + ) + self.retrieve_content = to_raw_response_wrapper( # pyright: ignore[reportDeprecated] + files.retrieve_content # pyright: ignore[reportDeprecated], ) @@ -517,6 +589,9 @@ def __init__(self, files: AsyncFiles) -> None: self.delete = async_to_raw_response_wrapper( files.delete, ) - self.retrieve_content = async_to_raw_response_wrapper( - files.retrieve_content, + self.content = async_to_raw_response_wrapper( + files.content, + ) + self.retrieve_content = async_to_raw_response_wrapper( # pyright: ignore[reportDeprecated] + files.retrieve_content # pyright: ignore[reportDeprecated], ) diff --git a/tests/api_resources/test_files.py b/tests/api_resources/test_files.py index d668c2d0c7..a2c9d07314 100644 --- a/tests/api_resources/test_files.py +++ b/tests/api_resources/test_files.py @@ -4,14 +4,19 @@ import os +import httpx import pytest +from respx import MockRouter from openai import OpenAI, AsyncOpenAI from tests.utils import assert_matches_type from openai.types import FileObject, FileDeleted +from openai._types import BinaryResponseContent from openai._client import OpenAI, AsyncOpenAI from openai.pagination import SyncPage, AsyncPage +# pyright: reportDeprecated=false + base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") api_key = "My API Key" @@ -91,19 +96,43 @@ def test_raw_response_delete(self, client: OpenAI) -> None: assert_matches_type(FileDeleted, file, path=["response"]) @parametrize - def test_method_retrieve_content(self, client: OpenAI) -> None: - file = client.files.retrieve_content( + @pytest.mark.respx(base_url=base_url) + def test_method_content(self, client: OpenAI, respx_mock: MockRouter) -> None: + respx_mock.get("/files/{file_id}/content").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + file = client.files.content( "string", ) - assert_matches_type(str, file, path=["response"]) + assert isinstance(file, BinaryResponseContent) + assert file.json() == {"foo": "bar"} @parametrize - def test_raw_response_retrieve_content(self, client: OpenAI) -> None: - response = client.files.with_raw_response.retrieve_content( + @pytest.mark.respx(base_url=base_url) + def test_raw_response_content(self, client: OpenAI, respx_mock: MockRouter) -> None: + respx_mock.get("/files/{file_id}/content").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + response = client.files.with_raw_response.content( "string", ) assert response.http_request.headers.get("X-Stainless-Lang") == "python" file = response.parse() + assert isinstance(file, BinaryResponseContent) + assert file.json() == {"foo": "bar"} + + @parametrize + def test_method_retrieve_content(self, client: OpenAI) -> None: + with pytest.warns(DeprecationWarning): + file = client.files.retrieve_content( + "string", + ) + assert_matches_type(str, file, path=["response"]) + + @parametrize + def test_raw_response_retrieve_content(self, client: OpenAI) -> None: + with pytest.warns(DeprecationWarning): + response = client.files.with_raw_response.retrieve_content( + "string", + ) + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file = response.parse() assert_matches_type(str, file, path=["response"]) @@ -182,17 +211,41 @@ async def test_raw_response_delete(self, client: AsyncOpenAI) -> None: assert_matches_type(FileDeleted, file, path=["response"]) @parametrize - async def test_method_retrieve_content(self, client: AsyncOpenAI) -> None: - file = await client.files.retrieve_content( + @pytest.mark.respx(base_url=base_url) + async def test_method_content(self, client: AsyncOpenAI, respx_mock: MockRouter) -> None: + respx_mock.get("/files/{file_id}/content").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + file = await client.files.content( "string", ) - assert_matches_type(str, file, path=["response"]) + assert isinstance(file, BinaryResponseContent) + assert file.json() == {"foo": "bar"} @parametrize - async def test_raw_response_retrieve_content(self, client: AsyncOpenAI) -> None: - response = await client.files.with_raw_response.retrieve_content( + @pytest.mark.respx(base_url=base_url) + async def test_raw_response_content(self, client: AsyncOpenAI, respx_mock: MockRouter) -> None: + respx_mock.get("/files/{file_id}/content").mock(return_value=httpx.Response(200, json={"foo": "bar"})) + response = await client.files.with_raw_response.content( "string", ) assert response.http_request.headers.get("X-Stainless-Lang") == "python" file = response.parse() + assert isinstance(file, BinaryResponseContent) + assert file.json() == {"foo": "bar"} + + @parametrize + async def test_method_retrieve_content(self, client: AsyncOpenAI) -> None: + with pytest.warns(DeprecationWarning): + file = await client.files.retrieve_content( + "string", + ) + assert_matches_type(str, file, path=["response"]) + + @parametrize + async def test_raw_response_retrieve_content(self, client: AsyncOpenAI) -> None: + with pytest.warns(DeprecationWarning): + response = await client.files.with_raw_response.retrieve_content( + "string", + ) + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file = response.parse() assert_matches_type(str, file, path=["response"])