From b50a532cc8faab872ecbeadc0ab2a2d54411f8a0 Mon Sep 17 00:00:00 2001 From: benflexcompute Date: Sat, 30 May 2026 14:05:41 -0400 Subject: [PATCH] Fix Flow360 25.8 URL slash handling --- flow360/component/folder.py | 4 +-- flow360/component/simulation/folder.py | 4 +-- flow360/environment.py | 6 ++--- poetry.lock | 2 +- pyproject.toml | 2 +- tests/test_environment.py | 36 ++++++++++++++++++++++++++ 6 files changed, 45 insertions(+), 9 deletions(-) diff --git a/flow360/component/folder.py b/flow360/component/folder.py index 342933cfe..b82f52040 100644 --- a/flow360/component/folder.py +++ b/flow360/component/folder.py @@ -197,7 +197,7 @@ def get_items(self): "expandFields": ["contentInfo"], } - data = RestApi("/v2/items").get(params=payload) + data = RestApi("v2/items").get(params=payload) records = data.get("records", []) all_records.extend(records) total_record_count = data.get("total", 0) @@ -265,7 +265,7 @@ def get_folder_tree(self): "page": 0, "size": 1000, } # it assumes user will not have more than 1000 folders - data = RestApi("/v2/folders").get(params=payload) + data = RestApi("v2/folders").get(params=payload) folder_tree = self._build_folder_tree(data["records"]) return folder_tree diff --git a/flow360/component/simulation/folder.py b/flow360/component/simulation/folder.py index c3ec26084..54ca5e315 100644 --- a/flow360/component/simulation/folder.py +++ b/flow360/component/simulation/folder.py @@ -247,7 +247,7 @@ def get_items(self): "expandFields": ["contentInfo"], } - data = RestApi("/v2/items").get(params=payload) + data = RestApi("v2/items").get(params=payload) records = data.get("records", []) all_records.extend(records) total_record_count = data.get("total", 0) @@ -315,7 +315,7 @@ def get_folder_tree(self): "page": 0, "size": 1000, } # it assumes user will not have more than 1000 folders - data = RestApi("/v2/folders").get(params=payload) + data = RestApi("v2/folders").get(params=payload) folder_tree = self._build_folder_tree(data["records"]) return folder_tree diff --git a/flow360/environment.py b/flow360/environment.py index 589115628..47c4dabeb 100644 --- a/flow360/environment.py +++ b/flow360/environment.py @@ -73,7 +73,7 @@ def get_real_url(self, path: str): :param path: :return: """ - return "/".join([self.web_api_endpoint, path]) + return self.web_api_endpoint.rstrip("/") + "/" + path.lstrip("/") def get_portal_real_url(self, path: str): """ @@ -81,7 +81,7 @@ def get_portal_real_url(self, path: str): :param path: :return: """ - return "/".join([self.portal_web_api_endpoint, path]) + return self.portal_web_api_endpoint.rstrip("/") + "/" + path.lstrip("/") def get_web_real_url(self, path: str): """ @@ -89,7 +89,7 @@ def get_web_real_url(self, path: str): :param path: :return: """ - return "/".join([self.web_url, path]) + return self.web_url.rstrip("/") + "/" + path.lstrip("/") @classmethod def from_config(cls, env_config_name: str): diff --git a/poetry.lock b/poetry.lock index c0986a714..2b14795a7 100644 --- a/poetry.lock +++ b/poetry.lock @@ -6320,4 +6320,4 @@ docs = ["autodoc_pydantic", "cairosvg", "ipython", "jinja2", "jupyter", "myst-pa [metadata] lock-version = "2.1" python-versions = ">=3.9,<3.14" -content-hash = "f17c72d9c531957854141eb35e4eb5e1dfe82303d92c46427ee51650745c095e" +content-hash = "e30b7ed808c06d968a1a0534cedb559584360cf9af9f843e4fecacbd9b143537" diff --git a/pyproject.toml b/pyproject.toml index 8f38fef56..747c9763d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,7 @@ pydantic = ">=2.8,<2.12" pytest = "^7.1.2" click = "^8.1.3" toml = "^0.10.2" -requests = "^2.32.4" +requests = ">=2.32.4,<2.33.0" boto3 = "^1.24.63" numpy = [ { python = "^3.9", version = ">=2.0,<3.0.0" }, diff --git a/tests/test_environment.py b/tests/test_environment.py index 502d152c3..d8033b889 100644 --- a/tests/test_environment.py +++ b/tests/test_environment.py @@ -1,4 +1,6 @@ from flow360 import Env +from flow360.cloud.rest_api import RestApi +from flow360.environment import EnvironmentConfig def test_version(): @@ -6,3 +8,37 @@ def test_version(): print(Env.current) assert Env.current.name == "dev" Env.prod.active() + + +def test_environment_urls_normalize_path_slashes(): + env = EnvironmentConfig( + name="test", + domain="example.com", + web_api_endpoint="https://api.example.com/", + web_url="https://web.example.com/", + portal_web_api_endpoint="https://portal.example.com/", + apikey_profile="default", + ) + + for path in ("v2/folders", "/v2/folders"): + assert env.get_real_url(path) == "https://api.example.com/v2/folders" + assert env.get_portal_real_url(path) == "https://portal.example.com/v2/folders" + assert env.get_web_real_url(path) == "https://web.example.com/v2/folders" + + +def test_rest_api_url_normalizes_with_environment(): + env = EnvironmentConfig( + name="test", + domain="example.com", + web_api_endpoint="https://api.example.com", + web_url="https://web.example.com", + portal_web_api_endpoint="https://portal.example.com", + apikey_profile="default", + ) + + assert env.get_real_url(RestApi("/v2/folders")._url(None)) == ( + "https://api.example.com/v2/folders" + ) + assert env.get_real_url(RestApi("v2/folders")._url(None)) == ( + "https://api.example.com/v2/folders" + )