vws-python 2026.8.26__tar.gz → 2026.9.7__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-2026.8.26 → vws_python-2026.9.7}/CHANGELOG.rst +5 -0
- {vws_python-2026.8.26/src/vws_python.egg-info → vws_python-2026.9.7}/PKG-INFO +15 -14
- {vws_python-2026.8.26 → vws_python-2026.9.7}/docs/source/index.rst +38 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/pyproject.toml +24 -14
- {vws_python-2026.8.26 → vws_python-2026.9.7}/spelling_private_dict.txt +3 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/src/vws/transports.py +192 -1
- {vws_python-2026.8.26 → vws_python-2026.9.7/src/vws_python.egg-info}/PKG-INFO +15 -14
- {vws_python-2026.8.26 → vws_python-2026.9.7}/src/vws_python.egg-info/requires.txt +14 -13
- vws_python-2026.9.7/src/vws_python.egg-info/scm_version.json +8 -0
- vws_python-2026.9.7/tests/test_transports.py +1111 -0
- vws_python-2026.8.26/src/vws_python.egg-info/scm_version.json +0 -8
- vws_python-2026.8.26/tests/test_transports.py +0 -407
- {vws_python-2026.8.26 → vws_python-2026.9.7}/.git_archival.txt +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/.gitattributes +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/.github/dependabot.yml +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/.github/workflows/autofix.yml +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/.github/workflows/ci.yml +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/.github/workflows/dependabot-merge.yml +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/.github/workflows/lint.yml +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/.github/workflows/publish-site.yml +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/.github/workflows/release.yml +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/.gitignore +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/.prettierrc +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/.vale.ini +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/.vscode/extensions.json +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/.vscode/settings.json +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/CODE_OF_CONDUCT.rst +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/LICENSE +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/README.rst +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/conftest.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/docs/source/__init__.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/docs/source/api-reference.rst +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/docs/source/changelog.rst +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/docs/source/conf.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/docs/source/contributing.rst +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/docs/source/exceptions.rst +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/docs/source/release-process.rst +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/docs/source/unreleased.rst +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/docs/towncrier_template.rst.jinja +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/newsfragments/.gitkeep +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/prek.toml +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/setup.cfg +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/src/vws/__init__.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/src/vws/_async_vws_request.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/src/vws/_image_utils.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/src/vws/_model_targets.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/src/vws/_reco_counts.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/src/vws/_vws_request.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/src/vws/async_model_target_service.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/src/vws/async_query.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/src/vws/async_vumark_service.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/src/vws/async_vws.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/src/vws/exceptions/__init__.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/src/vws/exceptions/base_exceptions.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/src/vws/exceptions/cloud_reco_exceptions.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/src/vws/exceptions/custom_exceptions.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/src/vws/exceptions/model_target_exceptions.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/src/vws/exceptions/vws_exceptions.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/src/vws/include_target_data.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/src/vws/model_target_datasets.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/src/vws/model_target_service.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/src/vws/py.typed +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/src/vws/query.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/src/vws/reports.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/src/vws/response.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/src/vws/vumark_accept.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/src/vws/vumark_service.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/src/vws/vws.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/src/vws_python.egg-info/SOURCES.txt +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/src/vws_python.egg-info/dependency_links.txt +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/src/vws_python.egg-info/not-zip-safe +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/src/vws_python.egg-info/scm_file_list.json +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/src/vws_python.egg-info/top_level.txt +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/tests/__init__.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/tests/conftest.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/tests/test_async_cloud_reco_exceptions.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/tests/test_async_model_targets.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/tests/test_async_query.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/tests/test_async_vws.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/tests/test_async_vws_exceptions.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/tests/test_cloud_reco_exceptions.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/tests/test_model_targets.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/tests/test_query.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/tests/test_vws.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/tests/test_vws_exceptions.py +0 -0
- {vws_python-2026.8.26 → vws_python-2026.9.7}/zizmor.yml +0 -0
|
@@ -3,6 +3,11 @@ Changelog
|
|
|
3
3
|
|
|
4
4
|
.. towncrier release notes start
|
|
5
5
|
|
|
6
|
+
2026.09.07
|
|
7
|
+
----------
|
|
8
|
+
|
|
9
|
+
- Add ``HTTPX2Transport`` and ``AsyncHTTPX2Transport``, which make requests with ``httpx2``, the continuation of ``httpx`` maintained by Pydantic. The ``requests`` and ``httpx`` transports are unchanged. ``httpx`` and ``httpx2`` objects are never mixed: the ``httpx`` transports raise ``httpx`` exceptions and the ``httpx2`` transports raise ``httpx2`` exceptions.
|
|
10
|
+
|
|
6
11
|
2026.08.26
|
|
7
12
|
----------
|
|
8
13
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: vws-python
|
|
3
|
-
Version: 2026.
|
|
3
|
+
Version: 2026.9.7
|
|
4
4
|
Summary: Interact with the Vuforia Web Services (VWS) API.
|
|
5
5
|
Author-email: Adam Dangoor <adamdangoor@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -18,6 +18,7 @@ Description-Content-Type: text/x-rst
|
|
|
18
18
|
License-File: LICENSE
|
|
19
19
|
Requires-Dist: beartype>=0.22.9
|
|
20
20
|
Requires-Dist: httpx>=0.28.0
|
|
21
|
+
Requires-Dist: httpx2>=2.12
|
|
21
22
|
Requires-Dist: requests>=2.32.3
|
|
22
23
|
Requires-Dist: urllib3>=2.2.3
|
|
23
24
|
Requires-Dist: vws-auth-tools>=2024.7.12
|
|
@@ -26,20 +27,20 @@ Requires-Dist: actionlint-py==1.7.12.24; extra == "dev"
|
|
|
26
27
|
Requires-Dist: check-manifest==0.51; extra == "dev"
|
|
27
28
|
Requires-Dist: deptry==0.25.1; extra == "dev"
|
|
28
29
|
Requires-Dist: doc8==2.0.0; extra == "dev"
|
|
29
|
-
Requires-Dist: doccmd==2026.
|
|
30
|
+
Requires-Dist: doccmd==2026.9.1; extra == "dev"
|
|
30
31
|
Requires-Dist: freezegun==1.5.5; extra == "dev"
|
|
31
32
|
Requires-Dist: furo==2025.12.19; extra == "dev"
|
|
32
33
|
Requires-Dist: interrogate==1.7.0; extra == "dev"
|
|
33
34
|
Requires-Dist: mypy[faster-cache]==2.3.1; extra == "dev"
|
|
34
35
|
Requires-Dist: mypy-strict-kwargs==2026.8.25.1; extra == "dev"
|
|
35
|
-
Requires-Dist: no-defaults==
|
|
36
|
-
Requires-Dist: prek==0.
|
|
36
|
+
Requires-Dist: no-defaults==2026.9.1; extra == "dev"
|
|
37
|
+
Requires-Dist: prek==0.5.2; extra == "dev"
|
|
37
38
|
Requires-Dist: pydocstringformatter==1.0.0; extra == "dev"
|
|
38
39
|
Requires-Dist: pydocstyle==6.3; extra == "dev"
|
|
39
40
|
Requires-Dist: pygments==2.21.0; extra == "dev"
|
|
40
|
-
Requires-Dist: pylint[spelling]==4.0.
|
|
41
|
+
Requires-Dist: pylint[spelling]==4.0.8; extra == "dev"
|
|
41
42
|
Requires-Dist: pylint-per-file-ignores==3.2.1; extra == "dev"
|
|
42
|
-
Requires-Dist: pyproject-fmt==2.
|
|
43
|
+
Requires-Dist: pyproject-fmt==2.29.3; extra == "dev"
|
|
43
44
|
Requires-Dist: pyrefly==1.2.0; extra == "dev"
|
|
44
45
|
Requires-Dist: pyright==1.1.411; extra == "dev"
|
|
45
46
|
Requires-Dist: pyroma==5.0.1; extra == "dev"
|
|
@@ -48,9 +49,9 @@ Requires-Dist: pytest-asyncio==1.4.0; extra == "dev"
|
|
|
48
49
|
Requires-Dist: pytest-beartype-tests==2026.8.16; extra == "dev"
|
|
49
50
|
Requires-Dist: pytest-cov==7.1.0; extra == "dev"
|
|
50
51
|
Requires-Dist: pyyaml==6.0.3; extra == "dev"
|
|
51
|
-
Requires-Dist: ruff==0.16.
|
|
52
|
+
Requires-Dist: ruff==0.16.6; extra == "dev"
|
|
52
53
|
Requires-Dist: shellcheck-py==0.11.0.1; extra == "dev"
|
|
53
|
-
Requires-Dist: shfmt-py==4.
|
|
54
|
+
Requires-Dist: shfmt-py==4.1.0; extra == "dev"
|
|
54
55
|
Requires-Dist: sphinx==9.1.0; extra == "dev"
|
|
55
56
|
Requires-Dist: sphinx-copybutton==0.5.2; extra == "dev"
|
|
56
57
|
Requires-Dist: sphinx-lint==1.0.2; extra == "dev"
|
|
@@ -58,17 +59,17 @@ Requires-Dist: sphinx-pyproject==0.3.0; extra == "dev"
|
|
|
58
59
|
Requires-Dist: sphinx-substitution-extensions==2026.8.13.1; extra == "dev"
|
|
59
60
|
Requires-Dist: sphinxcontrib-spelling==8.0.2; extra == "dev"
|
|
60
61
|
Requires-Dist: sphinxcontrib-towncrier==0.5.0a0; extra == "dev"
|
|
61
|
-
Requires-Dist: strict-kwargs==2026.8.
|
|
62
|
+
Requires-Dist: strict-kwargs==2026.8.28.post2; extra == "dev"
|
|
62
63
|
Requires-Dist: sybil==10.1.0; extra == "dev"
|
|
63
64
|
Requires-Dist: towncrier==25.8.0; extra == "dev"
|
|
64
|
-
Requires-Dist: ty==0.0.
|
|
65
|
+
Requires-Dist: ty==0.0.78; extra == "dev"
|
|
65
66
|
Requires-Dist: types-requests==2.33.0.20260712; extra == "dev"
|
|
66
|
-
Requires-Dist: vale==3.
|
|
67
|
+
Requires-Dist: vale==3.20.0.0; extra == "dev"
|
|
67
68
|
Requires-Dist: vulture==2.16; extra == "dev"
|
|
68
|
-
Requires-Dist: vws-python-mock==2026.
|
|
69
|
-
Requires-Dist: vws-test-fixtures==2026.8.
|
|
69
|
+
Requires-Dist: vws-python-mock==2026.9.6; extra == "dev"
|
|
70
|
+
Requires-Dist: vws-test-fixtures==2026.8.26; extra == "dev"
|
|
70
71
|
Requires-Dist: yamlfix==1.19.1; extra == "dev"
|
|
71
|
-
Requires-Dist: zizmor==1.
|
|
72
|
+
Requires-Dist: zizmor==1.30.0; extra == "dev"
|
|
72
73
|
Provides-Extra: release
|
|
73
74
|
Requires-Dist: check-wheel-contents==0.6.3; extra == "release"
|
|
74
75
|
Requires-Dist: towncrier==25.8.0; extra == "release"
|
|
@@ -186,6 +186,44 @@ Dataset generation happens in the background, and the generated dataset is downl
|
|
|
186
186
|
dataset_type=ModelTargetDatasetType.STANDARD,
|
|
187
187
|
)
|
|
188
188
|
|
|
189
|
+
HTTP transports
|
|
190
|
+
---------------
|
|
191
|
+
|
|
192
|
+
By default, the synchronous clients make requests with `requests`_ and the asynchronous clients make requests with `httpx`_.
|
|
193
|
+
To use another HTTP library, pass a transport from :mod:`vws.transports` to a client.
|
|
194
|
+
|
|
195
|
+
Transports are available for `requests`_, `httpx`_ and `HTTPX2`_.
|
|
196
|
+
``httpx`` and ``httpx2`` are separate packages with separate client, response and exception classes.
|
|
197
|
+
``HTTPXTransport`` and ``AsyncHTTPXTransport`` use ``httpx`` and raise ``httpx`` exceptions.
|
|
198
|
+
``HTTPX2Transport`` and ``AsyncHTTPX2Transport`` use ``httpx2`` and raise ``httpx2`` exceptions.
|
|
199
|
+
|
|
200
|
+
.. clear-namespace
|
|
201
|
+
|
|
202
|
+
.. code-block:: python
|
|
203
|
+
|
|
204
|
+
"""List targets using HTTPX2."""
|
|
205
|
+
|
|
206
|
+
import os
|
|
207
|
+
|
|
208
|
+
from vws import VWS
|
|
209
|
+
from vws.transports import HTTPX2Transport
|
|
210
|
+
|
|
211
|
+
server_access_key = os.environ["VWS_SERVER_ACCESS_KEY"]
|
|
212
|
+
server_secret_key = os.environ["VWS_SERVER_SECRET_KEY"]
|
|
213
|
+
|
|
214
|
+
vws_client = VWS(
|
|
215
|
+
server_access_key=server_access_key,
|
|
216
|
+
server_secret_key=server_secret_key,
|
|
217
|
+
transport=HTTPX2Transport(),
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
# This database has no targets.
|
|
221
|
+
assert not vws_client.list_targets()
|
|
222
|
+
|
|
223
|
+
.. _requests: https://pypi.org/project/requests/
|
|
224
|
+
.. _httpx: https://pypi.org/project/httpx/
|
|
225
|
+
.. _HTTPX2: https://httpx2.pydantic.dev/
|
|
226
|
+
|
|
189
227
|
Testing
|
|
190
228
|
-------
|
|
191
229
|
|
|
@@ -33,6 +33,7 @@ dynamic = [
|
|
|
33
33
|
dependencies = [
|
|
34
34
|
"beartype>=0.22.9",
|
|
35
35
|
"httpx>=0.28.0",
|
|
36
|
+
"httpx2>=2.12",
|
|
36
37
|
"requests>=2.32.3",
|
|
37
38
|
"urllib3>=2.2.3",
|
|
38
39
|
"vws-auth-tools>=2024.7.12",
|
|
@@ -42,20 +43,20 @@ optional-dependencies.dev = [
|
|
|
42
43
|
"check-manifest==0.51",
|
|
43
44
|
"deptry==0.25.1",
|
|
44
45
|
"doc8==2.0.0",
|
|
45
|
-
"doccmd==2026.
|
|
46
|
+
"doccmd==2026.9.1",
|
|
46
47
|
"freezegun==1.5.5",
|
|
47
48
|
"furo==2025.12.19",
|
|
48
49
|
"interrogate==1.7.0",
|
|
49
50
|
"mypy[faster-cache]==2.3.1",
|
|
50
51
|
"mypy-strict-kwargs==2026.8.25.1",
|
|
51
|
-
"no-defaults==
|
|
52
|
-
"prek==0.
|
|
52
|
+
"no-defaults==2026.9.1",
|
|
53
|
+
"prek==0.5.2",
|
|
53
54
|
"pydocstringformatter==1.0.0",
|
|
54
55
|
"pydocstyle==6.3",
|
|
55
56
|
"pygments==2.21.0",
|
|
56
|
-
"pylint[spelling]==4.0.
|
|
57
|
+
"pylint[spelling]==4.0.8",
|
|
57
58
|
"pylint-per-file-ignores==3.2.1",
|
|
58
|
-
"pyproject-fmt==2.
|
|
59
|
+
"pyproject-fmt==2.29.3",
|
|
59
60
|
"pyrefly==1.2.0",
|
|
60
61
|
"pyright==1.1.411",
|
|
61
62
|
"pyroma==5.0.1",
|
|
@@ -64,12 +65,12 @@ optional-dependencies.dev = [
|
|
|
64
65
|
"pytest-beartype-tests==2026.8.16",
|
|
65
66
|
"pytest-cov==7.1.0",
|
|
66
67
|
"pyyaml==6.0.3",
|
|
67
|
-
"ruff==0.16.
|
|
68
|
+
"ruff==0.16.6",
|
|
68
69
|
# We add shellcheck-py not only for shell scripts and shell code blocks,
|
|
69
70
|
# but also because having it installed means that ``actionlint-py`` will
|
|
70
71
|
# use it to lint shell commands in GitHub workflow files.
|
|
71
72
|
"shellcheck-py==0.11.0.1",
|
|
72
|
-
"shfmt-py==4.
|
|
73
|
+
"shfmt-py==4.1.0",
|
|
73
74
|
"sphinx==9.1.0",
|
|
74
75
|
"sphinx-copybutton==0.5.2",
|
|
75
76
|
"sphinx-lint==1.0.2",
|
|
@@ -79,17 +80,17 @@ optional-dependencies.dev = [
|
|
|
79
80
|
# ``sphinxcontrib-towncrier`` renders unreleased news fragments
|
|
80
81
|
# into docs/source/unreleased.rst during Sphinx builds.
|
|
81
82
|
"sphinxcontrib-towncrier==0.5.0a0",
|
|
82
|
-
"strict-kwargs==2026.8.
|
|
83
|
+
"strict-kwargs==2026.8.28.post2",
|
|
83
84
|
"sybil==10.1.0",
|
|
84
85
|
"towncrier==25.8.0",
|
|
85
|
-
"ty==0.0.
|
|
86
|
+
"ty==0.0.78",
|
|
86
87
|
"types-requests==2.33.0.20260712",
|
|
87
|
-
"vale==3.
|
|
88
|
+
"vale==3.20.0.0",
|
|
88
89
|
"vulture==2.16",
|
|
89
|
-
"vws-python-mock==2026.
|
|
90
|
-
"vws-test-fixtures==2026.8.
|
|
90
|
+
"vws-python-mock==2026.9.6",
|
|
91
|
+
"vws-test-fixtures==2026.8.26",
|
|
91
92
|
"yamlfix==1.19.1",
|
|
92
|
-
"zizmor==1.
|
|
93
|
+
"zizmor==1.30.0",
|
|
93
94
|
]
|
|
94
95
|
optional-dependencies.release = [ "check-wheel-contents==0.6.3", "towncrier==25.8.0" ]
|
|
95
96
|
urls.Documentation = "https://vws-python.github.io/vws-python/"
|
|
@@ -154,7 +155,9 @@ lint.unfixable = [
|
|
|
154
155
|
"ERA001",
|
|
155
156
|
]
|
|
156
157
|
lint.external = [ "NOD" ]
|
|
157
|
-
lint.flake8-tidy-imports.banned-api."typing.cast".msg = "
|
|
158
|
+
lint.flake8-tidy-imports.banned-api."typing.cast".msg = """\
|
|
159
|
+
typing.cast is banned: use explicit type narrowing or a typed variable instead.\
|
|
160
|
+
"""
|
|
158
161
|
lint.pydocstyle.convention = "google"
|
|
159
162
|
|
|
160
163
|
[tool.pylint]
|
|
@@ -328,6 +331,7 @@ ignore_names = [
|
|
|
328
331
|
"ALWAYS",
|
|
329
332
|
"AR_CONTROLLER",
|
|
330
333
|
# Public API classes imported by users from vws.transports
|
|
334
|
+
"AsyncHTTPX2Transport",
|
|
331
335
|
"AsyncHTTPXTransport",
|
|
332
336
|
"AUTO",
|
|
333
337
|
# Sphinx
|
|
@@ -351,6 +355,7 @@ ignore_names = [
|
|
|
351
355
|
"html_theme_options",
|
|
352
356
|
"html_title",
|
|
353
357
|
"htmlhelp_basename",
|
|
358
|
+
"HTTPX2Transport",
|
|
354
359
|
"HTTPXTransport",
|
|
355
360
|
"IGES",
|
|
356
361
|
"intersphinx_mapping",
|
|
@@ -434,6 +439,11 @@ issue_format = "#{issue}"
|
|
|
434
439
|
# version such as ``2026.05.18`` underlined with ``-`` matches every
|
|
435
440
|
# pre-towncrier entry in CHANGELOG.rst.
|
|
436
441
|
underlines = [ "-", "~", "^" ]
|
|
442
|
+
# Setting ``ignore`` makes ``towncrier build`` fail on any file in
|
|
443
|
+
# the fragment directory whose suffix is not a declared fragment
|
|
444
|
+
# type, instead of silently dropping it. Only the listed
|
|
445
|
+
# non-fragment files are allowed through.
|
|
446
|
+
ignore = [ ".gitkeep" ]
|
|
437
447
|
type = [
|
|
438
448
|
# A single, unnamed fragment type keeps the assembled output as one
|
|
439
449
|
# flat bullet list, matching the historical changelog (which never
|
|
@@ -4,6 +4,7 @@ BadImage
|
|
|
4
4
|
ConnectionErrorPossiblyImageTooLarge
|
|
5
5
|
DateRangeError
|
|
6
6
|
Falsy
|
|
7
|
+
HTTPX2
|
|
7
8
|
ImageTooLarge
|
|
8
9
|
InactiveProject
|
|
9
10
|
JSONDecodeError
|
|
@@ -17,6 +18,7 @@ OopsAnErrorOccurredPossiblyBadNameError
|
|
|
17
18
|
ProjectHasNoApiAccess
|
|
18
19
|
ProjectInactive
|
|
19
20
|
ProjectSuspended
|
|
21
|
+
Pydantic
|
|
20
22
|
QuotaExceeded
|
|
21
23
|
RequestQuotaReached
|
|
22
24
|
RequestTimeTooSkewed
|
|
@@ -65,6 +67,7 @@ html
|
|
|
65
67
|
http
|
|
66
68
|
https
|
|
67
69
|
httpx
|
|
70
|
+
httpx2
|
|
68
71
|
iff
|
|
69
72
|
io
|
|
70
73
|
issuecomment
|
|
@@ -1,8 +1,25 @@
|
|
|
1
|
-
"""HTTP transport implementations for VWS clients.
|
|
1
|
+
"""HTTP transport implementations for VWS clients.
|
|
2
|
+
|
|
3
|
+
Three transport families are available:
|
|
4
|
+
|
|
5
|
+
* ``RequestsTransport`` uses ``requests``. It is synchronous only, and
|
|
6
|
+
is the default transport for the synchronous clients.
|
|
7
|
+
* ``HTTPXTransport`` and ``AsyncHTTPXTransport`` use ``httpx``.
|
|
8
|
+
``AsyncHTTPXTransport`` is the default transport for the
|
|
9
|
+
asynchronous clients.
|
|
10
|
+
* ``HTTPX2Transport`` and ``AsyncHTTPX2Transport`` use ``httpx2``, the
|
|
11
|
+
continuation of ``httpx`` maintained by Pydantic.
|
|
12
|
+
|
|
13
|
+
``httpx`` and ``httpx2`` are separate packages with separate client,
|
|
14
|
+
request, response, timeout and exception classes. Each transport uses
|
|
15
|
+
exactly one of them: the ``httpx`` transports raise ``httpx``
|
|
16
|
+
exceptions, and the ``httpx2`` transports raise ``httpx2`` exceptions.
|
|
17
|
+
"""
|
|
2
18
|
|
|
3
19
|
from typing import TYPE_CHECKING, Protocol, Self, runtime_checkable
|
|
4
20
|
|
|
5
21
|
import httpx
|
|
22
|
+
import httpx2
|
|
6
23
|
import requests
|
|
7
24
|
from beartype import BeartypeConf, beartype
|
|
8
25
|
|
|
@@ -191,6 +208,120 @@ class HTTPXTransport:
|
|
|
191
208
|
)
|
|
192
209
|
|
|
193
210
|
|
|
211
|
+
@beartype(conf=BeartypeConf(is_pep484_tower=True))
|
|
212
|
+
def _httpx2_timeout(
|
|
213
|
+
*,
|
|
214
|
+
request_timeout: float | tuple[float, float],
|
|
215
|
+
) -> httpx2.Timeout:
|
|
216
|
+
"""The ``httpx2`` timeout for a request timeout.
|
|
217
|
+
|
|
218
|
+
Args:
|
|
219
|
+
request_timeout: The timeout for the request. A float sets
|
|
220
|
+
both the connect and read timeouts. A (connect, read)
|
|
221
|
+
tuple sets them individually.
|
|
222
|
+
|
|
223
|
+
Returns:
|
|
224
|
+
The equivalent ``httpx2`` timeout.
|
|
225
|
+
"""
|
|
226
|
+
match request_timeout:
|
|
227
|
+
case tuple() as timeout:
|
|
228
|
+
connect_timeout, read_timeout = timeout
|
|
229
|
+
case timeout:
|
|
230
|
+
connect_timeout = timeout
|
|
231
|
+
read_timeout = timeout
|
|
232
|
+
|
|
233
|
+
return httpx2.Timeout(
|
|
234
|
+
connect=connect_timeout,
|
|
235
|
+
read=read_timeout,
|
|
236
|
+
write=None,
|
|
237
|
+
pool=None,
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
@beartype(conf=BeartypeConf(is_pep484_tower=True))
|
|
242
|
+
def _response_from_httpx2(*, httpx2_response: httpx2.Response) -> Response:
|
|
243
|
+
"""Convert an ``httpx2`` response to a ``Response``.
|
|
244
|
+
|
|
245
|
+
Args:
|
|
246
|
+
httpx2_response: The response to convert.
|
|
247
|
+
|
|
248
|
+
Returns:
|
|
249
|
+
A Response populated from the ``httpx2`` response.
|
|
250
|
+
"""
|
|
251
|
+
content = bytes(httpx2_response.content)
|
|
252
|
+
request_content = httpx2_response.request.content
|
|
253
|
+
|
|
254
|
+
return Response(
|
|
255
|
+
text=httpx2_response.text,
|
|
256
|
+
url=str(object=httpx2_response.url),
|
|
257
|
+
status_code=httpx2_response.status_code,
|
|
258
|
+
headers=dict(httpx2_response.headers),
|
|
259
|
+
request_body=bytes(request_content) or None,
|
|
260
|
+
tell_position=len(content),
|
|
261
|
+
content=content,
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
@beartype(conf=BeartypeConf(is_pep484_tower=True))
|
|
266
|
+
class HTTPX2Transport:
|
|
267
|
+
"""HTTP transport using the ``httpx2`` library.
|
|
268
|
+
|
|
269
|
+
``httpx2`` is the continuation of ``httpx`` maintained by
|
|
270
|
+
Pydantic. Its client, request, response, timeout and exception
|
|
271
|
+
classes are distinct from the ``httpx`` ones, so this transport
|
|
272
|
+
raises ``httpx2`` exceptions, not ``httpx`` ones.
|
|
273
|
+
A single ``httpx2.Client`` is reused across requests
|
|
274
|
+
for connection pooling.
|
|
275
|
+
"""
|
|
276
|
+
|
|
277
|
+
def __init__(self) -> None:
|
|
278
|
+
"""Create an ``HTTPX2Transport``."""
|
|
279
|
+
self._client = httpx2.Client()
|
|
280
|
+
|
|
281
|
+
def close(self) -> None:
|
|
282
|
+
"""Close the underlying ``httpx2.Client``."""
|
|
283
|
+
self._client.close()
|
|
284
|
+
|
|
285
|
+
def __enter__(self) -> Self:
|
|
286
|
+
"""Enter the context manager."""
|
|
287
|
+
return self
|
|
288
|
+
|
|
289
|
+
def __exit__(self, *_args: object) -> None:
|
|
290
|
+
"""Exit the context manager and close the client."""
|
|
291
|
+
self.close()
|
|
292
|
+
|
|
293
|
+
def __call__(
|
|
294
|
+
self,
|
|
295
|
+
*,
|
|
296
|
+
method: str,
|
|
297
|
+
url: str,
|
|
298
|
+
headers: dict[str, str],
|
|
299
|
+
data: bytes,
|
|
300
|
+
request_timeout: float | tuple[float, float],
|
|
301
|
+
) -> Response:
|
|
302
|
+
"""Make an HTTP request using ``httpx2``.
|
|
303
|
+
|
|
304
|
+
Args:
|
|
305
|
+
method: The HTTP method.
|
|
306
|
+
url: The full URL.
|
|
307
|
+
headers: Request headers.
|
|
308
|
+
data: The request body.
|
|
309
|
+
request_timeout: The request timeout.
|
|
310
|
+
|
|
311
|
+
Returns:
|
|
312
|
+
A Response populated from the ``httpx2`` response.
|
|
313
|
+
"""
|
|
314
|
+
httpx2_response = self._client.request(
|
|
315
|
+
method=method,
|
|
316
|
+
url=url,
|
|
317
|
+
headers=headers,
|
|
318
|
+
content=data,
|
|
319
|
+
timeout=_httpx2_timeout(request_timeout=request_timeout),
|
|
320
|
+
follow_redirects=True,
|
|
321
|
+
)
|
|
322
|
+
return _response_from_httpx2(httpx2_response=httpx2_response)
|
|
323
|
+
|
|
324
|
+
|
|
194
325
|
@runtime_checkable
|
|
195
326
|
class AsyncTransport(Protocol):
|
|
196
327
|
"""Protocol for async HTTP transports used by VWS clients.
|
|
@@ -313,3 +444,63 @@ class AsyncHTTPXTransport:
|
|
|
313
444
|
tell_position=len(content),
|
|
314
445
|
content=content,
|
|
315
446
|
)
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
@beartype(conf=BeartypeConf(is_pep484_tower=True))
|
|
450
|
+
class AsyncHTTPX2Transport:
|
|
451
|
+
"""Async HTTP transport using the ``httpx2`` library.
|
|
452
|
+
|
|
453
|
+
``httpx2`` is the continuation of ``httpx`` maintained by
|
|
454
|
+
Pydantic. Its client, request, response, timeout and exception
|
|
455
|
+
classes are distinct from the ``httpx`` ones, so this transport
|
|
456
|
+
raises ``httpx2`` exceptions, not ``httpx`` ones.
|
|
457
|
+
A single ``httpx2.AsyncClient`` is reused across requests
|
|
458
|
+
for connection pooling.
|
|
459
|
+
"""
|
|
460
|
+
|
|
461
|
+
def __init__(self) -> None:
|
|
462
|
+
"""Create an ``AsyncHTTPX2Transport``."""
|
|
463
|
+
self._client = httpx2.AsyncClient()
|
|
464
|
+
|
|
465
|
+
async def aclose(self) -> None:
|
|
466
|
+
"""Close the underlying ``httpx2.AsyncClient``."""
|
|
467
|
+
await self._client.aclose()
|
|
468
|
+
|
|
469
|
+
async def __aenter__(self) -> Self:
|
|
470
|
+
"""Enter the async context manager."""
|
|
471
|
+
return self
|
|
472
|
+
|
|
473
|
+
async def __aexit__(self, *_args: object) -> None:
|
|
474
|
+
"""Exit the async context manager and close the client."""
|
|
475
|
+
await self.aclose()
|
|
476
|
+
|
|
477
|
+
async def __call__(
|
|
478
|
+
self,
|
|
479
|
+
*,
|
|
480
|
+
method: str,
|
|
481
|
+
url: str,
|
|
482
|
+
headers: dict[str, str],
|
|
483
|
+
data: bytes,
|
|
484
|
+
request_timeout: float | tuple[float, float],
|
|
485
|
+
) -> Response:
|
|
486
|
+
"""Make an async HTTP request using ``httpx2``.
|
|
487
|
+
|
|
488
|
+
Args:
|
|
489
|
+
method: The HTTP method.
|
|
490
|
+
url: The full URL.
|
|
491
|
+
headers: Request headers.
|
|
492
|
+
data: The request body.
|
|
493
|
+
request_timeout: The request timeout.
|
|
494
|
+
|
|
495
|
+
Returns:
|
|
496
|
+
A Response populated from the ``httpx2`` response.
|
|
497
|
+
"""
|
|
498
|
+
httpx2_response = await self._client.request(
|
|
499
|
+
method=method,
|
|
500
|
+
url=url,
|
|
501
|
+
headers=headers,
|
|
502
|
+
content=data,
|
|
503
|
+
timeout=_httpx2_timeout(request_timeout=request_timeout),
|
|
504
|
+
follow_redirects=True,
|
|
505
|
+
)
|
|
506
|
+
return _response_from_httpx2(httpx2_response=httpx2_response)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: vws-python
|
|
3
|
-
Version: 2026.
|
|
3
|
+
Version: 2026.9.7
|
|
4
4
|
Summary: Interact with the Vuforia Web Services (VWS) API.
|
|
5
5
|
Author-email: Adam Dangoor <adamdangoor@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -18,6 +18,7 @@ Description-Content-Type: text/x-rst
|
|
|
18
18
|
License-File: LICENSE
|
|
19
19
|
Requires-Dist: beartype>=0.22.9
|
|
20
20
|
Requires-Dist: httpx>=0.28.0
|
|
21
|
+
Requires-Dist: httpx2>=2.12
|
|
21
22
|
Requires-Dist: requests>=2.32.3
|
|
22
23
|
Requires-Dist: urllib3>=2.2.3
|
|
23
24
|
Requires-Dist: vws-auth-tools>=2024.7.12
|
|
@@ -26,20 +27,20 @@ Requires-Dist: actionlint-py==1.7.12.24; extra == "dev"
|
|
|
26
27
|
Requires-Dist: check-manifest==0.51; extra == "dev"
|
|
27
28
|
Requires-Dist: deptry==0.25.1; extra == "dev"
|
|
28
29
|
Requires-Dist: doc8==2.0.0; extra == "dev"
|
|
29
|
-
Requires-Dist: doccmd==2026.
|
|
30
|
+
Requires-Dist: doccmd==2026.9.1; extra == "dev"
|
|
30
31
|
Requires-Dist: freezegun==1.5.5; extra == "dev"
|
|
31
32
|
Requires-Dist: furo==2025.12.19; extra == "dev"
|
|
32
33
|
Requires-Dist: interrogate==1.7.0; extra == "dev"
|
|
33
34
|
Requires-Dist: mypy[faster-cache]==2.3.1; extra == "dev"
|
|
34
35
|
Requires-Dist: mypy-strict-kwargs==2026.8.25.1; extra == "dev"
|
|
35
|
-
Requires-Dist: no-defaults==
|
|
36
|
-
Requires-Dist: prek==0.
|
|
36
|
+
Requires-Dist: no-defaults==2026.9.1; extra == "dev"
|
|
37
|
+
Requires-Dist: prek==0.5.2; extra == "dev"
|
|
37
38
|
Requires-Dist: pydocstringformatter==1.0.0; extra == "dev"
|
|
38
39
|
Requires-Dist: pydocstyle==6.3; extra == "dev"
|
|
39
40
|
Requires-Dist: pygments==2.21.0; extra == "dev"
|
|
40
|
-
Requires-Dist: pylint[spelling]==4.0.
|
|
41
|
+
Requires-Dist: pylint[spelling]==4.0.8; extra == "dev"
|
|
41
42
|
Requires-Dist: pylint-per-file-ignores==3.2.1; extra == "dev"
|
|
42
|
-
Requires-Dist: pyproject-fmt==2.
|
|
43
|
+
Requires-Dist: pyproject-fmt==2.29.3; extra == "dev"
|
|
43
44
|
Requires-Dist: pyrefly==1.2.0; extra == "dev"
|
|
44
45
|
Requires-Dist: pyright==1.1.411; extra == "dev"
|
|
45
46
|
Requires-Dist: pyroma==5.0.1; extra == "dev"
|
|
@@ -48,9 +49,9 @@ Requires-Dist: pytest-asyncio==1.4.0; extra == "dev"
|
|
|
48
49
|
Requires-Dist: pytest-beartype-tests==2026.8.16; extra == "dev"
|
|
49
50
|
Requires-Dist: pytest-cov==7.1.0; extra == "dev"
|
|
50
51
|
Requires-Dist: pyyaml==6.0.3; extra == "dev"
|
|
51
|
-
Requires-Dist: ruff==0.16.
|
|
52
|
+
Requires-Dist: ruff==0.16.6; extra == "dev"
|
|
52
53
|
Requires-Dist: shellcheck-py==0.11.0.1; extra == "dev"
|
|
53
|
-
Requires-Dist: shfmt-py==4.
|
|
54
|
+
Requires-Dist: shfmt-py==4.1.0; extra == "dev"
|
|
54
55
|
Requires-Dist: sphinx==9.1.0; extra == "dev"
|
|
55
56
|
Requires-Dist: sphinx-copybutton==0.5.2; extra == "dev"
|
|
56
57
|
Requires-Dist: sphinx-lint==1.0.2; extra == "dev"
|
|
@@ -58,17 +59,17 @@ Requires-Dist: sphinx-pyproject==0.3.0; extra == "dev"
|
|
|
58
59
|
Requires-Dist: sphinx-substitution-extensions==2026.8.13.1; extra == "dev"
|
|
59
60
|
Requires-Dist: sphinxcontrib-spelling==8.0.2; extra == "dev"
|
|
60
61
|
Requires-Dist: sphinxcontrib-towncrier==0.5.0a0; extra == "dev"
|
|
61
|
-
Requires-Dist: strict-kwargs==2026.8.
|
|
62
|
+
Requires-Dist: strict-kwargs==2026.8.28.post2; extra == "dev"
|
|
62
63
|
Requires-Dist: sybil==10.1.0; extra == "dev"
|
|
63
64
|
Requires-Dist: towncrier==25.8.0; extra == "dev"
|
|
64
|
-
Requires-Dist: ty==0.0.
|
|
65
|
+
Requires-Dist: ty==0.0.78; extra == "dev"
|
|
65
66
|
Requires-Dist: types-requests==2.33.0.20260712; extra == "dev"
|
|
66
|
-
Requires-Dist: vale==3.
|
|
67
|
+
Requires-Dist: vale==3.20.0.0; extra == "dev"
|
|
67
68
|
Requires-Dist: vulture==2.16; extra == "dev"
|
|
68
|
-
Requires-Dist: vws-python-mock==2026.
|
|
69
|
-
Requires-Dist: vws-test-fixtures==2026.8.
|
|
69
|
+
Requires-Dist: vws-python-mock==2026.9.6; extra == "dev"
|
|
70
|
+
Requires-Dist: vws-test-fixtures==2026.8.26; extra == "dev"
|
|
70
71
|
Requires-Dist: yamlfix==1.19.1; extra == "dev"
|
|
71
|
-
Requires-Dist: zizmor==1.
|
|
72
|
+
Requires-Dist: zizmor==1.30.0; extra == "dev"
|
|
72
73
|
Provides-Extra: release
|
|
73
74
|
Requires-Dist: check-wheel-contents==0.6.3; extra == "release"
|
|
74
75
|
Requires-Dist: towncrier==25.8.0; extra == "release"
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
beartype>=0.22.9
|
|
2
2
|
httpx>=0.28.0
|
|
3
|
+
httpx2>=2.12
|
|
3
4
|
requests>=2.32.3
|
|
4
5
|
urllib3>=2.2.3
|
|
5
6
|
vws-auth-tools>=2024.7.12
|
|
@@ -9,20 +10,20 @@ actionlint-py==1.7.12.24
|
|
|
9
10
|
check-manifest==0.51
|
|
10
11
|
deptry==0.25.1
|
|
11
12
|
doc8==2.0.0
|
|
12
|
-
doccmd==2026.
|
|
13
|
+
doccmd==2026.9.1
|
|
13
14
|
freezegun==1.5.5
|
|
14
15
|
furo==2025.12.19
|
|
15
16
|
interrogate==1.7.0
|
|
16
17
|
mypy[faster-cache]==2.3.1
|
|
17
18
|
mypy-strict-kwargs==2026.8.25.1
|
|
18
|
-
no-defaults==
|
|
19
|
-
prek==0.
|
|
19
|
+
no-defaults==2026.9.1
|
|
20
|
+
prek==0.5.2
|
|
20
21
|
pydocstringformatter==1.0.0
|
|
21
22
|
pydocstyle==6.3
|
|
22
23
|
pygments==2.21.0
|
|
23
|
-
pylint[spelling]==4.0.
|
|
24
|
+
pylint[spelling]==4.0.8
|
|
24
25
|
pylint-per-file-ignores==3.2.1
|
|
25
|
-
pyproject-fmt==2.
|
|
26
|
+
pyproject-fmt==2.29.3
|
|
26
27
|
pyrefly==1.2.0
|
|
27
28
|
pyright==1.1.411
|
|
28
29
|
pyroma==5.0.1
|
|
@@ -31,9 +32,9 @@ pytest-asyncio==1.4.0
|
|
|
31
32
|
pytest-beartype-tests==2026.8.16
|
|
32
33
|
pytest-cov==7.1.0
|
|
33
34
|
pyyaml==6.0.3
|
|
34
|
-
ruff==0.16.
|
|
35
|
+
ruff==0.16.6
|
|
35
36
|
shellcheck-py==0.11.0.1
|
|
36
|
-
shfmt-py==4.
|
|
37
|
+
shfmt-py==4.1.0
|
|
37
38
|
sphinx==9.1.0
|
|
38
39
|
sphinx-copybutton==0.5.2
|
|
39
40
|
sphinx-lint==1.0.2
|
|
@@ -41,17 +42,17 @@ sphinx-pyproject==0.3.0
|
|
|
41
42
|
sphinx-substitution-extensions==2026.8.13.1
|
|
42
43
|
sphinxcontrib-spelling==8.0.2
|
|
43
44
|
sphinxcontrib-towncrier==0.5.0a0
|
|
44
|
-
strict-kwargs==2026.8.
|
|
45
|
+
strict-kwargs==2026.8.28.post2
|
|
45
46
|
sybil==10.1.0
|
|
46
47
|
towncrier==25.8.0
|
|
47
|
-
ty==0.0.
|
|
48
|
+
ty==0.0.78
|
|
48
49
|
types-requests==2.33.0.20260712
|
|
49
|
-
vale==3.
|
|
50
|
+
vale==3.20.0.0
|
|
50
51
|
vulture==2.16
|
|
51
|
-
vws-python-mock==2026.
|
|
52
|
-
vws-test-fixtures==2026.8.
|
|
52
|
+
vws-python-mock==2026.9.6
|
|
53
|
+
vws-test-fixtures==2026.8.26
|
|
53
54
|
yamlfix==1.19.1
|
|
54
|
-
zizmor==1.
|
|
55
|
+
zizmor==1.30.0
|
|
55
56
|
|
|
56
57
|
[release]
|
|
57
58
|
check-wheel-contents==0.6.3
|