diff --git a/pyproject.toml b/pyproject.toml index 8a13280e..f1baeabe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -82,7 +82,7 @@ optional-dependencies.dev = [ "ty==0.0.17", "types-requests==2.32.4.20260107", "vulture==2.14", - "vws-python-mock==2026.2.21", + "vws-python-mock==2026.2.22.2", "vws-test-fixtures==2023.3.5", "yamlfix==1.19.1", "zizmor==1.22.0", diff --git a/src/vws/_vws_request.py b/src/vws/_vws_request.py index 0ea91438..2fc7bd3b 100644 --- a/src/vws/_vws_request.py +++ b/src/vws/_vws_request.py @@ -2,8 +2,6 @@ API. """ -from urllib.parse import urljoin - import requests from beartype import BeartypeConf, beartype from vws_auth_tools import authorization_header, rfc_1123_date @@ -64,7 +62,7 @@ def target_api_request( **extra_headers, } - url = urljoin(base=base_vws_url, url=request_path) + url = base_vws_url.rstrip("/") + request_path requests_response = requests.request( method=method, diff --git a/src/vws/query.py b/src/vws/query.py index 9c997177..f5046bd1 100644 --- a/src/vws/query.py +++ b/src/vws/query.py @@ -5,7 +5,6 @@ import json from http import HTTPMethod, HTTPStatus from typing import Any, BinaryIO -from urllib.parse import urljoin import requests from beartype import BeartypeConf, beartype @@ -146,7 +145,7 @@ def query( requests_response = requests.request( method=method, - url=urljoin(base=self._base_vwq_url, url=request_path), + url=self._base_vwq_url.rstrip("/") + request_path, headers=headers, data=content, timeout=self._request_timeout_seconds, diff --git a/tests/test_query.py b/tests/test_query.py index b7f9687d..66d59611 100644 --- a/tests/test_query.py +++ b/tests/test_query.py @@ -190,6 +190,39 @@ def test_custom_base_url(image: io.BytesIO | BinaryIO) -> None: match = matches[0] assert match.target_id == target_id + @staticmethod + def test_custom_base_url_with_path_prefix( + image: io.BytesIO | BinaryIO, + ) -> None: + """ + A base VWQ URL with a path prefix is used as-is, without the + prefix being dropped. + """ + base_vwq_url = "http://example.com/prefix" + with MockVWS(base_vwq_url=base_vwq_url) as mock: + database = CloudDatabase() + mock.add_cloud_database(cloud_database=database) + vws_client = VWS( + server_access_key=database.server_access_key, + server_secret_key=database.server_secret_key, + ) + target_id = vws_client.add_target( + name="x", + width=1, + image=image, + active_flag=True, + application_metadata=None, + ) + vws_client.wait_for_target_processed(target_id=target_id) + cloud_reco_client = CloudRecoService( + client_access_key=database.client_access_key, + client_secret_key=database.client_secret_key, + base_vwq_url=base_vwq_url, + ) + + matches = cloud_reco_client.query(image=image) + assert len(matches) == 1 + class TestMaxNumResults: """Tests for the ``max_num_results`` parameter of ``query``.""" diff --git a/tests/test_vws.py b/tests/test_vws.py index 0b435503..29bd3aa3 100644 --- a/tests/test_vws.py +++ b/tests/test_vws.py @@ -246,6 +246,24 @@ def test_custom_base_url(image: io.BytesIO | BinaryIO) -> None: application_metadata=None, ) + @staticmethod + def test_custom_base_url_with_path_prefix() -> None: + """ + A base VWS URL with a path prefix is used as-is, without the + prefix being dropped. + """ + base_vws_url = "http://example.com/prefix" + with MockVWS(base_vws_url=base_vws_url) as mock: + database = CloudDatabase() + mock.add_cloud_database(cloud_database=database) + vws_client = VWS( + server_access_key=database.server_access_key, + server_secret_key=database.server_secret_key, + base_vws_url=base_vws_url, + ) + + assert not vws_client.list_targets() + class TestListTargets: """Tests for listing targets."""