Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/evo-sdk-common/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[project]
name = "evo-sdk-common"
description = "Python package that establishes a common framework for use by client libraries that interact with Seequent Evo APIs"
version = "0.4.2"
version = "0.4.2.a0"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be updated (likely force-push) when confirmed working from the other side of this.

requires-python = ">=3.10"
license-files = ["LICENSE.md"]
dynamic = ["readme"]
Expand Down
8 changes: 4 additions & 4 deletions packages/evo-sdk-common/src/evo/common/io/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from ..exceptions import ForbiddenException, UnauthorizedException
from ..interfaces import IFeedback, ITransport
from ..utils import NoFeedback, Retry
from ..utils.urls import load_base_url
from .bytes import BytesDestination
from .chunked_io_manager import ChunkedIOManager
from .exceptions import ChunkedIOError, RenewalError, RenewalTimeoutError
Expand Down Expand Up @@ -117,10 +118,9 @@ async def __aenter__(self: _T_Self) -> _T_Self:
async with self.__mutex:
if self.__connector is None:
url = await self.__get_new_url()
if not url.startswith("https://"):
raise ValueError("Unsupported URL scheme")
base_url = "https://" + urlparse(url).hostname
self.__connector = APIConnector(base_url=base_url, transport=self.__transport)
self.__connector = APIConnector(
base_url=load_base_url(url, allow_insecure=False), transport=self.__transport
)
self.__update_url(url)
await self.__connector.__aenter__()
return self
Expand Down
24 changes: 24 additions & 0 deletions packages/evo-sdk-common/src/evo/common/utils/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copyright © 2025 Bentley Systems, Incorporated
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Helper for handling URLs."""

from urllib.parse import urlparse


def load_base_url(url: str, *, allow_insecure: bool):
"""Returns the base URL - namely the URL with the path/query components stripped."""
parsed = urlparse(url)
allowed_schemes = ("https", "http") if allow_insecure else ("https",)
if parsed.scheme not in allowed_schemes:
raise ValueError(f"Unsupported URL scheme={parsed.scheme}")
return (
f"{parsed.scheme}://{parsed.hostname}:{parsed.port}" if parsed.port else f"{parsed.scheme}://{parsed.hostname}"
)
39 changes: 39 additions & 0 deletions packages/evo-sdk-common/tests/common/utils/test_urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Copyright © 2025 Bentley Systems, Incorporated
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import pytest

from evo.common.utils import urls


# fmt: off
@pytest.mark.parametrize(
"input,expected",
[

("https://example.com/foo/bar", "https://example.com"),
("https://example.com/foo/bar?a=b&c=d", "https://example.com"),
("http://example.com/foo/bar", "http://example.com"),
("http://example.com/foo/bar?a=b&c=d", "http://example.com"),
("https://example.com:5000/foo/bar", "https://example.com:5000"),
("http://example.com:5000/foo/bar", "http://example.com:5000"),

],
)
# fmt: on
def test_url_parsed_with_insecure_allowed(input: str, expected: str):

assert urls.load_base_url(input, allow_insecure=True) == expected


def test_disallowed_http_if_not_allow_insecure():
assert urls.load_base_url("https://example.com:9000/foo", allow_insecure=False) == "https://example.com:9000"
with pytest.raises(ValueError):
urls.load_base_url("http://example.com:9000/foo", allow_insecure=False)
Loading