Skip to content

Commit 5182d36

Browse files
fix: sanitize endpoint path params
1 parent 0993026 commit 5182d36

2 files changed

Lines changed: 64 additions & 19 deletions

File tree

src/runloop_api_client/_utils/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# isort: skip_file
2+
from ._path import path_template as path_template
23
from ._sync import asyncify as asyncify
34
from ._proxy import LazyProxy as LazyProxy
45
from ._utils import (

src/runloop_api_client/resources/devboxes/executions.py

Lines changed: 63 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import httpx
1010

1111
from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
12-
from ..._utils import is_given, maybe_transform, async_maybe_transform
12+
from ..._utils import is_given, path_template, maybe_transform, async_maybe_transform
1313
from ..._compat import cached_property
1414
from ..._resource import SyncAPIResource, AsyncAPIResource
1515
from ..._response import (
@@ -104,7 +104,9 @@ def retrieve(
104104
if not execution_id:
105105
raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}")
106106
return self._get(
107-
f"/v1/devboxes/{devbox_id}/executions/{execution_id}",
107+
path_template(
108+
"/v1/devboxes/{devbox_id}/executions/{execution_id}", devbox_id=devbox_id, execution_id=execution_id
109+
),
108110
options=make_request_options(
109111
extra_headers=extra_headers,
110112
extra_query=extra_query,
@@ -210,7 +212,7 @@ def execute_async(
210212
if not id:
211213
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
212214
return self._post(
213-
f"/v1/devboxes/{id}/execute_async",
215+
path_template("/v1/devboxes/{id}/execute_async", id=id),
214216
body=maybe_transform(
215217
{
216218
"command": command,
@@ -278,7 +280,7 @@ def execute_sync(
278280
if not is_given(timeout) and self._client.timeout == DEFAULT_TIMEOUT:
279281
timeout = 600
280282
return self._post(
281-
f"/v1/devboxes/{id}/execute_sync",
283+
path_template("/v1/devboxes/{id}/execute_sync", id=id),
282284
body=maybe_transform(
283285
{
284286
"command": command,
@@ -334,7 +336,11 @@ def kill(
334336
if not execution_id:
335337
raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}")
336338
return self._post(
337-
f"/v1/devboxes/{devbox_id}/executions/{execution_id}/kill",
339+
path_template(
340+
"/v1/devboxes/{devbox_id}/executions/{execution_id}/kill",
341+
devbox_id=devbox_id,
342+
execution_id=execution_id,
343+
),
338344
body=maybe_transform({"kill_process_group": kill_process_group}, execution_kill_params.ExecutionKillParams),
339345
options=make_request_options(
340346
extra_headers=extra_headers,
@@ -384,7 +390,11 @@ def send_std_in(
384390
if not execution_id:
385391
raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}")
386392
return self._post(
387-
f"/v1/devboxes/{devbox_id}/executions/{execution_id}/send_std_in",
393+
path_template(
394+
"/v1/devboxes/{devbox_id}/executions/{execution_id}/send_std_in",
395+
devbox_id=devbox_id,
396+
execution_id=execution_id,
397+
),
388398
body=maybe_transform(
389399
{
390400
"signal": signal,
@@ -435,12 +445,18 @@ def stream_stderr_updates(
435445
if not execution_id:
436446
raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}")
437447

448+
stream_path = path_template(
449+
"/v1/devboxes/{devbox_id}/executions/{execution_id}/stream_stderr_updates",
450+
devbox_id=devbox_id,
451+
execution_id=execution_id,
452+
)
453+
438454
default_headers: Headers = {"Accept": "text/event-stream"}
439455
merged_headers = default_headers if extra_headers is None else {**default_headers, **extra_headers}
440456

441457
if merged_headers and merged_headers.get(RAW_RESPONSE_HEADER):
442458
return self._get(
443-
f"/v1/devboxes/{devbox_id}/executions/{execution_id}/stream_stderr_updates",
459+
stream_path,
444460
options=make_request_options(
445461
extra_headers=merged_headers,
446462
extra_query=extra_query,
@@ -458,7 +474,7 @@ def stream_stderr_updates(
458474
def create_stream(last_offset: str | None) -> Stream[ExecutionUpdateChunk]:
459475
new_offset = last_offset if last_offset is not None else (None if isinstance(offset, NotGiven) else offset)
460476
return self._get(
461-
f"/v1/devboxes/{devbox_id}/executions/{execution_id}/stream_stderr_updates",
477+
stream_path,
462478
options=make_request_options(
463479
extra_headers=merged_headers,
464480
extra_query=extra_query,
@@ -520,12 +536,18 @@ def stream_stdout_updates(
520536
if not execution_id:
521537
raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}")
522538

539+
stream_path = path_template(
540+
"/v1/devboxes/{devbox_id}/executions/{execution_id}/stream_stdout_updates",
541+
devbox_id=devbox_id,
542+
execution_id=execution_id,
543+
)
544+
523545
default_headers: Headers = {"Accept": "text/event-stream"}
524546
merged_headers = default_headers if extra_headers is None else {**default_headers, **extra_headers}
525547

526548
if merged_headers and merged_headers.get(RAW_RESPONSE_HEADER):
527549
return self._get(
528-
f"/v1/devboxes/{devbox_id}/executions/{execution_id}/stream_stdout_updates",
550+
stream_path,
529551
options=make_request_options(
530552
extra_headers=merged_headers,
531553
extra_query=extra_query,
@@ -543,7 +565,7 @@ def stream_stdout_updates(
543565
def create_stream(last_offset: str | None) -> Stream[ExecutionUpdateChunk]:
544566
new_offset = last_offset if last_offset is not None else (None if isinstance(offset, NotGiven) else offset)
545567
return self._get(
546-
f"/v1/devboxes/{devbox_id}/executions/{execution_id}/stream_stdout_updates",
568+
stream_path,
547569
options=make_request_options(
548570
extra_headers=merged_headers,
549571
extra_query=extra_query,
@@ -626,7 +648,9 @@ async def retrieve(
626648
if not execution_id:
627649
raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}")
628650
return await self._get(
629-
f"/v1/devboxes/{devbox_id}/executions/{execution_id}",
651+
path_template(
652+
"/v1/devboxes/{devbox_id}/executions/{execution_id}", devbox_id=devbox_id, execution_id=execution_id
653+
),
630654
options=make_request_options(
631655
extra_headers=extra_headers,
632656
extra_query=extra_query,
@@ -730,7 +754,7 @@ async def execute_async(
730754
if not id:
731755
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
732756
return await self._post(
733-
f"/v1/devboxes/{id}/execute_async",
757+
path_template("/v1/devboxes/{id}/execute_async", id=id),
734758
body=await async_maybe_transform(
735759
{
736760
"command": command,
@@ -798,7 +822,7 @@ async def execute_sync(
798822
if not is_given(timeout) and self._client.timeout == DEFAULT_TIMEOUT:
799823
timeout = 600
800824
return await self._post(
801-
f"/v1/devboxes/{id}/execute_sync",
825+
path_template("/v1/devboxes/{id}/execute_sync", id=id),
802826
body=await async_maybe_transform(
803827
{
804828
"command": command,
@@ -854,7 +878,11 @@ async def kill(
854878
if not execution_id:
855879
raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}")
856880
return await self._post(
857-
f"/v1/devboxes/{devbox_id}/executions/{execution_id}/kill",
881+
path_template(
882+
"/v1/devboxes/{devbox_id}/executions/{execution_id}/kill",
883+
devbox_id=devbox_id,
884+
execution_id=execution_id,
885+
),
858886
body=await async_maybe_transform(
859887
{"kill_process_group": kill_process_group}, execution_kill_params.ExecutionKillParams
860888
),
@@ -906,7 +934,11 @@ async def send_std_in(
906934
if not execution_id:
907935
raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}")
908936
return await self._post(
909-
f"/v1/devboxes/{devbox_id}/executions/{execution_id}/send_std_in",
937+
path_template(
938+
"/v1/devboxes/{devbox_id}/executions/{execution_id}/send_std_in",
939+
devbox_id=devbox_id,
940+
execution_id=execution_id,
941+
),
910942
body=await async_maybe_transform(
911943
{
912944
"signal": signal,
@@ -957,12 +989,18 @@ async def stream_stderr_updates(
957989
if not execution_id:
958990
raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}")
959991

992+
stream_path = path_template(
993+
"/v1/devboxes/{devbox_id}/executions/{execution_id}/stream_stderr_updates",
994+
devbox_id=devbox_id,
995+
execution_id=execution_id,
996+
)
997+
960998
default_headers: Headers = {"Accept": "text/event-stream"}
961999
merged_headers = default_headers if extra_headers is None else {**default_headers, **extra_headers}
9621000

9631001
if merged_headers and merged_headers.get(RAW_RESPONSE_HEADER):
9641002
return await self._get(
965-
f"/v1/devboxes/{devbox_id}/executions/{execution_id}/stream_stderr_updates",
1003+
stream_path,
9661004
options=make_request_options(
9671005
extra_headers=merged_headers,
9681006
extra_query=extra_query,
@@ -980,7 +1018,7 @@ async def stream_stderr_updates(
9801018
async def create_stream(last_offset: str | None) -> AsyncStream[ExecutionUpdateChunk]:
9811019
new_offset = last_offset if last_offset is not None else (None if isinstance(offset, NotGiven) else offset)
9821020
return await self._get(
983-
f"/v1/devboxes/{devbox_id}/executions/{execution_id}/stream_stderr_updates",
1021+
stream_path,
9841022
options=make_request_options(
9851023
extra_headers=merged_headers,
9861024
extra_query=extra_query,
@@ -1042,13 +1080,19 @@ async def stream_stdout_updates(
10421080
if not execution_id:
10431081
raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}")
10441082

1083+
stream_path = path_template(
1084+
"/v1/devboxes/{devbox_id}/executions/{execution_id}/stream_stdout_updates",
1085+
devbox_id=devbox_id,
1086+
execution_id=execution_id,
1087+
)
1088+
10451089
default_headers: Headers = {"Accept": "text/event-stream"}
10461090
merged_headers = default_headers if extra_headers is None else {**default_headers, **extra_headers}
10471091

10481092
# If caller requested a raw or streaming response wrapper, return the underlying stream as-is
10491093
if merged_headers and merged_headers.get(RAW_RESPONSE_HEADER):
10501094
return await self._get(
1051-
f"/v1/devboxes/{devbox_id}/executions/{execution_id}/stream_stdout_updates",
1095+
stream_path,
10521096
options=make_request_options(
10531097
extra_headers=merged_headers,
10541098
extra_query=extra_query,
@@ -1066,7 +1110,7 @@ async def stream_stdout_updates(
10661110
async def create_stream(last_offset: str | None) -> AsyncStream[ExecutionUpdateChunk]:
10671111
new_offset = last_offset if last_offset is not None else (None if isinstance(offset, NotGiven) else offset)
10681112
return await self._get(
1069-
f"/v1/devboxes/{devbox_id}/executions/{execution_id}/stream_stdout_updates",
1113+
stream_path,
10701114
options=make_request_options(
10711115
extra_headers=merged_headers,
10721116
extra_query=extra_query,

0 commit comments

Comments
 (0)