diff --git a/packages/nemo_platform_plugin/src/nemo_platform_plugin/client/client.py b/packages/nemo_platform_plugin/src/nemo_platform_plugin/client/client.py index 52707a96fc..f570aa2f07 100644 --- a/packages/nemo_platform_plugin/src/nemo_platform_plugin/client/client.py +++ b/packages/nemo_platform_plugin/src/nemo_platform_plugin/client/client.py @@ -24,6 +24,7 @@ from collections.abc import Mapping from pathlib import Path from typing import Any, Self, TypeVar, get_args, get_origin, overload +from urllib.parse import quote import httpx from nemo_platform_plugin.client.auth import ( @@ -177,8 +178,9 @@ def _resolve_path(self, request: PreparedRequest) -> str: if self._workspace: params["workspace"] = self._workspace params.update(request.path_params) + encoded_params = {name: quote(str(value), safe="") for name, value in params.items()} try: - path = request.path_template.format_map(params) + path = request.path_template.format_map(encoded_params) except KeyError as exc: raise ValueError(f"Missing path parameter {exc} for {request.method} {request.path_template}") from exc return self._base_url + path diff --git a/packages/nemo_platform_plugin/tests/client/test_client.py b/packages/nemo_platform_plugin/tests/client/test_client.py index d415b6e458..cdcdd1c5ca 100644 --- a/packages/nemo_platform_plugin/tests/client/test_client.py +++ b/packages/nemo_platform_plugin/tests/client/test_client.py @@ -101,6 +101,34 @@ def test_send_get_with_path_params() -> None: ) +def test_send_url_encodes_path_params() -> None: + mock_http = MagicMock(spec=httpx.Client) + mock_http.request.return_value = httpx.Response( + 200, + request=httpx.Request("GET", f"{BASE}/apis/test/v2/items/name%20with%20%3F%23%2F"), + json={"id": 1, "name": "encoded"}, + ) + + client = NemoClient(base_url=BASE, http_client=mock_http) + client.send(GET_ITEM(name="name with ?#/")) + + assert mock_http.request.call_args.args[1] == f"{BASE}/apis/test/v2/items/name%20with%20%3F%23%2F" + + +def test_send_url_encodes_default_workspace() -> None: + mock_http = MagicMock(spec=httpx.Client) + mock_http.request.return_value = httpx.Response( + 200, + request=httpx.Request("GET", f"{BASE}/apis/test/v2/workspaces/team%20one%2Fwest/items"), + json={"id": 1, "name": "encoded"}, + ) + + client = NemoClient(base_url=BASE, workspace="team one/west", http_client=mock_http) + client.send(GET_WS_ITEM()) + + assert mock_http.request.call_args.args[1] == f"{BASE}/apis/test/v2/workspaces/team%20one%2Fwest/items" + + def test_send_delete() -> None: mock_http = MagicMock(spec=httpx.Client) mock_http.request.return_value = httpx.Response(