vws-python-mock 2026.2.22__tar.gz → 2026.2.22.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/CHANGELOG.rst +8 -0
- {vws_python_mock-2026.2.22/src/vws_python_mock.egg-info → vws_python_mock-2026.2.22.2}/PKG-INFO +1 -1
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_requests_mock_server/decorators.py +10 -6
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_respx_mock_server/decorators.py +21 -9
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2/src/vws_python_mock.egg-info}/PKG-INFO +1 -1
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_requests_mock_usage.py +82 -1
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_respx_mock_usage.py +118 -1
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/.git_archival.txt +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/.gitattributes +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/.github/dependabot.yml +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/.github/workflows/dependabot-merge.yml +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/.github/workflows/docker-build.yml +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/.github/workflows/lint.yml +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/.github/workflows/publish-site.yml +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/.github/workflows/release.yml +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/.github/workflows/test.yml +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/.gitignore +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/.pre-commit-config.yaml +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/.prettierrc +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/.vscode/extensions.json +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/.vscode/settings.json +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/CODE_OF_CONDUCT.rst +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/LICENSE +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/MANIFEST.in +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/README.rst +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/admin/__init__.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/admin/create_secrets_files.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/admin/vumark_template.svg +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/ci/__init__.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/ci/decrypt_secret.sh +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/ci/test_custom_linters.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/conftest.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/docker-bake.hcl +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/docs/source/__init__.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/docs/source/basic-example.rst +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/docs/source/changelog.rst +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/docs/source/ci-setup.rst +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/docs/source/conf.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/docs/source/contributing.rst +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/docs/source/differences-to-vws.rst +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/docs/source/docker.rst +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/docs/source/getting-started.rst +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/docs/source/httpx-example.rst +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/docs/source/index.rst +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/docs/source/installation.rst +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/docs/source/mock-api-reference.rst +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/docs/source/release-process.rst +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/docs/source/versioning-and-api-stability.rst +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/pyproject.toml +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/secrets.tar.gpg +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/setup.cfg +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/spelling_private_dict.txt +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/__init__.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_base64_decoding.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_constants.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_database_matchers.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_flask_server/Dockerfile +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_flask_server/__init__.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_flask_server/healthcheck.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_flask_server/target_manager.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_flask_server/vwq.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_flask_server/vws.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_mock_common.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_query_tools.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_query_validators/__init__.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_query_validators/accept_header_validators.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_query_validators/auth_validators.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_query_validators/content_length_validators.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_query_validators/content_type_validators.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_query_validators/date_validators.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_query_validators/exceptions.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_query_validators/fields_validators.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_query_validators/image_validators.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_query_validators/include_target_data_validators.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_query_validators/num_results_validators.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_query_validators/project_state_validators.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_requests_mock_server/__init__.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_requests_mock_server/mock_web_query_api.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_requests_mock_server/mock_web_services_api.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_respx_mock_server/__init__.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_services_validators/__init__.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_services_validators/active_flag_validators.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_services_validators/auth_validators.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_services_validators/content_length_validators.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_services_validators/content_type_validators.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_services_validators/date_validators.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_services_validators/exceptions.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_services_validators/image_validators.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_services_validators/json_validators.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_services_validators/key_validators.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_services_validators/metadata_validators.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_services_validators/name_validators.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_services_validators/project_state_validators.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_services_validators/target_validators.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_services_validators/width_validators.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/database.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/database_type.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/image_matchers.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/py.typed +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/states.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/target.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/target_manager.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/target_raters.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/vws_python_mock.egg-info/SOURCES.txt +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/vws_python_mock.egg-info/dependency_links.txt +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/vws_python_mock.egg-info/not-zip-safe +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/vws_python_mock.egg-info/requires.txt +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/vws_python_mock.egg-info/top_level.txt +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/__init__.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/conftest.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/__init__.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/fixtures/__init__.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/fixtures/credentials.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/fixtures/prepared_requests.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/fixtures/vuforia_backends.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_add_target.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_authorization_header.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_content_length.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_database_summary.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_date_header.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_delete_target.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_docker.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_flask_app_usage.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_get_duplicates.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_get_target.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_invalid_given_id.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_invalid_json.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_query.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_target_list.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_target_raters.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_target_summary.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_target_validators.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_unexpected_json.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_update_target.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_vumark_generation_api.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/utils/__init__.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/utils/assertions.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/utils/retries.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/utils/too_many_requests.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/utils/usage_test_helpers.py +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/vuforia_secrets.env.example +0 -0
- {vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/zizmor.yml +0 -0
|
@@ -5,7 +5,7 @@ import time
|
|
|
5
5
|
from collections.abc import Callable, Mapping
|
|
6
6
|
from contextlib import ContextDecorator
|
|
7
7
|
from typing import Any, Literal, Self
|
|
8
|
-
from urllib.parse import
|
|
8
|
+
from urllib.parse import urlparse
|
|
9
9
|
|
|
10
10
|
import requests
|
|
11
11
|
from beartype import BeartypeConf, beartype
|
|
@@ -162,6 +162,7 @@ class MockVWS(ContextDecorator):
|
|
|
162
162
|
callback: _MockCallback,
|
|
163
163
|
delay_seconds: float,
|
|
164
164
|
sleep_fn: Callable[[float], None],
|
|
165
|
+
base_path: str,
|
|
165
166
|
) -> _ResponsesCallback:
|
|
166
167
|
"""Wrap a callback to add a response delay."""
|
|
167
168
|
|
|
@@ -197,9 +198,13 @@ class MockVWS(ContextDecorator):
|
|
|
197
198
|
else:
|
|
198
199
|
body_bytes = raw_body
|
|
199
200
|
|
|
201
|
+
path = request.path_url
|
|
202
|
+
if base_path and path.startswith(base_path):
|
|
203
|
+
path = path[len(base_path) :]
|
|
204
|
+
|
|
200
205
|
request_data = RequestData(
|
|
201
206
|
method=request.method or "",
|
|
202
|
-
path=
|
|
207
|
+
path=path,
|
|
203
208
|
headers=dict(request.headers),
|
|
204
209
|
body=body_bytes,
|
|
205
210
|
)
|
|
@@ -221,11 +226,9 @@ class MockVWS(ContextDecorator):
|
|
|
221
226
|
(self._mock_vws_api, self._base_vws_url),
|
|
222
227
|
(self._mock_vwq_api, self._base_vwq_url),
|
|
223
228
|
):
|
|
229
|
+
base_path = urlparse(url=base_url).path.rstrip("/")
|
|
224
230
|
for route in api.routes:
|
|
225
|
-
url_pattern =
|
|
226
|
-
base=base_url,
|
|
227
|
-
url=f"{route.path_pattern}$",
|
|
228
|
-
)
|
|
231
|
+
url_pattern = base_url.rstrip("/") + route.path_pattern + "$"
|
|
229
232
|
compiled_url_pattern = re.compile(pattern=url_pattern)
|
|
230
233
|
|
|
231
234
|
for http_method in route.http_methods:
|
|
@@ -237,6 +240,7 @@ class MockVWS(ContextDecorator):
|
|
|
237
240
|
callback=original_callback,
|
|
238
241
|
delay_seconds=self._response_delay_seconds,
|
|
239
242
|
sleep_fn=self._sleep_fn,
|
|
243
|
+
base_path=base_path,
|
|
240
244
|
),
|
|
241
245
|
content_type=None,
|
|
242
246
|
)
|
|
@@ -5,7 +5,7 @@ import time
|
|
|
5
5
|
from collections.abc import Callable, Mapping
|
|
6
6
|
from contextlib import ContextDecorator
|
|
7
7
|
from typing import Literal, Self
|
|
8
|
-
from urllib.parse import
|
|
8
|
+
from urllib.parse import urlparse
|
|
9
9
|
|
|
10
10
|
import httpx
|
|
11
11
|
import respx
|
|
@@ -36,19 +36,27 @@ _STRUCTURAL_SIMILARITY_MATCHER = StructuralSimilarityMatcher()
|
|
|
36
36
|
_BRISQUE_TRACKING_RATER = BrisqueTargetTrackingRater()
|
|
37
37
|
|
|
38
38
|
|
|
39
|
-
def _to_request_data(
|
|
39
|
+
def _to_request_data(
|
|
40
|
+
request: httpx.Request,
|
|
41
|
+
*,
|
|
42
|
+
base_path: str,
|
|
43
|
+
) -> RequestData:
|
|
40
44
|
"""Convert an httpx.Request to a RequestData.
|
|
41
45
|
|
|
42
46
|
Args:
|
|
43
47
|
request: The httpx request to convert.
|
|
48
|
+
base_path: The base path prefix to strip from the request path.
|
|
44
49
|
|
|
45
50
|
Returns:
|
|
46
51
|
A RequestData with method, path, headers, and body set.
|
|
47
52
|
"""
|
|
53
|
+
path = request.url.raw_path.decode(encoding="ascii")
|
|
54
|
+
if base_path and path.startswith(base_path):
|
|
55
|
+
path = path[len(base_path) :]
|
|
48
56
|
return RequestData(
|
|
49
57
|
method=request.method,
|
|
50
|
-
path=
|
|
51
|
-
headers=request.headers,
|
|
58
|
+
path=path,
|
|
59
|
+
headers={k.title(): v for k, v in request.headers.items()},
|
|
52
60
|
body=request.content,
|
|
53
61
|
)
|
|
54
62
|
|
|
@@ -155,12 +163,14 @@ class MockVWSForHttpx(ContextDecorator):
|
|
|
155
163
|
def _make_callback(
|
|
156
164
|
self,
|
|
157
165
|
handler: Callable[[RequestData], _ResponseType],
|
|
166
|
+
base_path: str,
|
|
158
167
|
) -> Callable[[httpx.Request], httpx.Response]:
|
|
159
168
|
"""Create a respx-compatible callback from a handler.
|
|
160
169
|
|
|
161
170
|
Args:
|
|
162
171
|
handler: A handler that takes a RequestData and returns a
|
|
163
172
|
response tuple.
|
|
173
|
+
base_path: The base path prefix to strip from the request path.
|
|
164
174
|
|
|
165
175
|
Returns:
|
|
166
176
|
A callback that takes an httpx.Request and returns an
|
|
@@ -183,7 +193,10 @@ class MockVWSForHttpx(ContextDecorator):
|
|
|
183
193
|
Exception: A timeout error is raised when the response
|
|
184
194
|
delay exceeds the read timeout.
|
|
185
195
|
"""
|
|
186
|
-
request_data = _to_request_data(
|
|
196
|
+
request_data = _to_request_data(
|
|
197
|
+
request=request,
|
|
198
|
+
base_path=base_path,
|
|
199
|
+
)
|
|
187
200
|
timeout_info: dict[str, float | None] = request.extensions.get(
|
|
188
201
|
"timeout", {}
|
|
189
202
|
)
|
|
@@ -237,11 +250,9 @@ class MockVWSForHttpx(ContextDecorator):
|
|
|
237
250
|
(self._mock_vws_api, self._base_vws_url),
|
|
238
251
|
(self._mock_vwq_api, self._base_vwq_url),
|
|
239
252
|
):
|
|
253
|
+
base_path = urlparse(url=base_url).path.rstrip("/")
|
|
240
254
|
for route in api.routes:
|
|
241
|
-
url_pattern =
|
|
242
|
-
base=base_url,
|
|
243
|
-
url=f"{route.path_pattern}$",
|
|
244
|
-
)
|
|
255
|
+
url_pattern = base_url.rstrip("/") + route.path_pattern + "$"
|
|
245
256
|
compiled_url_pattern = re.compile(pattern=url_pattern)
|
|
246
257
|
|
|
247
258
|
for http_method in route.http_methods:
|
|
@@ -252,6 +263,7 @@ class MockVWSForHttpx(ContextDecorator):
|
|
|
252
263
|
).mock(
|
|
253
264
|
side_effect=self._make_callback(
|
|
254
265
|
handler=original_callback,
|
|
266
|
+
base_path=base_path,
|
|
255
267
|
),
|
|
256
268
|
)
|
|
257
269
|
|
{vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_requests_mock_usage.py
RENAMED
|
@@ -5,6 +5,7 @@ import email.utils
|
|
|
5
5
|
import io
|
|
6
6
|
import json
|
|
7
7
|
import socket
|
|
8
|
+
from http import HTTPStatus
|
|
8
9
|
from urllib.parse import urlparse
|
|
9
10
|
|
|
10
11
|
import pytest
|
|
@@ -13,7 +14,7 @@ from beartype import beartype
|
|
|
13
14
|
from freezegun import freeze_time
|
|
14
15
|
from PIL import Image
|
|
15
16
|
from vws import VWS, CloudRecoService
|
|
16
|
-
from vws_auth_tools import rfc_1123_date
|
|
17
|
+
from vws_auth_tools import authorization_header, rfc_1123_date
|
|
17
18
|
|
|
18
19
|
from mock_vws import MissingSchemeError, MockVWS
|
|
19
20
|
from mock_vws.database import CloudDatabase, VuMarkDatabase
|
|
@@ -347,6 +348,86 @@ class TestCustomBaseURLs:
|
|
|
347
348
|
timeout=30,
|
|
348
349
|
)
|
|
349
350
|
|
|
351
|
+
@staticmethod
|
|
352
|
+
def test_custom_base_vws_url_with_path_prefix() -> None:
|
|
353
|
+
"""A custom base VWS URL with a path prefix intercepts at the
|
|
354
|
+
prefix.
|
|
355
|
+
"""
|
|
356
|
+
with MockVWS(
|
|
357
|
+
base_vws_url="https://vuforia.vws.example.com/prefix",
|
|
358
|
+
real_http=False,
|
|
359
|
+
):
|
|
360
|
+
with pytest.raises(
|
|
361
|
+
expected_exception=requests.exceptions.ConnectionError
|
|
362
|
+
):
|
|
363
|
+
requests.get(
|
|
364
|
+
url="https://vuforia.vws.example.com/summary",
|
|
365
|
+
timeout=30,
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
requests.get(
|
|
369
|
+
url="https://vuforia.vws.example.com/prefix/summary",
|
|
370
|
+
timeout=30,
|
|
371
|
+
)
|
|
372
|
+
|
|
373
|
+
@staticmethod
|
|
374
|
+
def test_custom_base_vwq_url_with_path_prefix() -> None:
|
|
375
|
+
"""A custom base VWQ URL with a path prefix intercepts at the
|
|
376
|
+
prefix.
|
|
377
|
+
"""
|
|
378
|
+
with MockVWS(
|
|
379
|
+
base_vwq_url="https://vuforia.vwq.example.com/prefix",
|
|
380
|
+
real_http=False,
|
|
381
|
+
):
|
|
382
|
+
with pytest.raises(
|
|
383
|
+
expected_exception=requests.exceptions.ConnectionError
|
|
384
|
+
):
|
|
385
|
+
requests.post(
|
|
386
|
+
url="https://vuforia.vwq.example.com/v1/query",
|
|
387
|
+
timeout=30,
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
requests.post(
|
|
391
|
+
url="https://vuforia.vwq.example.com/prefix/v1/query",
|
|
392
|
+
timeout=30,
|
|
393
|
+
)
|
|
394
|
+
|
|
395
|
+
@staticmethod
|
|
396
|
+
def test_vws_operations_work_with_path_prefix() -> None:
|
|
397
|
+
"""VWS API operations work correctly with a base URL path
|
|
398
|
+
prefix.
|
|
399
|
+
"""
|
|
400
|
+
database = CloudDatabase()
|
|
401
|
+
base_vws_url = "https://vuforia.vws.example.com/prefix"
|
|
402
|
+
|
|
403
|
+
with MockVWS(base_vws_url=base_vws_url) as mock:
|
|
404
|
+
mock.add_cloud_database(cloud_database=database)
|
|
405
|
+
|
|
406
|
+
request_path = "/targets"
|
|
407
|
+
date = rfc_1123_date()
|
|
408
|
+
auth = authorization_header(
|
|
409
|
+
access_key=database.server_access_key,
|
|
410
|
+
secret_key=database.server_secret_key,
|
|
411
|
+
method="GET",
|
|
412
|
+
content=b"",
|
|
413
|
+
content_type="",
|
|
414
|
+
date=date,
|
|
415
|
+
request_path=request_path,
|
|
416
|
+
)
|
|
417
|
+
response = requests.get(
|
|
418
|
+
url=base_vws_url + request_path,
|
|
419
|
+
headers={
|
|
420
|
+
"Authorization": auth,
|
|
421
|
+
"Date": date,
|
|
422
|
+
},
|
|
423
|
+
timeout=30,
|
|
424
|
+
)
|
|
425
|
+
|
|
426
|
+
assert response.status_code == HTTPStatus.OK
|
|
427
|
+
response_json = response.json()
|
|
428
|
+
assert response_json["result_code"] == "Success"
|
|
429
|
+
assert response_json["results"] == []
|
|
430
|
+
|
|
350
431
|
@staticmethod
|
|
351
432
|
def test_no_scheme() -> None:
|
|
352
433
|
"""An error if raised if a URL is given with no scheme."""
|
{vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_respx_mock_usage.py
RENAMED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
"""Tests for the usage of the mock for ``httpx`` via ``respx``."""
|
|
2
2
|
|
|
3
|
+
import json
|
|
3
4
|
import socket
|
|
5
|
+
import uuid
|
|
6
|
+
from http import HTTPMethod, HTTPStatus
|
|
4
7
|
|
|
5
8
|
import httpx
|
|
6
9
|
import pytest
|
|
7
|
-
from vws_auth_tools import rfc_1123_date
|
|
10
|
+
from vws_auth_tools import authorization_header, rfc_1123_date
|
|
8
11
|
|
|
9
12
|
from mock_vws import MissingSchemeError, MockVWSForHttpx
|
|
10
13
|
from mock_vws.database import CloudDatabase, VuMarkDatabase
|
|
14
|
+
from mock_vws.target import VuMarkTarget
|
|
11
15
|
|
|
12
16
|
|
|
13
17
|
def _request_unmocked_address() -> None:
|
|
@@ -208,6 +212,82 @@ class TestCustomBaseURLs:
|
|
|
208
212
|
timeout=30,
|
|
209
213
|
)
|
|
210
214
|
|
|
215
|
+
@staticmethod
|
|
216
|
+
def test_custom_base_vws_url_with_path_prefix() -> None:
|
|
217
|
+
"""A custom base VWS URL with a path prefix intercepts at the
|
|
218
|
+
prefix.
|
|
219
|
+
"""
|
|
220
|
+
with MockVWSForHttpx(
|
|
221
|
+
base_vws_url="https://vuforia.vws.example.com/prefix",
|
|
222
|
+
real_http=False,
|
|
223
|
+
):
|
|
224
|
+
with pytest.raises(expected_exception=httpx.ConnectError):
|
|
225
|
+
httpx.get(
|
|
226
|
+
url="https://vuforia.vws.example.com/summary",
|
|
227
|
+
timeout=30,
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
httpx.get(
|
|
231
|
+
url="https://vuforia.vws.example.com/prefix/summary",
|
|
232
|
+
timeout=30,
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
@staticmethod
|
|
236
|
+
def test_custom_base_vwq_url_with_path_prefix() -> None:
|
|
237
|
+
"""A custom base VWQ URL with a path prefix intercepts at the
|
|
238
|
+
prefix.
|
|
239
|
+
"""
|
|
240
|
+
with MockVWSForHttpx(
|
|
241
|
+
base_vwq_url="https://vuforia.vwq.example.com/prefix",
|
|
242
|
+
real_http=False,
|
|
243
|
+
):
|
|
244
|
+
with pytest.raises(expected_exception=httpx.ConnectError):
|
|
245
|
+
httpx.post(
|
|
246
|
+
url="https://vuforia.vwq.example.com/v1/query",
|
|
247
|
+
timeout=30,
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
httpx.post(
|
|
251
|
+
url="https://vuforia.vwq.example.com/prefix/v1/query",
|
|
252
|
+
timeout=30,
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
@staticmethod
|
|
256
|
+
def test_vws_operations_work_with_path_prefix() -> None:
|
|
257
|
+
"""VWS API operations work correctly with a base URL path
|
|
258
|
+
prefix.
|
|
259
|
+
"""
|
|
260
|
+
database = CloudDatabase()
|
|
261
|
+
base_vws_url = "https://vuforia.vws.example.com/prefix"
|
|
262
|
+
|
|
263
|
+
with MockVWSForHttpx(base_vws_url=base_vws_url) as mock:
|
|
264
|
+
mock.add_cloud_database(cloud_database=database)
|
|
265
|
+
|
|
266
|
+
request_path = "/targets"
|
|
267
|
+
date = rfc_1123_date()
|
|
268
|
+
auth = authorization_header(
|
|
269
|
+
access_key=database.server_access_key,
|
|
270
|
+
secret_key=database.server_secret_key,
|
|
271
|
+
method="GET",
|
|
272
|
+
content=b"",
|
|
273
|
+
content_type="",
|
|
274
|
+
date=date,
|
|
275
|
+
request_path=request_path,
|
|
276
|
+
)
|
|
277
|
+
response = httpx.get(
|
|
278
|
+
url=base_vws_url + request_path,
|
|
279
|
+
headers={
|
|
280
|
+
"Authorization": auth,
|
|
281
|
+
"Date": date,
|
|
282
|
+
},
|
|
283
|
+
timeout=30,
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
assert response.status_code == HTTPStatus.OK
|
|
287
|
+
response_json = response.json()
|
|
288
|
+
assert response_json["result_code"] == "Success"
|
|
289
|
+
assert response_json["results"] == []
|
|
290
|
+
|
|
211
291
|
@staticmethod
|
|
212
292
|
def test_no_scheme() -> None:
|
|
213
293
|
"""An error is raised if a URL is given with no scheme."""
|
|
@@ -348,3 +428,40 @@ class TestVWSEndpoints:
|
|
|
348
428
|
)
|
|
349
429
|
# We just verify we get a response (auth will fail but endpoint works)
|
|
350
430
|
assert response.status_code is not None
|
|
431
|
+
|
|
432
|
+
@staticmethod
|
|
433
|
+
def test_vumark_bytes_response() -> None:
|
|
434
|
+
"""The VuMark endpoint returns bytes content via httpx."""
|
|
435
|
+
vumark_target = VuMarkTarget(name="test-target")
|
|
436
|
+
database = VuMarkDatabase(vumark_targets={vumark_target})
|
|
437
|
+
target_id = vumark_target.target_id
|
|
438
|
+
request_path = f"/targets/{target_id}/instances"
|
|
439
|
+
content_type = "application/json"
|
|
440
|
+
content = json.dumps(obj={"instance_id": uuid.uuid4().hex}).encode(
|
|
441
|
+
encoding="utf-8"
|
|
442
|
+
)
|
|
443
|
+
date = rfc_1123_date()
|
|
444
|
+
auth = authorization_header(
|
|
445
|
+
access_key=database.server_access_key,
|
|
446
|
+
secret_key=database.server_secret_key,
|
|
447
|
+
method=HTTPMethod.POST,
|
|
448
|
+
content=content,
|
|
449
|
+
content_type=content_type,
|
|
450
|
+
date=date,
|
|
451
|
+
request_path=request_path,
|
|
452
|
+
)
|
|
453
|
+
with MockVWSForHttpx() as mock:
|
|
454
|
+
mock.add_vumark_database(vumark_database=database)
|
|
455
|
+
response = httpx.post(
|
|
456
|
+
url="https://vws.vuforia.com" + request_path,
|
|
457
|
+
headers={
|
|
458
|
+
"Accept": "image/png",
|
|
459
|
+
"Authorization": auth,
|
|
460
|
+
"Content-Length": str(object=len(content)),
|
|
461
|
+
"Content-Type": content_type,
|
|
462
|
+
"Date": date,
|
|
463
|
+
},
|
|
464
|
+
content=content,
|
|
465
|
+
timeout=30,
|
|
466
|
+
)
|
|
467
|
+
assert response.status_code == HTTPStatus.OK
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/.github/workflows/dependabot-merge.yml
RENAMED
|
File without changes
|
{vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/.github/workflows/docker-build.yml
RENAMED
|
File without changes
|
|
File without changes
|
{vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/.github/workflows/publish-site.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/docs/source/differences-to-vws.rst
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/docs/source/mock-api-reference.rst
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_database_matchers.py
RENAMED
|
File without changes
|
{vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_flask_server/Dockerfile
RENAMED
|
File without changes
|
{vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_flask_server/__init__.py
RENAMED
|
File without changes
|
{vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_flask_server/healthcheck.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/mock_vws/_query_validators/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/vws_python_mock.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/vws_python_mock.egg-info/not-zip-safe
RENAMED
|
File without changes
|
{vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/vws_python_mock.egg-info/requires.txt
RENAMED
|
File without changes
|
{vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/src/vws_python_mock.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/fixtures/__init__.py
RENAMED
|
File without changes
|
{vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/fixtures/credentials.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_content_length.py
RENAMED
|
File without changes
|
{vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_database_summary.py
RENAMED
|
File without changes
|
{vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_date_header.py
RENAMED
|
File without changes
|
{vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_delete_target.py
RENAMED
|
File without changes
|
|
File without changes
|
{vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_flask_app_usage.py
RENAMED
|
File without changes
|
{vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_get_duplicates.py
RENAMED
|
File without changes
|
|
File without changes
|
{vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_invalid_given_id.py
RENAMED
|
File without changes
|
{vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_invalid_json.py
RENAMED
|
File without changes
|
|
File without changes
|
{vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_target_list.py
RENAMED
|
File without changes
|
{vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_target_raters.py
RENAMED
|
File without changes
|
{vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_target_summary.py
RENAMED
|
File without changes
|
{vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_target_validators.py
RENAMED
|
File without changes
|
{vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_unexpected_json.py
RENAMED
|
File without changes
|
{vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/test_update_target.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/utils/assertions.py
RENAMED
|
File without changes
|
|
File without changes
|
{vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/utils/too_many_requests.py
RENAMED
|
File without changes
|
{vws_python_mock-2026.2.22 → vws_python_mock-2026.2.22.2}/tests/mock_vws/utils/usage_test_helpers.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|