diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 3a5058bfce..c0ae4d87db 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.29.0" + ".": "2.29.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index eea76f7709..2599343942 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## 2.29.1 (2026-03-21) + +Full Changelog: [v2.29.0...v2.29.1](https://github.com/openai/openai-python/compare/v2.29.0...v2.29.1) + +### Bug Fixes + +* sanitize endpoint path params ([89f6698](https://github.com/openai/openai-python/commit/89f66988fde790c0c83ff8b876d1e1b10d616367)) + + +### Chores + +* **tests:** bump steady to v0.19.4 ([f350af8](https://github.com/openai/openai-python/commit/f350af86c13ade0237778010d264c55fda443354)) +* **tests:** bump steady to v0.19.5 ([5c03401](https://github.com/openai/openai-python/commit/5c0340128fc1a416e2dfdc6ab4b05f1e954e8482)) + + +### Refactors + +* **tests:** switch from prism to steady ([4a82035](https://github.com/openai/openai-python/commit/4a82035669b739d16a0e85d4ded778d51e061948)) + ## 2.29.0 (2026-03-17) Full Changelog: [v2.28.0...v2.29.0](https://github.com/openai/openai-python/compare/v2.28.0...v2.29.0) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3a1cf70bb8..253b9ce5e6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -85,7 +85,7 @@ $ pip install ./path-to-wheel-file.whl ## Running tests -Most tests require you to [set up a mock server](https://github.com/stoplightio/prism) against the OpenAPI spec to run the tests. +Most tests require you to [set up a mock server](https://github.com/dgellow/steady) against the OpenAPI spec to run the tests. ```sh $ ./scripts/mock diff --git a/pyproject.toml b/pyproject.toml index 46a72007df..4205e2f109 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.29.0" +version = "2.29.1" description = "The official Python library for the openai API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/scripts/mock b/scripts/mock index bcf3b392b3..4f7dfd12b4 100755 --- a/scripts/mock +++ b/scripts/mock @@ -19,34 +19,34 @@ fi echo "==> Starting mock server with URL ${URL}" -# Run prism mock on the given spec +# Run steady mock on the given spec if [ "$1" == "--daemon" ]; then # Pre-install the package so the download doesn't eat into the startup timeout - npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism --version + npm exec --package=@stdy/cli@0.19.5 -- steady --version - npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" &> .prism.log & + npm exec --package=@stdy/cli@0.19.5 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=brackets --validator-query-array-format=brackets --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" &> .stdy.log & - # Wait for server to come online (max 30s) + # Wait for server to come online via health endpoint (max 30s) echo -n "Waiting for server" attempts=0 - while ! grep -q "✖ fatal\|Prism is listening" ".prism.log" ; do + while ! curl --silent --fail "http://127.0.0.1:4010/_x-steady/health" >/dev/null 2>&1; do + if ! kill -0 $! 2>/dev/null; then + echo + cat .stdy.log + exit 1 + fi attempts=$((attempts + 1)) if [ "$attempts" -ge 300 ]; then echo - echo "Timed out waiting for Prism server to start" - cat .prism.log + echo "Timed out waiting for Steady server to start" + cat .stdy.log exit 1 fi echo -n "." sleep 0.1 done - if grep -q "✖ fatal" ".prism.log"; then - cat .prism.log - exit 1 - fi - echo else - npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" + npm exec --package=@stdy/cli@0.19.5 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=brackets --validator-query-array-format=brackets --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" fi diff --git a/scripts/test b/scripts/test index dbeda2d217..3861edc6d1 100755 --- a/scripts/test +++ b/scripts/test @@ -9,8 +9,8 @@ GREEN='\033[0;32m' YELLOW='\033[0;33m' NC='\033[0m' # No Color -function prism_is_running() { - curl --silent "http://localhost:4010" >/dev/null 2>&1 +function steady_is_running() { + curl --silent "http://127.0.0.1:4010/_x-steady/health" >/dev/null 2>&1 } kill_server_on_port() { @@ -25,7 +25,7 @@ function is_overriding_api_base_url() { [ -n "$TEST_API_BASE_URL" ] } -if ! is_overriding_api_base_url && ! prism_is_running ; then +if ! is_overriding_api_base_url && ! steady_is_running ; then # When we exit this script, make sure to kill the background mock server process trap 'kill_server_on_port 4010' EXIT @@ -36,19 +36,19 @@ fi if is_overriding_api_base_url ; then echo -e "${GREEN}✔ Running tests against ${TEST_API_BASE_URL}${NC}" echo -elif ! prism_is_running ; then - echo -e "${RED}ERROR:${NC} The test suite will not run without a mock Prism server" +elif ! steady_is_running ; then + echo -e "${RED}ERROR:${NC} The test suite will not run without a mock Steady server" echo -e "running against your OpenAPI spec." echo echo -e "To run the server, pass in the path or url of your OpenAPI" - echo -e "spec to the prism command:" + echo -e "spec to the steady command:" echo - echo -e " \$ ${YELLOW}npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock path/to/your.openapi.yml${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.5 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-form-array-format=brackets --validator-query-array-format=brackets --validator-form-object-format=brackets --validator-query-object-format=brackets${NC}" echo exit 1 else - echo -e "${GREEN}✔ Mock prism server is running with your OpenAPI spec${NC}" + echo -e "${GREEN}✔ Mock steady server is running with your OpenAPI spec${NC}" echo fi diff --git a/src/openai/_utils/__init__.py b/src/openai/_utils/__init__.py index 963c83b6d4..52853aaf03 100644 --- a/src/openai/_utils/__init__.py +++ b/src/openai/_utils/__init__.py @@ -1,4 +1,5 @@ from ._logs import SensitiveHeadersFilter as SensitiveHeadersFilter +from ._path import path_template as path_template from ._sync import asyncify as asyncify from ._proxy import LazyProxy as LazyProxy from ._utils import ( diff --git a/src/openai/_utils/_path.py b/src/openai/_utils/_path.py new file mode 100644 index 0000000000..4d6e1e4cbc --- /dev/null +++ b/src/openai/_utils/_path.py @@ -0,0 +1,127 @@ +from __future__ import annotations + +import re +from typing import ( + Any, + Mapping, + Callable, +) +from urllib.parse import quote + +# Matches '.' or '..' where each dot is either literal or percent-encoded (%2e / %2E). +_DOT_SEGMENT_RE = re.compile(r"^(?:\.|%2[eE]){1,2}$") + +_PLACEHOLDER_RE = re.compile(r"\{(\w+)\}") + + +def _quote_path_segment_part(value: str) -> str: + """Percent-encode `value` for use in a URI path segment. + + Considers characters not in `pchar` set from RFC 3986 §3.3 to be unsafe. + https://datatracker.ietf.org/doc/html/rfc3986#section-3.3 + """ + # quote() already treats unreserved characters (letters, digits, and -._~) + # as safe, so we only need to add sub-delims, ':', and '@'. + # Notably, unlike the default `safe` for quote(), / is unsafe and must be quoted. + return quote(value, safe="!$&'()*+,;=:@") + + +def _quote_query_part(value: str) -> str: + """Percent-encode `value` for use in a URI query string. + + Considers &, = and characters not in `query` set from RFC 3986 §3.4 to be unsafe. + https://datatracker.ietf.org/doc/html/rfc3986#section-3.4 + """ + return quote(value, safe="!$'()*+,;:@/?") + + +def _quote_fragment_part(value: str) -> str: + """Percent-encode `value` for use in a URI fragment. + + Considers characters not in `fragment` set from RFC 3986 §3.5 to be unsafe. + https://datatracker.ietf.org/doc/html/rfc3986#section-3.5 + """ + return quote(value, safe="!$&'()*+,;=:@/?") + + +def _interpolate( + template: str, + values: Mapping[str, Any], + quoter: Callable[[str], str], +) -> str: + """Replace {name} placeholders in `template`, quoting each value with `quoter`. + + Placeholder names are looked up in `values`. + + Raises: + KeyError: If a placeholder is not found in `values`. + """ + # re.split with a capturing group returns alternating + # [text, name, text, name, ..., text] elements. + parts = _PLACEHOLDER_RE.split(template) + + for i in range(1, len(parts), 2): + name = parts[i] + if name not in values: + raise KeyError(f"a value for placeholder {{{name}}} was not provided") + val = values[name] + if val is None: + parts[i] = "null" + elif isinstance(val, bool): + parts[i] = "true" if val else "false" + else: + parts[i] = quoter(str(values[name])) + + return "".join(parts) + + +def path_template(template: str, /, **kwargs: Any) -> str: + """Interpolate {name} placeholders in `template` from keyword arguments. + + Args: + template: The template string containing {name} placeholders. + **kwargs: Keyword arguments to interpolate into the template. + + Returns: + The template with placeholders interpolated and percent-encoded. + + Safe characters for percent-encoding are dependent on the URI component. + Placeholders in path and fragment portions are percent-encoded where the `segment` + and `fragment` sets from RFC 3986 respectively are considered safe. + Placeholders in the query portion are percent-encoded where the `query` set from + RFC 3986 §3.3 is considered safe except for = and & characters. + + Raises: + KeyError: If a placeholder is not found in `kwargs`. + ValueError: If resulting path contains /./ or /../ segments (including percent-encoded dot-segments). + """ + # Split the template into path, query, and fragment portions. + fragment_template: str | None = None + query_template: str | None = None + + rest = template + if "#" in rest: + rest, fragment_template = rest.split("#", 1) + if "?" in rest: + rest, query_template = rest.split("?", 1) + path_template = rest + + # Interpolate each portion with the appropriate quoting rules. + path_result = _interpolate(path_template, kwargs, _quote_path_segment_part) + + # Reject dot-segments (. and ..) in the final assembled path. The check + # runs after interpolation so that adjacent placeholders or a mix of static + # text and placeholders that together form a dot-segment are caught. + # Also reject percent-encoded dot-segments to protect against incorrectly + # implemented normalization in servers/proxies. + for segment in path_result.split("/"): + if _DOT_SEGMENT_RE.match(segment): + raise ValueError(f"Constructed path {path_result!r} contains dot-segment {segment!r} which is not allowed") + + result = path_result + if query_template is not None: + result += "?" + _interpolate(query_template, kwargs, _quote_query_part) + if fragment_template is not None: + result += "#" + _interpolate(fragment_template, kwargs, _quote_fragment_part) + + return result diff --git a/src/openai/_version.py b/src/openai/_version.py index b8a1b37e13..cee5635d27 100644 --- a/src/openai/_version.py +++ b/src/openai/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "openai" -__version__ = "2.29.0" # x-release-please-version +__version__ = "2.29.1" # x-release-please-version diff --git a/src/openai/resources/batches.py b/src/openai/resources/batches.py index c269b93e2c..6cdb50c280 100644 --- a/src/openai/resources/batches.py +++ b/src/openai/resources/batches.py @@ -10,7 +10,7 @@ from .. import _legacy_response from ..types import batch_list_params, batch_create_params from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from .._utils import maybe_transform, async_maybe_transform +from .._utils import path_template, maybe_transform, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -154,7 +154,7 @@ def retrieve( if not batch_id: raise ValueError(f"Expected a non-empty value for `batch_id` but received {batch_id!r}") return self._get( - f"/batches/{batch_id}", + path_template("/batches/{batch_id}", batch_id=batch_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -242,7 +242,7 @@ def cancel( if not batch_id: raise ValueError(f"Expected a non-empty value for `batch_id` but received {batch_id!r}") return self._post( - f"/batches/{batch_id}/cancel", + path_template("/batches/{batch_id}/cancel", batch_id=batch_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -382,7 +382,7 @@ async def retrieve( if not batch_id: raise ValueError(f"Expected a non-empty value for `batch_id` but received {batch_id!r}") return await self._get( - f"/batches/{batch_id}", + path_template("/batches/{batch_id}", batch_id=batch_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -470,7 +470,7 @@ async def cancel( if not batch_id: raise ValueError(f"Expected a non-empty value for `batch_id` but received {batch_id!r}") return await self._post( - f"/batches/{batch_id}/cancel", + path_template("/batches/{batch_id}/cancel", batch_id=batch_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/beta/assistants.py b/src/openai/resources/beta/assistants.py index bf22122553..7ea8a918ca 100644 --- a/src/openai/resources/beta/assistants.py +++ b/src/openai/resources/beta/assistants.py @@ -10,7 +10,7 @@ from ... import _legacy_response from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform +from ..._utils import path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -215,7 +215,7 @@ def retrieve( raise ValueError(f"Expected a non-empty value for `assistant_id` but received {assistant_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get( - f"/assistants/{assistant_id}", + path_template("/assistants/{assistant_id}", assistant_id=assistant_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -383,7 +383,7 @@ def update( raise ValueError(f"Expected a non-empty value for `assistant_id` but received {assistant_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( - f"/assistants/{assistant_id}", + path_template("/assistants/{assistant_id}", assistant_id=assistant_id), body=maybe_transform( { "description": description, @@ -500,7 +500,7 @@ def delete( raise ValueError(f"Expected a non-empty value for `assistant_id` but received {assistant_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._delete( - f"/assistants/{assistant_id}", + path_template("/assistants/{assistant_id}", assistant_id=assistant_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -691,7 +691,7 @@ async def retrieve( raise ValueError(f"Expected a non-empty value for `assistant_id` but received {assistant_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._get( - f"/assistants/{assistant_id}", + path_template("/assistants/{assistant_id}", assistant_id=assistant_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -859,7 +859,7 @@ async def update( raise ValueError(f"Expected a non-empty value for `assistant_id` but received {assistant_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( - f"/assistants/{assistant_id}", + path_template("/assistants/{assistant_id}", assistant_id=assistant_id), body=await async_maybe_transform( { "description": description, @@ -976,7 +976,7 @@ async def delete( raise ValueError(f"Expected a non-empty value for `assistant_id` but received {assistant_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._delete( - f"/assistants/{assistant_id}", + path_template("/assistants/{assistant_id}", assistant_id=assistant_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/beta/chatkit/sessions.py b/src/openai/resources/beta/chatkit/sessions.py index abfa496a56..6e95fd65fb 100644 --- a/src/openai/resources/beta/chatkit/sessions.py +++ b/src/openai/resources/beta/chatkit/sessions.py @@ -6,7 +6,7 @@ from .... import _legacy_response from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import maybe_transform, async_maybe_transform +from ...._utils import path_template, maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -134,7 +134,7 @@ def cancel( raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} return self._post( - f"/chatkit/sessions/{session_id}/cancel", + path_template("/chatkit/sessions/{session_id}/cancel", session_id=session_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -249,7 +249,7 @@ async def cancel( raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} return await self._post( - f"/chatkit/sessions/{session_id}/cancel", + path_template("/chatkit/sessions/{session_id}/cancel", session_id=session_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/beta/chatkit/threads.py b/src/openai/resources/beta/chatkit/threads.py index 7a2d4c4a30..16e0e11a0a 100644 --- a/src/openai/resources/beta/chatkit/threads.py +++ b/src/openai/resources/beta/chatkit/threads.py @@ -9,7 +9,7 @@ from .... import _legacy_response from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import maybe_transform +from ...._utils import path_template, maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -70,7 +70,7 @@ def retrieve( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} return self._get( - f"/chatkit/threads/{thread_id}", + path_template("/chatkit/threads/{thread_id}", thread_id=thread_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -167,7 +167,7 @@ def delete( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} return self._delete( - f"/chatkit/threads/{thread_id}", + path_template("/chatkit/threads/{thread_id}", thread_id=thread_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -215,7 +215,7 @@ def list_items( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} return self._get_api_list( - f"/chatkit/threads/{thread_id}/items", + path_template("/chatkit/threads/{thread_id}/items", thread_id=thread_id), page=SyncConversationCursorPage[Data], options=make_request_options( extra_headers=extra_headers, @@ -283,7 +283,7 @@ async def retrieve( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} return await self._get( - f"/chatkit/threads/{thread_id}", + path_template("/chatkit/threads/{thread_id}", thread_id=thread_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -380,7 +380,7 @@ async def delete( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} return await self._delete( - f"/chatkit/threads/{thread_id}", + path_template("/chatkit/threads/{thread_id}", thread_id=thread_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -428,7 +428,7 @@ def list_items( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "chatkit_beta=v1", **(extra_headers or {})} return self._get_api_list( - f"/chatkit/threads/{thread_id}/items", + path_template("/chatkit/threads/{thread_id}/items", thread_id=thread_id), page=AsyncConversationCursorPage[Data], options=make_request_options( extra_headers=extra_headers, diff --git a/src/openai/resources/beta/threads/messages.py b/src/openai/resources/beta/threads/messages.py index e783310933..95b750d4e4 100644 --- a/src/openai/resources/beta/threads/messages.py +++ b/src/openai/resources/beta/threads/messages.py @@ -10,7 +10,7 @@ from .... import _legacy_response from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import maybe_transform, async_maybe_transform +from ...._utils import path_template, maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -101,7 +101,7 @@ def create( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( - f"/threads/{thread_id}/messages", + path_template("/threads/{thread_id}/messages", thread_id=thread_id), body=maybe_transform( { "content": content, @@ -148,7 +148,7 @@ def retrieve( raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get( - f"/threads/{thread_id}/messages/{message_id}", + path_template("/threads/{thread_id}/messages/{message_id}", thread_id=thread_id, message_id=message_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -194,7 +194,7 @@ def update( raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( - f"/threads/{thread_id}/messages/{message_id}", + path_template("/threads/{thread_id}/messages/{message_id}", thread_id=thread_id, message_id=message_id), body=maybe_transform({"metadata": metadata}, message_update_params.MessageUpdateParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -253,7 +253,7 @@ def list( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( - f"/threads/{thread_id}/messages", + path_template("/threads/{thread_id}/messages", thread_id=thread_id), page=SyncCursorPage[Message], options=make_request_options( extra_headers=extra_headers, @@ -305,7 +305,7 @@ def delete( raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._delete( - f"/threads/{thread_id}/messages/{message_id}", + path_template("/threads/{thread_id}/messages/{message_id}", thread_id=thread_id, message_id=message_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -386,7 +386,7 @@ async def create( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( - f"/threads/{thread_id}/messages", + path_template("/threads/{thread_id}/messages", thread_id=thread_id), body=await async_maybe_transform( { "content": content, @@ -433,7 +433,7 @@ async def retrieve( raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._get( - f"/threads/{thread_id}/messages/{message_id}", + path_template("/threads/{thread_id}/messages/{message_id}", thread_id=thread_id, message_id=message_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -479,7 +479,7 @@ async def update( raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( - f"/threads/{thread_id}/messages/{message_id}", + path_template("/threads/{thread_id}/messages/{message_id}", thread_id=thread_id, message_id=message_id), body=await async_maybe_transform({"metadata": metadata}, message_update_params.MessageUpdateParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -538,7 +538,7 @@ def list( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( - f"/threads/{thread_id}/messages", + path_template("/threads/{thread_id}/messages", thread_id=thread_id), page=AsyncCursorPage[Message], options=make_request_options( extra_headers=extra_headers, @@ -590,7 +590,7 @@ async def delete( raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._delete( - f"/threads/{thread_id}/messages/{message_id}", + path_template("/threads/{thread_id}/messages/{message_id}", thread_id=thread_id, message_id=message_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/beta/threads/runs/runs.py b/src/openai/resources/beta/threads/runs/runs.py index 20862185d2..882e88dfa6 100644 --- a/src/openai/resources/beta/threads/runs/runs.py +++ b/src/openai/resources/beta/threads/runs/runs.py @@ -21,6 +21,7 @@ from ....._types import NOT_GIVEN, Body, Omit, Query, Headers, NotGiven, omit, not_given from ....._utils import ( is_given, + path_template, required_args, maybe_transform, async_maybe_transform, @@ -594,7 +595,7 @@ def create( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( - f"/threads/{thread_id}/runs", + path_template("/threads/{thread_id}/runs", thread_id=thread_id), body=maybe_transform( { "assistant_id": assistant_id, @@ -661,7 +662,7 @@ def retrieve( raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get( - f"/threads/{thread_id}/runs/{run_id}", + path_template("/threads/{thread_id}/runs/{run_id}", thread_id=thread_id, run_id=run_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -707,7 +708,7 @@ def update( raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( - f"/threads/{thread_id}/runs/{run_id}", + path_template("/threads/{thread_id}/runs/{run_id}", thread_id=thread_id, run_id=run_id), body=maybe_transform({"metadata": metadata}, run_update_params.RunUpdateParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -763,7 +764,7 @@ def list( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( - f"/threads/{thread_id}/runs", + path_template("/threads/{thread_id}/runs", thread_id=thread_id), page=SyncCursorPage[Run], options=make_request_options( extra_headers=extra_headers, @@ -814,7 +815,7 @@ def cancel( raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( - f"/threads/{thread_id}/runs/{run_id}/cancel", + path_template("/threads/{thread_id}/runs/{run_id}/cancel", thread_id=thread_id, run_id=run_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -998,7 +999,7 @@ def create_and_stream( } make_request = partial( self._post, - f"/threads/{thread_id}/runs", + path_template("/threads/{thread_id}/runs", thread_id=thread_id), body=maybe_transform( { "assistant_id": assistant_id, @@ -1185,7 +1186,7 @@ def stream( } make_request = partial( self._post, - f"/threads/{thread_id}/runs", + path_template("/threads/{thread_id}/runs", thread_id=thread_id), body=maybe_transform( { "assistant_id": assistant_id, @@ -1361,7 +1362,7 @@ def submit_tool_outputs( raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( - f"/threads/{thread_id}/runs/{run_id}/submit_tool_outputs", + path_template("/threads/{thread_id}/runs/{run_id}/submit_tool_outputs", thread_id=thread_id, run_id=run_id), body=maybe_transform( { "tool_outputs": tool_outputs, @@ -1502,7 +1503,7 @@ def submit_tool_outputs_stream( } request = partial( self._post, - f"/threads/{thread_id}/runs/{run_id}/submit_tool_outputs", + path_template("/threads/{thread_id}/runs/{run_id}/submit_tool_outputs", thread_id=thread_id, run_id=run_id), body=maybe_transform( { "tool_outputs": tool_outputs, @@ -2057,7 +2058,7 @@ async def create( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( - f"/threads/{thread_id}/runs", + path_template("/threads/{thread_id}/runs", thread_id=thread_id), body=await async_maybe_transform( { "assistant_id": assistant_id, @@ -2124,7 +2125,7 @@ async def retrieve( raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._get( - f"/threads/{thread_id}/runs/{run_id}", + path_template("/threads/{thread_id}/runs/{run_id}", thread_id=thread_id, run_id=run_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -2170,7 +2171,7 @@ async def update( raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( - f"/threads/{thread_id}/runs/{run_id}", + path_template("/threads/{thread_id}/runs/{run_id}", thread_id=thread_id, run_id=run_id), body=await async_maybe_transform({"metadata": metadata}, run_update_params.RunUpdateParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -2226,7 +2227,7 @@ def list( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( - f"/threads/{thread_id}/runs", + path_template("/threads/{thread_id}/runs", thread_id=thread_id), page=AsyncCursorPage[Run], options=make_request_options( extra_headers=extra_headers, @@ -2277,7 +2278,7 @@ async def cancel( raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( - f"/threads/{thread_id}/runs/{run_id}/cancel", + path_template("/threads/{thread_id}/runs/{run_id}/cancel", thread_id=thread_id, run_id=run_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -2460,7 +2461,7 @@ def create_and_stream( **(extra_headers or {}), } request = self._post( - f"/threads/{thread_id}/runs", + path_template("/threads/{thread_id}/runs", thread_id=thread_id), body=maybe_transform( { "assistant_id": assistant_id, @@ -2647,7 +2648,7 @@ def stream( **(extra_headers or {}), } request = self._post( - f"/threads/{thread_id}/runs", + path_template("/threads/{thread_id}/runs", thread_id=thread_id), body=maybe_transform( { "assistant_id": assistant_id, @@ -2823,7 +2824,7 @@ async def submit_tool_outputs( raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( - f"/threads/{thread_id}/runs/{run_id}/submit_tool_outputs", + path_template("/threads/{thread_id}/runs/{run_id}/submit_tool_outputs", thread_id=thread_id, run_id=run_id), body=await async_maybe_transform( { "tool_outputs": tool_outputs, @@ -2966,7 +2967,7 @@ def submit_tool_outputs_stream( **(extra_headers or {}), } request = self._post( - f"/threads/{thread_id}/runs/{run_id}/submit_tool_outputs", + path_template("/threads/{thread_id}/runs/{run_id}/submit_tool_outputs", thread_id=thread_id, run_id=run_id), body=maybe_transform( { "tool_outputs": tool_outputs, diff --git a/src/openai/resources/beta/threads/runs/steps.py b/src/openai/resources/beta/threads/runs/steps.py index dea5df69bc..9a6402b263 100644 --- a/src/openai/resources/beta/threads/runs/steps.py +++ b/src/openai/resources/beta/threads/runs/steps.py @@ -10,7 +10,7 @@ from ..... import _legacy_response from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ....._utils import maybe_transform, async_maybe_transform +from ....._utils import path_template, maybe_transform, async_maybe_transform from ....._compat import cached_property from ....._resource import SyncAPIResource, AsyncAPIResource from ....._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -88,7 +88,12 @@ def retrieve( raise ValueError(f"Expected a non-empty value for `step_id` but received {step_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get( - f"/threads/{thread_id}/runs/{run_id}/steps/{step_id}", + path_template( + "/threads/{thread_id}/runs/{run_id}/steps/{step_id}", + thread_id=thread_id, + run_id=run_id, + step_id=step_id, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -159,7 +164,7 @@ def list( raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( - f"/threads/{thread_id}/runs/{run_id}/steps", + path_template("/threads/{thread_id}/runs/{run_id}/steps", thread_id=thread_id, run_id=run_id), page=SyncCursorPage[RunStep], options=make_request_options( extra_headers=extra_headers, @@ -246,7 +251,12 @@ async def retrieve( raise ValueError(f"Expected a non-empty value for `step_id` but received {step_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._get( - f"/threads/{thread_id}/runs/{run_id}/steps/{step_id}", + path_template( + "/threads/{thread_id}/runs/{run_id}/steps/{step_id}", + thread_id=thread_id, + run_id=run_id, + step_id=step_id, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -317,7 +327,7 @@ def list( raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( - f"/threads/{thread_id}/runs/{run_id}/steps", + path_template("/threads/{thread_id}/runs/{run_id}/steps", thread_id=thread_id, run_id=run_id), page=AsyncCursorPage[RunStep], options=make_request_options( extra_headers=extra_headers, diff --git a/src/openai/resources/beta/threads/threads.py b/src/openai/resources/beta/threads/threads.py index 0a93baf452..4b0f18fe47 100644 --- a/src/openai/resources/beta/threads/threads.py +++ b/src/openai/resources/beta/threads/threads.py @@ -19,7 +19,7 @@ AsyncMessagesWithStreamingResponse, ) from ...._types import NOT_GIVEN, Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import required_args, maybe_transform, async_maybe_transform +from ...._utils import path_template, required_args, maybe_transform, async_maybe_transform from .runs.runs import ( Runs, AsyncRuns, @@ -177,7 +177,7 @@ def retrieve( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get( - f"/threads/{thread_id}", + path_template("/threads/{thread_id}", thread_id=thread_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -226,7 +226,7 @@ def update( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( - f"/threads/{thread_id}", + path_template("/threads/{thread_id}", thread_id=thread_id), body=maybe_transform( { "metadata": metadata, @@ -268,7 +268,7 @@ def delete( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._delete( - f"/threads/{thread_id}", + path_template("/threads/{thread_id}", thread_id=thread_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1043,7 +1043,7 @@ async def retrieve( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._get( - f"/threads/{thread_id}", + path_template("/threads/{thread_id}", thread_id=thread_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1092,7 +1092,7 @@ async def update( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( - f"/threads/{thread_id}", + path_template("/threads/{thread_id}", thread_id=thread_id), body=await async_maybe_transform( { "metadata": metadata, @@ -1134,7 +1134,7 @@ async def delete( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._delete( - f"/threads/{thread_id}", + path_template("/threads/{thread_id}", thread_id=thread_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index a705c1f658..845bd1a1e1 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -20,7 +20,7 @@ AsyncMessagesWithStreamingResponse, ) from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given -from ...._utils import required_args, maybe_transform, async_maybe_transform +from ...._utils import path_template, required_args, maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -1288,7 +1288,7 @@ def retrieve( if not completion_id: raise ValueError(f"Expected a non-empty value for `completion_id` but received {completion_id!r}") return self._get( - f"/chat/completions/{completion_id}", + path_template("/chat/completions/{completion_id}", completion_id=completion_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1332,7 +1332,7 @@ def update( if not completion_id: raise ValueError(f"Expected a non-empty value for `completion_id` but received {completion_id!r}") return self._post( - f"/chat/completions/{completion_id}", + path_template("/chat/completions/{completion_id}", completion_id=completion_id), body=maybe_transform({"metadata": metadata}, completion_update_params.CompletionUpdateParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -1433,7 +1433,7 @@ def delete( if not completion_id: raise ValueError(f"Expected a non-empty value for `completion_id` but received {completion_id!r}") return self._delete( - f"/chat/completions/{completion_id}", + path_template("/chat/completions/{completion_id}", completion_id=completion_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -2791,7 +2791,7 @@ async def retrieve( if not completion_id: raise ValueError(f"Expected a non-empty value for `completion_id` but received {completion_id!r}") return await self._get( - f"/chat/completions/{completion_id}", + path_template("/chat/completions/{completion_id}", completion_id=completion_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -2835,7 +2835,7 @@ async def update( if not completion_id: raise ValueError(f"Expected a non-empty value for `completion_id` but received {completion_id!r}") return await self._post( - f"/chat/completions/{completion_id}", + path_template("/chat/completions/{completion_id}", completion_id=completion_id), body=await async_maybe_transform({"metadata": metadata}, completion_update_params.CompletionUpdateParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -2936,7 +2936,7 @@ async def delete( if not completion_id: raise ValueError(f"Expected a non-empty value for `completion_id` but received {completion_id!r}") return await self._delete( - f"/chat/completions/{completion_id}", + path_template("/chat/completions/{completion_id}", completion_id=completion_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/chat/completions/messages.py b/src/openai/resources/chat/completions/messages.py index b1c6a08d51..ffbff566db 100644 --- a/src/openai/resources/chat/completions/messages.py +++ b/src/openai/resources/chat/completions/messages.py @@ -8,7 +8,7 @@ from .... import _legacy_response from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import maybe_transform +from ...._utils import path_template, maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -82,7 +82,7 @@ def list( if not completion_id: raise ValueError(f"Expected a non-empty value for `completion_id` but received {completion_id!r}") return self._get_api_list( - f"/chat/completions/{completion_id}/messages", + path_template("/chat/completions/{completion_id}/messages", completion_id=completion_id), page=SyncCursorPage[ChatCompletionStoreMessage], options=make_request_options( extra_headers=extra_headers, @@ -164,7 +164,7 @@ def list( if not completion_id: raise ValueError(f"Expected a non-empty value for `completion_id` but received {completion_id!r}") return self._get_api_list( - f"/chat/completions/{completion_id}/messages", + path_template("/chat/completions/{completion_id}/messages", completion_id=completion_id), page=AsyncCursorPage[ChatCompletionStoreMessage], options=make_request_options( extra_headers=extra_headers, diff --git a/src/openai/resources/containers/containers.py b/src/openai/resources/containers/containers.py index 216097d9c8..f6b8c33c75 100644 --- a/src/openai/resources/containers/containers.py +++ b/src/openai/resources/containers/containers.py @@ -10,7 +10,7 @@ from ... import _legacy_response from ...types import container_list_params, container_create_params from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform +from ..._utils import path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -140,7 +140,7 @@ def retrieve( if not container_id: raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") return self._get( - f"/containers/{container_id}", + path_template("/containers/{container_id}", container_id=container_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -235,7 +235,7 @@ def delete( raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._delete( - f"/containers/{container_id}", + path_template("/containers/{container_id}", container_id=container_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -352,7 +352,7 @@ async def retrieve( if not container_id: raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") return await self._get( - f"/containers/{container_id}", + path_template("/containers/{container_id}", container_id=container_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -447,7 +447,7 @@ async def delete( raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._delete( - f"/containers/{container_id}", + path_template("/containers/{container_id}", container_id=container_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/containers/files/content.py b/src/openai/resources/containers/files/content.py index a3dbd0e8c7..eb915b9c13 100644 --- a/src/openai/resources/containers/files/content.py +++ b/src/openai/resources/containers/files/content.py @@ -6,6 +6,7 @@ from .... import _legacy_response from ...._types import Body, Query, Headers, NotGiven, not_given +from ...._utils import path_template from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import ( @@ -69,7 +70,9 @@ def retrieve( raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") extra_headers = {"Accept": "application/binary", **(extra_headers or {})} return self._get( - f"/containers/{container_id}/files/{file_id}/content", + path_template( + "/containers/{container_id}/files/{file_id}/content", container_id=container_id, file_id=file_id + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -127,7 +130,9 @@ async def retrieve( raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") extra_headers = {"Accept": "application/binary", **(extra_headers or {})} return await self._get( - f"/containers/{container_id}/files/{file_id}/content", + path_template( + "/containers/{container_id}/files/{file_id}/content", container_id=container_id, file_id=file_id + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/containers/files/files.py b/src/openai/resources/containers/files/files.py index 62659a5c3d..f48adf3a2a 100644 --- a/src/openai/resources/containers/files/files.py +++ b/src/openai/resources/containers/files/files.py @@ -17,7 +17,7 @@ AsyncContentWithStreamingResponse, ) from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, FileTypes, omit, not_given -from ...._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform +from ...._utils import extract_files, path_template, maybe_transform, deepcopy_minimal, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -102,7 +102,7 @@ def create( # multipart/form-data; boundary=---abc-- extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} return self._post( - f"/containers/{container_id}/files", + path_template("/containers/{container_id}/files", container_id=container_id), body=maybe_transform(body, file_create_params.FileCreateParams), files=files, options=make_request_options( @@ -140,7 +140,7 @@ def retrieve( if not file_id: raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") return self._get( - f"/containers/{container_id}/files/{file_id}", + path_template("/containers/{container_id}/files/{file_id}", container_id=container_id, file_id=file_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -188,7 +188,7 @@ def list( if not container_id: raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") return self._get_api_list( - f"/containers/{container_id}/files", + path_template("/containers/{container_id}/files", container_id=container_id), page=SyncCursorPage[FileListResponse], options=make_request_options( extra_headers=extra_headers, @@ -237,7 +237,7 @@ def delete( raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._delete( - f"/containers/{container_id}/files/{file_id}", + path_template("/containers/{container_id}/files/{file_id}", container_id=container_id, file_id=file_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -316,7 +316,7 @@ async def create( # multipart/form-data; boundary=---abc-- extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} return await self._post( - f"/containers/{container_id}/files", + path_template("/containers/{container_id}/files", container_id=container_id), body=await async_maybe_transform(body, file_create_params.FileCreateParams), files=files, options=make_request_options( @@ -354,7 +354,7 @@ async def retrieve( if not file_id: raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") return await self._get( - f"/containers/{container_id}/files/{file_id}", + path_template("/containers/{container_id}/files/{file_id}", container_id=container_id, file_id=file_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -402,7 +402,7 @@ def list( if not container_id: raise ValueError(f"Expected a non-empty value for `container_id` but received {container_id!r}") return self._get_api_list( - f"/containers/{container_id}/files", + path_template("/containers/{container_id}/files", container_id=container_id), page=AsyncCursorPage[FileListResponse], options=make_request_options( extra_headers=extra_headers, @@ -451,7 +451,7 @@ async def delete( raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._delete( - f"/containers/{container_id}/files/{file_id}", + path_template("/containers/{container_id}/files/{file_id}", container_id=container_id, file_id=file_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/conversations/conversations.py b/src/openai/resources/conversations/conversations.py index f2c54e4d04..d349f38546 100644 --- a/src/openai/resources/conversations/conversations.py +++ b/src/openai/resources/conversations/conversations.py @@ -16,7 +16,7 @@ AsyncItemsWithStreamingResponse, ) from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform +from ..._utils import path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -132,7 +132,7 @@ def retrieve( if not conversation_id: raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") return self._get( - f"/conversations/{conversation_id}", + path_template("/conversations/{conversation_id}", conversation_id=conversation_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -173,7 +173,7 @@ def update( if not conversation_id: raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") return self._post( - f"/conversations/{conversation_id}", + path_template("/conversations/{conversation_id}", conversation_id=conversation_id), body=maybe_transform({"metadata": metadata}, conversation_update_params.ConversationUpdateParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -208,7 +208,7 @@ def delete( if not conversation_id: raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") return self._delete( - f"/conversations/{conversation_id}", + path_template("/conversations/{conversation_id}", conversation_id=conversation_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -318,7 +318,7 @@ async def retrieve( if not conversation_id: raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") return await self._get( - f"/conversations/{conversation_id}", + path_template("/conversations/{conversation_id}", conversation_id=conversation_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -359,7 +359,7 @@ async def update( if not conversation_id: raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") return await self._post( - f"/conversations/{conversation_id}", + path_template("/conversations/{conversation_id}", conversation_id=conversation_id), body=await async_maybe_transform( {"metadata": metadata}, conversation_update_params.ConversationUpdateParams ), @@ -396,7 +396,7 @@ async def delete( if not conversation_id: raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") return await self._delete( - f"/conversations/{conversation_id}", + path_template("/conversations/{conversation_id}", conversation_id=conversation_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/conversations/items.py b/src/openai/resources/conversations/items.py index 1f8e101f7f..7d7c9a4aba 100644 --- a/src/openai/resources/conversations/items.py +++ b/src/openai/resources/conversations/items.py @@ -9,7 +9,7 @@ from ... import _legacy_response from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform +from ..._utils import path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -81,7 +81,7 @@ def create( if not conversation_id: raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") return self._post( - f"/conversations/{conversation_id}/items", + path_template("/conversations/{conversation_id}/items", conversation_id=conversation_id), body=maybe_transform({"items": items}, item_create_params.ItemCreateParams), options=make_request_options( extra_headers=extra_headers, @@ -129,7 +129,9 @@ def retrieve( return cast( ConversationItem, self._get( - f"/conversations/{conversation_id}/items/{item_id}", + path_template( + "/conversations/{conversation_id}/items/{item_id}", conversation_id=conversation_id, item_id=item_id + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -200,7 +202,7 @@ def list( if not conversation_id: raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") return self._get_api_list( - f"/conversations/{conversation_id}/items", + path_template("/conversations/{conversation_id}/items", conversation_id=conversation_id), page=SyncConversationCursorPage[ConversationItem], options=make_request_options( extra_headers=extra_headers, @@ -249,7 +251,9 @@ def delete( if not item_id: raise ValueError(f"Expected a non-empty value for `item_id` but received {item_id!r}") return self._delete( - f"/conversations/{conversation_id}/items/{item_id}", + path_template( + "/conversations/{conversation_id}/items/{item_id}", conversation_id=conversation_id, item_id=item_id + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -313,7 +317,7 @@ async def create( if not conversation_id: raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") return await self._post( - f"/conversations/{conversation_id}/items", + path_template("/conversations/{conversation_id}/items", conversation_id=conversation_id), body=await async_maybe_transform({"items": items}, item_create_params.ItemCreateParams), options=make_request_options( extra_headers=extra_headers, @@ -361,7 +365,9 @@ async def retrieve( return cast( ConversationItem, await self._get( - f"/conversations/{conversation_id}/items/{item_id}", + path_template( + "/conversations/{conversation_id}/items/{item_id}", conversation_id=conversation_id, item_id=item_id + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -432,7 +438,7 @@ def list( if not conversation_id: raise ValueError(f"Expected a non-empty value for `conversation_id` but received {conversation_id!r}") return self._get_api_list( - f"/conversations/{conversation_id}/items", + path_template("/conversations/{conversation_id}/items", conversation_id=conversation_id), page=AsyncConversationCursorPage[ConversationItem], options=make_request_options( extra_headers=extra_headers, @@ -481,7 +487,9 @@ async def delete( if not item_id: raise ValueError(f"Expected a non-empty value for `item_id` but received {item_id!r}") return await self._delete( - f"/conversations/{conversation_id}/items/{item_id}", + path_template( + "/conversations/{conversation_id}/items/{item_id}", conversation_id=conversation_id, item_id=item_id + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/evals/evals.py b/src/openai/resources/evals/evals.py index f0fe28fe8c..6acd669a2c 100644 --- a/src/openai/resources/evals/evals.py +++ b/src/openai/resources/evals/evals.py @@ -10,7 +10,7 @@ from ... import _legacy_response from ...types import eval_list_params, eval_create_params, eval_update_params from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform +from ..._utils import path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from .runs.runs import ( Runs, @@ -152,7 +152,7 @@ def retrieve( if not eval_id: raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") return self._get( - f"/evals/{eval_id}", + path_template("/evals/{eval_id}", eval_id=eval_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -196,7 +196,7 @@ def update( if not eval_id: raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") return self._post( - f"/evals/{eval_id}", + path_template("/evals/{eval_id}", eval_id=eval_id), body=maybe_transform( { "metadata": metadata, @@ -293,7 +293,7 @@ def delete( if not eval_id: raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") return self._delete( - f"/evals/{eval_id}", + path_template("/evals/{eval_id}", eval_id=eval_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -419,7 +419,7 @@ async def retrieve( if not eval_id: raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") return await self._get( - f"/evals/{eval_id}", + path_template("/evals/{eval_id}", eval_id=eval_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -463,7 +463,7 @@ async def update( if not eval_id: raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") return await self._post( - f"/evals/{eval_id}", + path_template("/evals/{eval_id}", eval_id=eval_id), body=await async_maybe_transform( { "metadata": metadata, @@ -560,7 +560,7 @@ async def delete( if not eval_id: raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") return await self._delete( - f"/evals/{eval_id}", + path_template("/evals/{eval_id}", eval_id=eval_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/evals/runs/output_items.py b/src/openai/resources/evals/runs/output_items.py index c2e6647715..7a498a7ebf 100644 --- a/src/openai/resources/evals/runs/output_items.py +++ b/src/openai/resources/evals/runs/output_items.py @@ -8,7 +8,7 @@ from .... import _legacy_response from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import maybe_transform +from ...._utils import path_template, maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -75,7 +75,12 @@ def retrieve( if not output_item_id: raise ValueError(f"Expected a non-empty value for `output_item_id` but received {output_item_id!r}") return self._get( - f"/evals/{eval_id}/runs/{run_id}/output_items/{output_item_id}", + path_template( + "/evals/{eval_id}/runs/{run_id}/output_items/{output_item_id}", + eval_id=eval_id, + run_id=run_id, + output_item_id=output_item_id, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -125,7 +130,7 @@ def list( if not run_id: raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") return self._get_api_list( - f"/evals/{eval_id}/runs/{run_id}/output_items", + path_template("/evals/{eval_id}/runs/{run_id}/output_items", eval_id=eval_id, run_id=run_id), page=SyncCursorPage[OutputItemListResponse], options=make_request_options( extra_headers=extra_headers, @@ -200,7 +205,12 @@ async def retrieve( if not output_item_id: raise ValueError(f"Expected a non-empty value for `output_item_id` but received {output_item_id!r}") return await self._get( - f"/evals/{eval_id}/runs/{run_id}/output_items/{output_item_id}", + path_template( + "/evals/{eval_id}/runs/{run_id}/output_items/{output_item_id}", + eval_id=eval_id, + run_id=run_id, + output_item_id=output_item_id, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -250,7 +260,7 @@ def list( if not run_id: raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") return self._get_api_list( - f"/evals/{eval_id}/runs/{run_id}/output_items", + path_template("/evals/{eval_id}/runs/{run_id}/output_items", eval_id=eval_id, run_id=run_id), page=AsyncCursorPage[OutputItemListResponse], options=make_request_options( extra_headers=extra_headers, diff --git a/src/openai/resources/evals/runs/runs.py b/src/openai/resources/evals/runs/runs.py index 49eecd768f..152ce9cb77 100644 --- a/src/openai/resources/evals/runs/runs.py +++ b/src/openai/resources/evals/runs/runs.py @@ -9,7 +9,7 @@ from .... import _legacy_response from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import maybe_transform, async_maybe_transform +from ...._utils import path_template, maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -103,7 +103,7 @@ def create( if not eval_id: raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") return self._post( - f"/evals/{eval_id}/runs", + path_template("/evals/{eval_id}/runs", eval_id=eval_id), body=maybe_transform( { "data_source": data_source, @@ -147,7 +147,7 @@ def retrieve( if not run_id: raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") return self._get( - f"/evals/{eval_id}/runs/{run_id}", + path_template("/evals/{eval_id}/runs/{run_id}", eval_id=eval_id, run_id=run_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -194,7 +194,7 @@ def list( if not eval_id: raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") return self._get_api_list( - f"/evals/{eval_id}/runs", + path_template("/evals/{eval_id}/runs", eval_id=eval_id), page=SyncCursorPage[RunListResponse], options=make_request_options( extra_headers=extra_headers, @@ -243,7 +243,7 @@ def delete( if not run_id: raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") return self._delete( - f"/evals/{eval_id}/runs/{run_id}", + path_template("/evals/{eval_id}/runs/{run_id}", eval_id=eval_id, run_id=run_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -279,7 +279,7 @@ def cancel( if not run_id: raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") return self._post( - f"/evals/{eval_id}/runs/{run_id}", + path_template("/evals/{eval_id}/runs/{run_id}", eval_id=eval_id, run_id=run_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -356,7 +356,7 @@ async def create( if not eval_id: raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") return await self._post( - f"/evals/{eval_id}/runs", + path_template("/evals/{eval_id}/runs", eval_id=eval_id), body=await async_maybe_transform( { "data_source": data_source, @@ -400,7 +400,7 @@ async def retrieve( if not run_id: raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") return await self._get( - f"/evals/{eval_id}/runs/{run_id}", + path_template("/evals/{eval_id}/runs/{run_id}", eval_id=eval_id, run_id=run_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -447,7 +447,7 @@ def list( if not eval_id: raise ValueError(f"Expected a non-empty value for `eval_id` but received {eval_id!r}") return self._get_api_list( - f"/evals/{eval_id}/runs", + path_template("/evals/{eval_id}/runs", eval_id=eval_id), page=AsyncCursorPage[RunListResponse], options=make_request_options( extra_headers=extra_headers, @@ -496,7 +496,7 @@ async def delete( if not run_id: raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") return await self._delete( - f"/evals/{eval_id}/runs/{run_id}", + path_template("/evals/{eval_id}/runs/{run_id}", eval_id=eval_id, run_id=run_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -532,7 +532,7 @@ async def cancel( if not run_id: raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") return await self._post( - f"/evals/{eval_id}/runs/{run_id}", + path_template("/evals/{eval_id}/runs/{run_id}", eval_id=eval_id, run_id=run_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/files.py b/src/openai/resources/files.py index 7341b326dc..b03f11b06a 100644 --- a/src/openai/resources/files.py +++ b/src/openai/resources/files.py @@ -12,7 +12,7 @@ from .. import _legacy_response from ..types import FilePurpose, file_list_params, file_create_params from .._types import Body, Omit, Query, Headers, NotGiven, FileTypes, omit, not_given -from .._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform +from .._utils import extract_files, path_template, maybe_transform, deepcopy_minimal, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import ( @@ -164,7 +164,7 @@ def retrieve( if not file_id: raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") return self._get( - f"/files/{file_id}", + path_template("/files/{file_id}", file_id=file_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -258,7 +258,7 @@ def delete( if not file_id: raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") return self._delete( - f"/files/{file_id}", + path_template("/files/{file_id}", file_id=file_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -292,7 +292,7 @@ def content( raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") extra_headers = {"Accept": "application/binary", **(extra_headers or {})} return self._get( - f"/files/{file_id}/content", + path_template("/files/{file_id}/content", file_id=file_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -326,7 +326,7 @@ def retrieve_content( if not file_id: raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") return self._get( - f"/files/{file_id}/content", + path_template("/files/{file_id}/content", file_id=file_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -489,7 +489,7 @@ async def retrieve( if not file_id: raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") return await self._get( - f"/files/{file_id}", + path_template("/files/{file_id}", file_id=file_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -583,7 +583,7 @@ async def delete( if not file_id: raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") return await self._delete( - f"/files/{file_id}", + path_template("/files/{file_id}", file_id=file_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -617,7 +617,7 @@ async def content( raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") extra_headers = {"Accept": "application/binary", **(extra_headers or {})} return await self._get( - f"/files/{file_id}/content", + path_template("/files/{file_id}/content", file_id=file_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -651,7 +651,7 @@ async def retrieve_content( if not file_id: raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") return await self._get( - f"/files/{file_id}/content", + path_template("/files/{file_id}/content", file_id=file_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/fine_tuning/checkpoints/permissions.py b/src/openai/resources/fine_tuning/checkpoints/permissions.py index 35e06feee0..15184e130b 100644 --- a/src/openai/resources/fine_tuning/checkpoints/permissions.py +++ b/src/openai/resources/fine_tuning/checkpoints/permissions.py @@ -9,7 +9,7 @@ from .... import _legacy_response from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given -from ...._utils import maybe_transform, async_maybe_transform +from ...._utils import path_template, maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -84,7 +84,10 @@ def create( f"Expected a non-empty value for `fine_tuned_model_checkpoint` but received {fine_tuned_model_checkpoint!r}" ) return self._get_api_list( - f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + path_template( + "/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + fine_tuned_model_checkpoint=fine_tuned_model_checkpoint, + ), page=SyncPage[PermissionCreateResponse], body=maybe_transform({"project_ids": project_ids}, permission_create_params.PermissionCreateParams), options=make_request_options( @@ -138,7 +141,10 @@ def retrieve( f"Expected a non-empty value for `fine_tuned_model_checkpoint` but received {fine_tuned_model_checkpoint!r}" ) return self._get( - f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + path_template( + "/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + fine_tuned_model_checkpoint=fine_tuned_model_checkpoint, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -200,7 +206,10 @@ def list( f"Expected a non-empty value for `fine_tuned_model_checkpoint` but received {fine_tuned_model_checkpoint!r}" ) return self._get_api_list( - f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + path_template( + "/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + fine_tuned_model_checkpoint=fine_tuned_model_checkpoint, + ), page=SyncConversationCursorPage[PermissionListResponse], options=make_request_options( extra_headers=extra_headers, @@ -254,7 +263,11 @@ def delete( if not permission_id: raise ValueError(f"Expected a non-empty value for `permission_id` but received {permission_id!r}") return self._delete( - f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions/{permission_id}", + path_template( + "/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions/{permission_id}", + fine_tuned_model_checkpoint=fine_tuned_model_checkpoint, + permission_id=permission_id, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -318,7 +331,10 @@ def create( f"Expected a non-empty value for `fine_tuned_model_checkpoint` but received {fine_tuned_model_checkpoint!r}" ) return self._get_api_list( - f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + path_template( + "/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + fine_tuned_model_checkpoint=fine_tuned_model_checkpoint, + ), page=AsyncPage[PermissionCreateResponse], body=maybe_transform({"project_ids": project_ids}, permission_create_params.PermissionCreateParams), options=make_request_options( @@ -372,7 +388,10 @@ async def retrieve( f"Expected a non-empty value for `fine_tuned_model_checkpoint` but received {fine_tuned_model_checkpoint!r}" ) return await self._get( - f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + path_template( + "/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + fine_tuned_model_checkpoint=fine_tuned_model_checkpoint, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -434,7 +453,10 @@ def list( f"Expected a non-empty value for `fine_tuned_model_checkpoint` but received {fine_tuned_model_checkpoint!r}" ) return self._get_api_list( - f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + path_template( + "/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions", + fine_tuned_model_checkpoint=fine_tuned_model_checkpoint, + ), page=AsyncConversationCursorPage[PermissionListResponse], options=make_request_options( extra_headers=extra_headers, @@ -488,7 +510,11 @@ async def delete( if not permission_id: raise ValueError(f"Expected a non-empty value for `permission_id` but received {permission_id!r}") return await self._delete( - f"/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions/{permission_id}", + path_template( + "/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions/{permission_id}", + fine_tuned_model_checkpoint=fine_tuned_model_checkpoint, + permission_id=permission_id, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/fine_tuning/jobs/checkpoints.py b/src/openai/resources/fine_tuning/jobs/checkpoints.py index 6f14a0994e..0f91a6218a 100644 --- a/src/openai/resources/fine_tuning/jobs/checkpoints.py +++ b/src/openai/resources/fine_tuning/jobs/checkpoints.py @@ -6,7 +6,7 @@ from .... import _legacy_response from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import maybe_transform +from ...._utils import path_template, maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -75,7 +75,7 @@ def list( if not fine_tuning_job_id: raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") return self._get_api_list( - f"/fine_tuning/jobs/{fine_tuning_job_id}/checkpoints", + path_template("/fine_tuning/jobs/{fine_tuning_job_id}/checkpoints", fine_tuning_job_id=fine_tuning_job_id), page=SyncCursorPage[FineTuningJobCheckpoint], options=make_request_options( extra_headers=extra_headers, @@ -148,7 +148,7 @@ def list( if not fine_tuning_job_id: raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") return self._get_api_list( - f"/fine_tuning/jobs/{fine_tuning_job_id}/checkpoints", + path_template("/fine_tuning/jobs/{fine_tuning_job_id}/checkpoints", fine_tuning_job_id=fine_tuning_job_id), page=AsyncCursorPage[FineTuningJobCheckpoint], options=make_request_options( extra_headers=extra_headers, diff --git a/src/openai/resources/fine_tuning/jobs/jobs.py b/src/openai/resources/fine_tuning/jobs/jobs.py index e38baa5539..a948b10349 100644 --- a/src/openai/resources/fine_tuning/jobs/jobs.py +++ b/src/openai/resources/fine_tuning/jobs/jobs.py @@ -9,7 +9,7 @@ from .... import _legacy_response from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import maybe_transform, async_maybe_transform +from ...._utils import path_template, maybe_transform, async_maybe_transform from ...._compat import cached_property from .checkpoints import ( Checkpoints, @@ -208,7 +208,7 @@ def retrieve( if not fine_tuning_job_id: raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") return self._get( - f"/fine_tuning/jobs/{fine_tuning_job_id}", + path_template("/fine_tuning/jobs/{fine_tuning_job_id}", fine_tuning_job_id=fine_tuning_job_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -293,7 +293,7 @@ def cancel( if not fine_tuning_job_id: raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") return self._post( - f"/fine_tuning/jobs/{fine_tuning_job_id}/cancel", + path_template("/fine_tuning/jobs/{fine_tuning_job_id}/cancel", fine_tuning_job_id=fine_tuning_job_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -332,7 +332,7 @@ def list_events( if not fine_tuning_job_id: raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") return self._get_api_list( - f"/fine_tuning/jobs/{fine_tuning_job_id}/events", + path_template("/fine_tuning/jobs/{fine_tuning_job_id}/events", fine_tuning_job_id=fine_tuning_job_id), page=SyncCursorPage[FineTuningJobEvent], options=make_request_options( extra_headers=extra_headers, @@ -376,7 +376,7 @@ def pause( if not fine_tuning_job_id: raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") return self._post( - f"/fine_tuning/jobs/{fine_tuning_job_id}/pause", + path_template("/fine_tuning/jobs/{fine_tuning_job_id}/pause", fine_tuning_job_id=fine_tuning_job_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -409,7 +409,7 @@ def resume( if not fine_tuning_job_id: raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") return self._post( - f"/fine_tuning/jobs/{fine_tuning_job_id}/resume", + path_template("/fine_tuning/jobs/{fine_tuning_job_id}/resume", fine_tuning_job_id=fine_tuning_job_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -591,7 +591,7 @@ async def retrieve( if not fine_tuning_job_id: raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") return await self._get( - f"/fine_tuning/jobs/{fine_tuning_job_id}", + path_template("/fine_tuning/jobs/{fine_tuning_job_id}", fine_tuning_job_id=fine_tuning_job_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -676,7 +676,7 @@ async def cancel( if not fine_tuning_job_id: raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") return await self._post( - f"/fine_tuning/jobs/{fine_tuning_job_id}/cancel", + path_template("/fine_tuning/jobs/{fine_tuning_job_id}/cancel", fine_tuning_job_id=fine_tuning_job_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -715,7 +715,7 @@ def list_events( if not fine_tuning_job_id: raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") return self._get_api_list( - f"/fine_tuning/jobs/{fine_tuning_job_id}/events", + path_template("/fine_tuning/jobs/{fine_tuning_job_id}/events", fine_tuning_job_id=fine_tuning_job_id), page=AsyncCursorPage[FineTuningJobEvent], options=make_request_options( extra_headers=extra_headers, @@ -759,7 +759,7 @@ async def pause( if not fine_tuning_job_id: raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") return await self._post( - f"/fine_tuning/jobs/{fine_tuning_job_id}/pause", + path_template("/fine_tuning/jobs/{fine_tuning_job_id}/pause", fine_tuning_job_id=fine_tuning_job_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -792,7 +792,7 @@ async def resume( if not fine_tuning_job_id: raise ValueError(f"Expected a non-empty value for `fine_tuning_job_id` but received {fine_tuning_job_id!r}") return await self._post( - f"/fine_tuning/jobs/{fine_tuning_job_id}/resume", + path_template("/fine_tuning/jobs/{fine_tuning_job_id}/resume", fine_tuning_job_id=fine_tuning_job_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/models.py b/src/openai/resources/models.py index 508393263f..a1fe0d395e 100644 --- a/src/openai/resources/models.py +++ b/src/openai/resources/models.py @@ -6,6 +6,7 @@ from .. import _legacy_response from .._types import Body, Query, Headers, NotGiven, not_given +from .._utils import path_template from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -69,7 +70,7 @@ def retrieve( if not model: raise ValueError(f"Expected a non-empty value for `model` but received {model!r}") return self._get( - f"/models/{model}", + path_template("/models/{model}", model=model), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -127,7 +128,7 @@ def delete( if not model: raise ValueError(f"Expected a non-empty value for `model` but received {model!r}") return self._delete( - f"/models/{model}", + path_template("/models/{model}", model=model), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -184,7 +185,7 @@ async def retrieve( if not model: raise ValueError(f"Expected a non-empty value for `model` but received {model!r}") return await self._get( - f"/models/{model}", + path_template("/models/{model}", model=model), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -242,7 +243,7 @@ async def delete( if not model: raise ValueError(f"Expected a non-empty value for `model` but received {model!r}") return await self._delete( - f"/models/{model}", + path_template("/models/{model}", model=model), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/realtime/calls.py b/src/openai/resources/realtime/calls.py index 1520a97b0a..f34748d239 100644 --- a/src/openai/resources/realtime/calls.py +++ b/src/openai/resources/realtime/calls.py @@ -9,7 +9,7 @@ from ... import _legacy_response from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform +from ..._utils import path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import ( @@ -230,7 +230,7 @@ def accept( raise ValueError(f"Expected a non-empty value for `call_id` but received {call_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._post( - f"/realtime/calls/{call_id}/accept", + path_template("/realtime/calls/{call_id}/accept", call_id=call_id), body=maybe_transform( { "type": type, @@ -281,7 +281,7 @@ def hangup( raise ValueError(f"Expected a non-empty value for `call_id` but received {call_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._post( - f"/realtime/calls/{call_id}/hangup", + path_template("/realtime/calls/{call_id}/hangup", call_id=call_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -319,7 +319,7 @@ def refer( raise ValueError(f"Expected a non-empty value for `call_id` but received {call_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._post( - f"/realtime/calls/{call_id}/refer", + path_template("/realtime/calls/{call_id}/refer", call_id=call_id), body=maybe_transform({"target_uri": target_uri}, call_refer_params.CallReferParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -358,7 +358,7 @@ def reject( raise ValueError(f"Expected a non-empty value for `call_id` but received {call_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._post( - f"/realtime/calls/{call_id}/reject", + path_template("/realtime/calls/{call_id}/reject", call_id=call_id), body=maybe_transform({"status_code": status_code}, call_reject_params.CallRejectParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -559,7 +559,7 @@ async def accept( raise ValueError(f"Expected a non-empty value for `call_id` but received {call_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._post( - f"/realtime/calls/{call_id}/accept", + path_template("/realtime/calls/{call_id}/accept", call_id=call_id), body=await async_maybe_transform( { "type": type, @@ -610,7 +610,7 @@ async def hangup( raise ValueError(f"Expected a non-empty value for `call_id` but received {call_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._post( - f"/realtime/calls/{call_id}/hangup", + path_template("/realtime/calls/{call_id}/hangup", call_id=call_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -648,7 +648,7 @@ async def refer( raise ValueError(f"Expected a non-empty value for `call_id` but received {call_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._post( - f"/realtime/calls/{call_id}/refer", + path_template("/realtime/calls/{call_id}/refer", call_id=call_id), body=await async_maybe_transform({"target_uri": target_uri}, call_refer_params.CallReferParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -687,7 +687,7 @@ async def reject( raise ValueError(f"Expected a non-empty value for `call_id` but received {call_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._post( - f"/realtime/calls/{call_id}/reject", + path_template("/realtime/calls/{call_id}/reject", call_id=call_id), body=await async_maybe_transform({"status_code": status_code}, call_reject_params.CallRejectParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout diff --git a/src/openai/resources/responses/input_items.py b/src/openai/resources/responses/input_items.py index 3311bfe10a..b9ae5eeeae 100644 --- a/src/openai/resources/responses/input_items.py +++ b/src/openai/resources/responses/input_items.py @@ -9,7 +9,7 @@ from ... import _legacy_response from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ..._utils import maybe_transform +from ..._utils import path_template, maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -85,7 +85,7 @@ def list( if not response_id: raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") return self._get_api_list( - f"/responses/{response_id}/input_items", + path_template("/responses/{response_id}/input_items", response_id=response_id), page=SyncCursorPage[ResponseItem], options=make_request_options( extra_headers=extra_headers, @@ -169,7 +169,7 @@ def list( if not response_id: raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") return self._get_api_list( - f"/responses/{response_id}/input_items", + path_template("/responses/{response_id}/input_items", response_id=response_id), page=AsyncCursorPage[ResponseItem], options=make_request_options( extra_headers=extra_headers, diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py index 6d57f86313..63795f95a9 100644 --- a/src/openai/resources/responses/responses.py +++ b/src/openai/resources/responses/responses.py @@ -15,7 +15,7 @@ from ... import _legacy_response from ..._types import NOT_GIVEN, Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given -from ..._utils import is_given, maybe_transform, strip_not_given, async_maybe_transform +from ..._utils import is_given, path_template, maybe_transform, strip_not_given, async_maybe_transform from ..._compat import cached_property from ..._models import construct_type_unchecked from ..._resource import SyncAPIResource, AsyncAPIResource @@ -1471,7 +1471,7 @@ def retrieve( if not response_id: raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") return self._get( - f"/responses/{response_id}", + path_template("/responses/{response_id}", response_id=response_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -1519,7 +1519,7 @@ def delete( raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return self._delete( - f"/responses/{response_id}", + path_template("/responses/{response_id}", response_id=response_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1555,7 +1555,7 @@ def cancel( if not response_id: raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") return self._post( - f"/responses/{response_id}/cancel", + path_template("/responses/{response_id}/cancel", response_id=response_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -3142,7 +3142,7 @@ async def retrieve( if not response_id: raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") return await self._get( - f"/responses/{response_id}", + path_template("/responses/{response_id}", response_id=response_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -3190,7 +3190,7 @@ async def delete( raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") extra_headers = {"Accept": "*/*", **(extra_headers or {})} return await self._delete( - f"/responses/{response_id}", + path_template("/responses/{response_id}", response_id=response_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -3226,7 +3226,7 @@ async def cancel( if not response_id: raise ValueError(f"Expected a non-empty value for `response_id` but received {response_id!r}") return await self._post( - f"/responses/{response_id}/cancel", + path_template("/responses/{response_id}/cancel", response_id=response_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/skills/content.py b/src/openai/resources/skills/content.py index c912fd3eb3..96b237177e 100644 --- a/src/openai/resources/skills/content.py +++ b/src/openai/resources/skills/content.py @@ -6,6 +6,7 @@ from ... import _legacy_response from ..._types import Body, Query, Headers, NotGiven, not_given +from ..._utils import path_template from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import ( @@ -66,7 +67,7 @@ def retrieve( raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") extra_headers = {"Accept": "application/binary", **(extra_headers or {})} return self._get( - f"/skills/{skill_id}/content", + path_template("/skills/{skill_id}/content", skill_id=skill_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -121,7 +122,7 @@ async def retrieve( raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") extra_headers = {"Accept": "application/binary", **(extra_headers or {})} return await self._get( - f"/skills/{skill_id}/content", + path_template("/skills/{skill_id}/content", skill_id=skill_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/skills/skills.py b/src/openai/resources/skills/skills.py index 77bed029df..f44fb24607 100644 --- a/src/openai/resources/skills/skills.py +++ b/src/openai/resources/skills/skills.py @@ -28,7 +28,7 @@ omit, not_given, ) -from ..._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform +from ..._utils import extract_files, path_template, maybe_transform, deepcopy_minimal, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -144,7 +144,7 @@ def retrieve( if not skill_id: raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") return self._get( - f"/skills/{skill_id}", + path_template("/skills/{skill_id}", skill_id=skill_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -180,7 +180,7 @@ def update( if not skill_id: raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") return self._post( - f"/skills/{skill_id}", + path_template("/skills/{skill_id}", skill_id=skill_id), body=maybe_transform({"default_version": default_version}, skill_update_params.SkillUpdateParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -266,7 +266,7 @@ def delete( if not skill_id: raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") return self._delete( - f"/skills/{skill_id}", + path_template("/skills/{skill_id}", skill_id=skill_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -370,7 +370,7 @@ async def retrieve( if not skill_id: raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") return await self._get( - f"/skills/{skill_id}", + path_template("/skills/{skill_id}", skill_id=skill_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -406,7 +406,7 @@ async def update( if not skill_id: raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") return await self._post( - f"/skills/{skill_id}", + path_template("/skills/{skill_id}", skill_id=skill_id), body=await async_maybe_transform( {"default_version": default_version}, skill_update_params.SkillUpdateParams ), @@ -494,7 +494,7 @@ async def delete( if not skill_id: raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") return await self._delete( - f"/skills/{skill_id}", + path_template("/skills/{skill_id}", skill_id=skill_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/skills/versions/content.py b/src/openai/resources/skills/versions/content.py index 182a563dde..2f54586718 100644 --- a/src/openai/resources/skills/versions/content.py +++ b/src/openai/resources/skills/versions/content.py @@ -6,6 +6,7 @@ from .... import _legacy_response from ...._types import Body, Query, Headers, NotGiven, not_given +from ...._utils import path_template from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import ( @@ -71,7 +72,7 @@ def retrieve( raise ValueError(f"Expected a non-empty value for `version` but received {version!r}") extra_headers = {"Accept": "application/binary", **(extra_headers or {})} return self._get( - f"/skills/{skill_id}/versions/{version}/content", + path_template("/skills/{skill_id}/versions/{version}/content", skill_id=skill_id, version=version), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -131,7 +132,7 @@ async def retrieve( raise ValueError(f"Expected a non-empty value for `version` but received {version!r}") extra_headers = {"Accept": "application/binary", **(extra_headers or {})} return await self._get( - f"/skills/{skill_id}/versions/{version}/content", + path_template("/skills/{skill_id}/versions/{version}/content", skill_id=skill_id, version=version), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/skills/versions/versions.py b/src/openai/resources/skills/versions/versions.py index 610a24240a..8b48075cc3 100644 --- a/src/openai/resources/skills/versions/versions.py +++ b/src/openai/resources/skills/versions/versions.py @@ -27,7 +27,7 @@ omit, not_given, ) -from ...._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform +from ...._utils import extract_files, path_template, maybe_transform, deepcopy_minimal, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -108,7 +108,7 @@ def create( # multipart/form-data; boundary=---abc-- extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} return self._post( - f"/skills/{skill_id}/versions", + path_template("/skills/{skill_id}/versions", skill_id=skill_id), body=maybe_transform(body, version_create_params.VersionCreateParams), files=extracted_files, options=make_request_options( @@ -148,7 +148,7 @@ def retrieve( if not version: raise ValueError(f"Expected a non-empty value for `version` but received {version!r}") return self._get( - f"/skills/{skill_id}/versions/{version}", + path_template("/skills/{skill_id}/versions/{version}", skill_id=skill_id, version=version), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -190,7 +190,7 @@ def list( if not skill_id: raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") return self._get_api_list( - f"/skills/{skill_id}/versions", + path_template("/skills/{skill_id}/versions", skill_id=skill_id), page=SyncCursorPage[SkillVersion], options=make_request_options( extra_headers=extra_headers, @@ -240,7 +240,7 @@ def delete( if not version: raise ValueError(f"Expected a non-empty value for `version` but received {version!r}") return self._delete( - f"/skills/{skill_id}/versions/{version}", + path_template("/skills/{skill_id}/versions/{version}", skill_id=skill_id, version=version), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -316,7 +316,7 @@ async def create( # multipart/form-data; boundary=---abc-- extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} return await self._post( - f"/skills/{skill_id}/versions", + path_template("/skills/{skill_id}/versions", skill_id=skill_id), body=await async_maybe_transform(body, version_create_params.VersionCreateParams), files=extracted_files, options=make_request_options( @@ -356,7 +356,7 @@ async def retrieve( if not version: raise ValueError(f"Expected a non-empty value for `version` but received {version!r}") return await self._get( - f"/skills/{skill_id}/versions/{version}", + path_template("/skills/{skill_id}/versions/{version}", skill_id=skill_id, version=version), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -398,7 +398,7 @@ def list( if not skill_id: raise ValueError(f"Expected a non-empty value for `skill_id` but received {skill_id!r}") return self._get_api_list( - f"/skills/{skill_id}/versions", + path_template("/skills/{skill_id}/versions", skill_id=skill_id), page=AsyncCursorPage[SkillVersion], options=make_request_options( extra_headers=extra_headers, @@ -448,7 +448,7 @@ async def delete( if not version: raise ValueError(f"Expected a non-empty value for `version` but received {version!r}") return await self._delete( - f"/skills/{skill_id}/versions/{version}", + path_template("/skills/{skill_id}/versions/{version}", skill_id=skill_id, version=version), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/openai/resources/uploads/parts.py b/src/openai/resources/uploads/parts.py index 034547f308..cf09eea75e 100644 --- a/src/openai/resources/uploads/parts.py +++ b/src/openai/resources/uploads/parts.py @@ -8,7 +8,7 @@ from ... import _legacy_response from ..._types import Body, Query, Headers, NotGiven, FileTypes, not_given -from ..._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform +from ..._utils import extract_files, path_template, maybe_transform, deepcopy_minimal, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -86,7 +86,7 @@ def create( # multipart/form-data; boundary=---abc-- extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} return self._post( - f"/uploads/{upload_id}/parts", + path_template("/uploads/{upload_id}/parts", upload_id=upload_id), body=maybe_transform(body, part_create_params.PartCreateParams), files=files, options=make_request_options( @@ -163,7 +163,7 @@ async def create( # multipart/form-data; boundary=---abc-- extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} return await self._post( - f"/uploads/{upload_id}/parts", + path_template("/uploads/{upload_id}/parts", upload_id=upload_id), body=await async_maybe_transform(body, part_create_params.PartCreateParams), files=files, options=make_request_options( diff --git a/src/openai/resources/uploads/uploads.py b/src/openai/resources/uploads/uploads.py index f5e5e6f664..7778e51539 100644 --- a/src/openai/resources/uploads/uploads.py +++ b/src/openai/resources/uploads/uploads.py @@ -23,7 +23,7 @@ ) from ...types import FilePurpose, upload_create_params, upload_complete_params from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform +from ..._utils import path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -276,7 +276,7 @@ def cancel( if not upload_id: raise ValueError(f"Expected a non-empty value for `upload_id` but received {upload_id!r}") return self._post( - f"/uploads/{upload_id}/cancel", + path_template("/uploads/{upload_id}/cancel", upload_id=upload_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -330,7 +330,7 @@ def complete( if not upload_id: raise ValueError(f"Expected a non-empty value for `upload_id` but received {upload_id!r}") return self._post( - f"/uploads/{upload_id}/complete", + path_template("/uploads/{upload_id}/complete", upload_id=upload_id), body=maybe_transform( { "part_ids": part_ids, @@ -592,7 +592,7 @@ async def cancel( if not upload_id: raise ValueError(f"Expected a non-empty value for `upload_id` but received {upload_id!r}") return await self._post( - f"/uploads/{upload_id}/cancel", + path_template("/uploads/{upload_id}/cancel", upload_id=upload_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -646,7 +646,7 @@ async def complete( if not upload_id: raise ValueError(f"Expected a non-empty value for `upload_id` but received {upload_id!r}") return await self._post( - f"/uploads/{upload_id}/complete", + path_template("/uploads/{upload_id}/complete", upload_id=upload_id), body=await async_maybe_transform( { "part_ids": part_ids, diff --git a/src/openai/resources/vector_stores/file_batches.py b/src/openai/resources/vector_stores/file_batches.py index 13ffa66d1a..f097cf8a92 100644 --- a/src/openai/resources/vector_stores/file_batches.py +++ b/src/openai/resources/vector_stores/file_batches.py @@ -13,7 +13,7 @@ from ... import _legacy_response from ...types import FileChunkingStrategyParam from ..._types import Body, Omit, Query, Headers, NotGiven, FileTypes, SequenceNotStr, omit, not_given -from ..._utils import is_given, maybe_transform, async_maybe_transform +from ..._utils import is_given, path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -100,7 +100,7 @@ def create( raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( - f"/vector_stores/{vector_store_id}/file_batches", + path_template("/vector_stores/{vector_store_id}/file_batches", vector_store_id=vector_store_id), body=maybe_transform( { "attributes": attributes, @@ -146,7 +146,11 @@ def retrieve( raise ValueError(f"Expected a non-empty value for `batch_id` but received {batch_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get( - f"/vector_stores/{vector_store_id}/file_batches/{batch_id}", + path_template( + "/vector_stores/{vector_store_id}/file_batches/{batch_id}", + vector_store_id=vector_store_id, + batch_id=batch_id, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -185,7 +189,11 @@ def cancel( raise ValueError(f"Expected a non-empty value for `batch_id` but received {batch_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( - f"/vector_stores/{vector_store_id}/file_batches/{batch_id}/cancel", + path_template( + "/vector_stores/{vector_store_id}/file_batches/{batch_id}/cancel", + vector_store_id=vector_store_id, + batch_id=batch_id, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -280,7 +288,11 @@ def list_files( raise ValueError(f"Expected a non-empty value for `batch_id` but received {batch_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( - f"/vector_stores/{vector_store_id}/file_batches/{batch_id}/files", + path_template( + "/vector_stores/{vector_store_id}/file_batches/{batch_id}/files", + vector_store_id=vector_store_id, + batch_id=batch_id, + ), page=SyncCursorPage[VectorStoreFile], options=make_request_options( extra_headers=extra_headers, @@ -461,7 +473,7 @@ async def create( raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( - f"/vector_stores/{vector_store_id}/file_batches", + path_template("/vector_stores/{vector_store_id}/file_batches", vector_store_id=vector_store_id), body=await async_maybe_transform( { "attributes": attributes, @@ -507,7 +519,11 @@ async def retrieve( raise ValueError(f"Expected a non-empty value for `batch_id` but received {batch_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._get( - f"/vector_stores/{vector_store_id}/file_batches/{batch_id}", + path_template( + "/vector_stores/{vector_store_id}/file_batches/{batch_id}", + vector_store_id=vector_store_id, + batch_id=batch_id, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -546,7 +562,11 @@ async def cancel( raise ValueError(f"Expected a non-empty value for `batch_id` but received {batch_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( - f"/vector_stores/{vector_store_id}/file_batches/{batch_id}/cancel", + path_template( + "/vector_stores/{vector_store_id}/file_batches/{batch_id}/cancel", + vector_store_id=vector_store_id, + batch_id=batch_id, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -641,7 +661,11 @@ def list_files( raise ValueError(f"Expected a non-empty value for `batch_id` but received {batch_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( - f"/vector_stores/{vector_store_id}/file_batches/{batch_id}/files", + path_template( + "/vector_stores/{vector_store_id}/file_batches/{batch_id}/files", + vector_store_id=vector_store_id, + batch_id=batch_id, + ), page=AsyncCursorPage[VectorStoreFile], options=make_request_options( extra_headers=extra_headers, diff --git a/src/openai/resources/vector_stores/files.py b/src/openai/resources/vector_stores/files.py index 29f6e879f1..8666434587 100644 --- a/src/openai/resources/vector_stores/files.py +++ b/src/openai/resources/vector_stores/files.py @@ -10,7 +10,7 @@ from ... import _legacy_response from ...types import FileChunkingStrategyParam from ..._types import Body, Omit, Query, Headers, NotGiven, FileTypes, omit, not_given -from ..._utils import is_given, maybe_transform, async_maybe_transform +from ..._utils import is_given, path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -90,7 +90,7 @@ def create( raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( - f"/vector_stores/{vector_store_id}/files", + path_template("/vector_stores/{vector_store_id}/files", vector_store_id=vector_store_id), body=maybe_transform( { "file_id": file_id, @@ -135,7 +135,9 @@ def retrieve( raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get( - f"/vector_stores/{vector_store_id}/files/{file_id}", + path_template( + "/vector_stores/{vector_store_id}/files/{file_id}", vector_store_id=vector_store_id, file_id=file_id + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -179,7 +181,9 @@ def update( raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( - f"/vector_stores/{vector_store_id}/files/{file_id}", + path_template( + "/vector_stores/{vector_store_id}/files/{file_id}", vector_store_id=vector_store_id, file_id=file_id + ), body=maybe_transform({"attributes": attributes}, file_update_params.FileUpdateParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -237,7 +241,7 @@ def list( raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( - f"/vector_stores/{vector_store_id}/files", + path_template("/vector_stores/{vector_store_id}/files", vector_store_id=vector_store_id), page=SyncCursorPage[VectorStoreFile], options=make_request_options( extra_headers=extra_headers, @@ -292,7 +296,9 @@ def delete( raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._delete( - f"/vector_stores/{vector_store_id}/files/{file_id}", + path_template( + "/vector_stores/{vector_store_id}/files/{file_id}", vector_store_id=vector_store_id, file_id=file_id + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -437,7 +443,11 @@ def content( raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( - f"/vector_stores/{vector_store_id}/files/{file_id}/content", + path_template( + "/vector_stores/{vector_store_id}/files/{file_id}/content", + vector_store_id=vector_store_id, + file_id=file_id, + ), page=SyncPage[FileContentResponse], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -511,7 +521,7 @@ async def create( raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( - f"/vector_stores/{vector_store_id}/files", + path_template("/vector_stores/{vector_store_id}/files", vector_store_id=vector_store_id), body=await async_maybe_transform( { "file_id": file_id, @@ -556,7 +566,9 @@ async def retrieve( raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._get( - f"/vector_stores/{vector_store_id}/files/{file_id}", + path_template( + "/vector_stores/{vector_store_id}/files/{file_id}", vector_store_id=vector_store_id, file_id=file_id + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -600,7 +612,9 @@ async def update( raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( - f"/vector_stores/{vector_store_id}/files/{file_id}", + path_template( + "/vector_stores/{vector_store_id}/files/{file_id}", vector_store_id=vector_store_id, file_id=file_id + ), body=await async_maybe_transform({"attributes": attributes}, file_update_params.FileUpdateParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -658,7 +672,7 @@ def list( raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( - f"/vector_stores/{vector_store_id}/files", + path_template("/vector_stores/{vector_store_id}/files", vector_store_id=vector_store_id), page=AsyncCursorPage[VectorStoreFile], options=make_request_options( extra_headers=extra_headers, @@ -713,7 +727,9 @@ async def delete( raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._delete( - f"/vector_stores/{vector_store_id}/files/{file_id}", + path_template( + "/vector_stores/{vector_store_id}/files/{file_id}", vector_store_id=vector_store_id, file_id=file_id + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -860,7 +876,11 @@ def content( raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( - f"/vector_stores/{vector_store_id}/files/{file_id}/content", + path_template( + "/vector_stores/{vector_store_id}/files/{file_id}/content", + vector_store_id=vector_store_id, + file_id=file_id, + ), page=AsyncPage[FileContentResponse], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout diff --git a/src/openai/resources/vector_stores/vector_stores.py b/src/openai/resources/vector_stores/vector_stores.py index 490e3e7fdb..7fa2ad5274 100644 --- a/src/openai/resources/vector_stores/vector_stores.py +++ b/src/openai/resources/vector_stores/vector_stores.py @@ -24,7 +24,7 @@ vector_store_update_params, ) from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform +from ..._utils import path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -171,7 +171,7 @@ def retrieve( raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get( - f"/vector_stores/{vector_store_id}", + path_template("/vector_stores/{vector_store_id}", vector_store_id=vector_store_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -219,7 +219,7 @@ def update( raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( - f"/vector_stores/{vector_store_id}", + path_template("/vector_stores/{vector_store_id}", vector_store_id=vector_store_id), body=maybe_transform( { "expires_after": expires_after, @@ -326,7 +326,7 @@ def delete( raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._delete( - f"/vector_stores/{vector_store_id}", + path_template("/vector_stores/{vector_store_id}", vector_store_id=vector_store_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -377,7 +377,7 @@ def search( raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( - f"/vector_stores/{vector_store_id}/search", + path_template("/vector_stores/{vector_store_id}/search", vector_store_id=vector_store_id), page=SyncPage[VectorStoreSearchResponse], body=maybe_transform( { @@ -521,7 +521,7 @@ async def retrieve( raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._get( - f"/vector_stores/{vector_store_id}", + path_template("/vector_stores/{vector_store_id}", vector_store_id=vector_store_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -569,7 +569,7 @@ async def update( raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( - f"/vector_stores/{vector_store_id}", + path_template("/vector_stores/{vector_store_id}", vector_store_id=vector_store_id), body=await async_maybe_transform( { "expires_after": expires_after, @@ -676,7 +676,7 @@ async def delete( raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._delete( - f"/vector_stores/{vector_store_id}", + path_template("/vector_stores/{vector_store_id}", vector_store_id=vector_store_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -727,7 +727,7 @@ def search( raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( - f"/vector_stores/{vector_store_id}/search", + path_template("/vector_stores/{vector_store_id}/search", vector_store_id=vector_store_id), page=AsyncPage[VectorStoreSearchResponse], body=maybe_transform( { diff --git a/src/openai/resources/videos.py b/src/openai/resources/videos.py index f387f55824..a006e64705 100644 --- a/src/openai/resources/videos.py +++ b/src/openai/resources/videos.py @@ -20,7 +20,7 @@ video_download_content_params, ) from .._types import Body, Omit, Query, Headers, NotGiven, FileTypes, omit, not_given -from .._utils import extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform +from .._utils import extract_files, path_template, maybe_transform, deepcopy_minimal, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import ( @@ -227,7 +227,7 @@ def retrieve( if not video_id: raise ValueError(f"Expected a non-empty value for `video_id` but received {video_id!r}") return self._get( - f"/videos/{video_id}", + path_template("/videos/{video_id}", video_id=video_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -312,7 +312,7 @@ def delete( if not video_id: raise ValueError(f"Expected a non-empty value for `video_id` but received {video_id!r}") return self._delete( - f"/videos/{video_id}", + path_template("/videos/{video_id}", video_id=video_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -400,7 +400,7 @@ def download_content( raise ValueError(f"Expected a non-empty value for `video_id` but received {video_id!r}") extra_headers = {"Accept": "application/binary", **(extra_headers or {})} return self._get( - f"/videos/{video_id}/content", + path_template("/videos/{video_id}/content", video_id=video_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -541,7 +541,7 @@ def get_character( if not character_id: raise ValueError(f"Expected a non-empty value for `character_id` but received {character_id!r}") return self._get( - f"/videos/characters/{character_id}", + path_template("/videos/characters/{character_id}", character_id=character_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -577,7 +577,7 @@ def remix( if not video_id: raise ValueError(f"Expected a non-empty value for `video_id` but received {video_id!r}") return self._post( - f"/videos/{video_id}/remix", + path_template("/videos/{video_id}/remix", video_id=video_id), body=maybe_transform({"prompt": prompt}, video_remix_params.VideoRemixParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -768,7 +768,7 @@ async def retrieve( if not video_id: raise ValueError(f"Expected a non-empty value for `video_id` but received {video_id!r}") return await self._get( - f"/videos/{video_id}", + path_template("/videos/{video_id}", video_id=video_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -853,7 +853,7 @@ async def delete( if not video_id: raise ValueError(f"Expected a non-empty value for `video_id` but received {video_id!r}") return await self._delete( - f"/videos/{video_id}", + path_template("/videos/{video_id}", video_id=video_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -941,7 +941,7 @@ async def download_content( raise ValueError(f"Expected a non-empty value for `video_id` but received {video_id!r}") extra_headers = {"Accept": "application/binary", **(extra_headers or {})} return await self._get( - f"/videos/{video_id}/content", + path_template("/videos/{video_id}/content", video_id=video_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -1084,7 +1084,7 @@ async def get_character( if not character_id: raise ValueError(f"Expected a non-empty value for `character_id` but received {character_id!r}") return await self._get( - f"/videos/characters/{character_id}", + path_template("/videos/characters/{character_id}", character_id=character_id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1120,7 +1120,7 @@ async def remix( if not video_id: raise ValueError(f"Expected a non-empty value for `video_id` but received {video_id!r}") return await self._post( - f"/videos/{video_id}/remix", + path_template("/videos/{video_id}/remix", video_id=video_id), body=await async_maybe_transform({"prompt": prompt}, video_remix_params.VideoRemixParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout diff --git a/tests/test_utils/test_path.py b/tests/test_utils/test_path.py new file mode 100644 index 0000000000..420cd19973 --- /dev/null +++ b/tests/test_utils/test_path.py @@ -0,0 +1,89 @@ +from __future__ import annotations + +from typing import Any + +import pytest + +from openai._utils._path import path_template + + +@pytest.mark.parametrize( + "template, kwargs, expected", + [ + ("/v1/{id}", dict(id="abc"), "/v1/abc"), + ("/v1/{a}/{b}", dict(a="x", b="y"), "/v1/x/y"), + ("/v1/{a}{b}/path/{c}?val={d}#{e}", dict(a="x", b="y", c="z", d="u", e="v"), "/v1/xy/path/z?val=u#v"), + ("/{w}/{w}", dict(w="echo"), "/echo/echo"), + ("/v1/static", {}, "/v1/static"), + ("", {}, ""), + ("/v1/?q={n}&count=10", dict(n=42), "/v1/?q=42&count=10"), + ("/v1/{v}", dict(v=None), "/v1/null"), + ("/v1/{v}", dict(v=True), "/v1/true"), + ("/v1/{v}", dict(v=False), "/v1/false"), + ("/v1/{v}", dict(v=".hidden"), "/v1/.hidden"), # dot prefix ok + ("/v1/{v}", dict(v="file.txt"), "/v1/file.txt"), # dot in middle ok + ("/v1/{v}", dict(v="..."), "/v1/..."), # triple dot ok + ("/v1/{a}{b}", dict(a=".", b="txt"), "/v1/.txt"), # dot var combining with adjacent to be ok + ("/items?q={v}#{f}", dict(v=".", f=".."), "/items?q=.#.."), # dots in query/fragment are fine + ( + "/v1/{a}?query={b}", + dict(a="../../other/endpoint", b="a&bad=true"), + "/v1/..%2F..%2Fother%2Fendpoint?query=a%26bad%3Dtrue", + ), + ("/v1/{val}", dict(val="a/b/c"), "/v1/a%2Fb%2Fc"), + ("/v1/{val}", dict(val="a/b/c?query=value"), "/v1/a%2Fb%2Fc%3Fquery=value"), + ("/v1/{val}", dict(val="a/b/c?query=value&bad=true"), "/v1/a%2Fb%2Fc%3Fquery=value&bad=true"), + ("/v1/{val}", dict(val="%20"), "/v1/%2520"), # escapes escape sequences in input + # Query: slash and ? are safe, # is not + ("/items?q={v}", dict(v="a/b"), "/items?q=a/b"), + ("/items?q={v}", dict(v="a?b"), "/items?q=a?b"), + ("/items?q={v}", dict(v="a#b"), "/items?q=a%23b"), + ("/items?q={v}", dict(v="a b"), "/items?q=a%20b"), + # Fragment: slash and ? are safe + ("/docs#{v}", dict(v="a/b"), "/docs#a/b"), + ("/docs#{v}", dict(v="a?b"), "/docs#a?b"), + # Path: slash, ? and # are all encoded + ("/v1/{v}", dict(v="a/b"), "/v1/a%2Fb"), + ("/v1/{v}", dict(v="a?b"), "/v1/a%3Fb"), + ("/v1/{v}", dict(v="a#b"), "/v1/a%23b"), + # same var encoded differently by component + ( + "/v1/{v}?q={v}#{v}", + dict(v="a/b?c#d"), + "/v1/a%2Fb%3Fc%23d?q=a/b?c%23d#a/b?c%23d", + ), + ("/v1/{val}", dict(val="x?admin=true"), "/v1/x%3Fadmin=true"), # query injection + ("/v1/{val}", dict(val="x#admin"), "/v1/x%23admin"), # fragment injection + ], +) +def test_interpolation(template: str, kwargs: dict[str, Any], expected: str) -> None: + assert path_template(template, **kwargs) == expected + + +def test_missing_kwarg_raises_key_error() -> None: + with pytest.raises(KeyError, match="org_id"): + path_template("/v1/{org_id}") + + +@pytest.mark.parametrize( + "template, kwargs", + [ + ("{a}/path", dict(a=".")), + ("{a}/path", dict(a="..")), + ("/v1/{a}", dict(a=".")), + ("/v1/{a}", dict(a="..")), + ("/v1/{a}/path", dict(a=".")), + ("/v1/{a}/path", dict(a="..")), + ("/v1/{a}{b}", dict(a=".", b=".")), # adjacent vars → ".." + ("/v1/{a}.", dict(a=".")), # var + static → ".." + ("/v1/{a}{b}", dict(a="", b=".")), # empty + dot → "." + ("/v1/%2e/{x}", dict(x="ok")), # encoded dot in static text + ("/v1/%2e./{x}", dict(x="ok")), # mixed encoded ".." in static + ("/v1/.%2E/{x}", dict(x="ok")), # mixed encoded ".." in static + ("/v1/{v}?q=1", dict(v="..")), + ("/v1/{v}#frag", dict(v="..")), + ], +) +def test_dot_segment_rejected(template: str, kwargs: dict[str, Any]) -> None: + with pytest.raises(ValueError, match="dot-segment"): + path_template(template, **kwargs)