Skip to content

Commit 41d4100

Browse files
Merge main and resolve conflicts
Co-authored-by: Cursor <cursoragent@cursor.com>
2 parents 5c84590 + 555a2d1 commit 41d4100

25 files changed

Lines changed: 583 additions & 602 deletions

CHANGELOG.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ Changelog
44
Next
55
----
66

7+
2026.02.22.3
8+
------------
9+
10+
11+
- ``MockVWS`` now intercepts both ``requests`` (via ``responses``) and ``httpx`` (via ``respx``) simultaneously.
12+
``MockVWSForHttpx`` has been removed — ``MockVWS`` handles both HTTP libraries.
13+
714
2026.02.22.2
815
------------
916

README.rst

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ VWS Mock
88

99
Mock for the Vuforia Web Services (VWS) API and the Vuforia Web Query API.
1010

11-
Mocking calls made to Vuforia with Python ``requests``
12-
------------------------------------------------------
11+
Mocking calls made to Vuforia
12+
------------------------------
1313

14-
Using the mock redirects requests to Vuforia made with `requests`_ to an in-memory implementation.
14+
``MockVWS`` intercepts requests made with `requests`_ or `httpx`_.
1515

1616
.. code-block:: shell
1717
@@ -34,32 +34,26 @@ This requires Python |minimum-python-version|\+.
3434
# This will use the Vuforia mock.
3535
requests.get(url="https://vws.vuforia.com/summary", timeout=30)
3636
37-
By default, an exception will be raised if any requests to unmocked addresses are made.
38-
39-
.. _requests: https://pypi.org/project/requests/
40-
41-
Mocking calls made to Vuforia with Python ``httpx``
42-
----------------------------------------------------
43-
44-
Using the mock redirects requests to Vuforia made with `httpx`_ to an in-memory implementation.
37+
``MockVWS`` also intercepts `httpx`_ requests:
4538

4639
.. code-block:: python
4740
48-
"""Make a request to the Vuforia Web Services API mock."""
41+
"""Make a request to the Vuforia Web Services API mock using httpx."""
4942
5043
import httpx
5144
52-
from mock_vws import MockVWSForHttpx
45+
from mock_vws import MockVWS
5346
from mock_vws.database import CloudDatabase
5447
55-
with MockVWSForHttpx() as mock:
48+
with MockVWS() as mock:
5649
database = CloudDatabase()
5750
mock.add_cloud_database(cloud_database=database)
5851
# This will use the Vuforia mock.
5952
httpx.get(url="https://vws.vuforia.com/summary", timeout=30)
6053
6154
By default, an exception will be raised if any requests to unmocked addresses are made.
6255

56+
.. _requests: https://pypi.org/project/requests/
6357
.. _httpx: https://pypi.org/project/httpx/
6458

6559
Using Docker to mock calls to Vuforia from any language

admin/create_secrets_files.py

Lines changed: 104 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@
2323
)
2424

2525

26-
def _create_and_get_database_details(
26+
def _create_and_get_cloud_database_details(
2727
driver: "WebDriver",
2828
email_address: str,
2929
password: str,
30-
license_name: str,
31-
database_name: str,
30+
cloud_license_name: str,
31+
cloud_database_name: str,
3232
) -> "DatabaseDict":
3333
"""Create a cloud database and get its details.
3434
@@ -40,17 +40,19 @@ def _create_and_get_database_details(
4040
password=password,
4141
)
4242
vws_web_tools.wait_for_logged_in(driver=driver)
43-
vws_web_tools.create_license(driver=driver, license_name=license_name)
43+
vws_web_tools.create_license(
44+
driver=driver, license_name=cloud_license_name
45+
)
4446

4547
vws_web_tools.create_cloud_database(
4648
driver=driver,
47-
database_name=database_name,
48-
license_name=license_name,
49+
database_name=cloud_database_name,
50+
license_name=cloud_license_name,
4951
)
5052

5153
return vws_web_tools.get_database_details(
5254
driver=driver,
53-
database_name=database_name,
55+
database_name=cloud_database_name,
5456
)
5557

5658

@@ -74,19 +76,20 @@ def _create_and_get_vumark_details(
7476

7577

7678
def _generate_secrets_file_content(
77-
database_details: "DatabaseDict",
79+
cloud_database_details: "DatabaseDict",
7880
vumark_details: "VuMarkDatabaseDict",
7981
inactive_database_details: "DatabaseDict",
82+
inactive_vumark_details: "VuMarkDatabaseDict",
8083
vumark_target_id: str,
8184
) -> str:
8285
"""Generate the content of a secrets file."""
8386
return textwrap.dedent(
8487
text=f"""\
85-
VUFORIA_TARGET_MANAGER_DATABASE_NAME={database_details["database_name"]}
86-
VUFORIA_SERVER_ACCESS_KEY={database_details["server_access_key"]}
87-
VUFORIA_SERVER_SECRET_KEY={database_details["server_secret_key"]}
88-
VUFORIA_CLIENT_ACCESS_KEY={database_details["client_access_key"]}
89-
VUFORIA_CLIENT_SECRET_KEY={database_details["client_secret_key"]}
88+
VUFORIA_TARGET_MANAGER_DATABASE_NAME={cloud_database_details["database_name"]}
89+
VUFORIA_SERVER_ACCESS_KEY={cloud_database_details["server_access_key"]}
90+
VUFORIA_SERVER_SECRET_KEY={cloud_database_details["server_secret_key"]}
91+
VUFORIA_CLIENT_ACCESS_KEY={cloud_database_details["client_access_key"]}
92+
VUFORIA_CLIENT_SECRET_KEY={cloud_database_details["client_secret_key"]}
9093
9194
INACTIVE_VUFORIA_TARGET_MANAGER_DATABASE_NAME={inactive_database_details["database_name"]}
9295
INACTIVE_VUFORIA_SERVER_ACCESS_KEY={inactive_database_details["server_access_key"]}
@@ -98,6 +101,10 @@ def _generate_secrets_file_content(
98101
VUMARK_VUFORIA_TARGET_ID={vumark_target_id}
99102
VUMARK_VUFORIA_SERVER_ACCESS_KEY={vumark_details["server_access_key"]}
100103
VUMARK_VUFORIA_SERVER_SECRET_KEY={vumark_details["server_secret_key"]}
104+
105+
INACTIVE_VUMARK_VUFORIA_TARGET_MANAGER_DATABASE_NAME={inactive_vumark_details["database_name"]}
106+
INACTIVE_VUMARK_VUFORIA_SERVER_ACCESS_KEY={inactive_vumark_details["server_access_key"]}
107+
INACTIVE_VUMARK_VUFORIA_SERVER_SECRET_KEY={inactive_vumark_details["server_secret_key"]}
101108
""",
102109
)
103110

@@ -122,23 +129,72 @@ def _create_and_get_vumark_target_id(
122129
)
123130

124131

125-
def _fetch_inactive_database_details(
132+
def _create_and_get_inactive_database_details(
126133
driver: "WebDriver",
127134
email_address: str,
128135
password: str,
129-
database_name: str,
136+
cloud_license_name: str,
137+
cloud_database_name: str,
130138
) -> "DatabaseDict":
131-
"""Fetch details for an existing inactive database."""
139+
"""Create a cloud database, get its details, then delete the license to
140+
make it inactive.
141+
"""
132142
vws_web_tools.log_in(
133143
driver=driver,
134144
email_address=email_address,
135145
password=password,
136146
)
137147
vws_web_tools.wait_for_logged_in(driver=driver)
138-
return vws_web_tools.get_database_details(
148+
vws_web_tools.create_license(
149+
driver=driver, license_name=cloud_license_name
150+
)
151+
vws_web_tools.create_cloud_database(
152+
driver=driver,
153+
database_name=cloud_database_name,
154+
license_name=cloud_license_name,
155+
)
156+
cloud_database_details = vws_web_tools.get_database_details(
157+
driver=driver,
158+
database_name=cloud_database_name,
159+
)
160+
vws_web_tools.delete_license(
161+
driver=driver, license_name=cloud_license_name
162+
)
163+
return cloud_database_details
164+
165+
166+
def _create_and_get_inactive_vumark_details(
167+
driver: "WebDriver",
168+
email_address: str,
169+
password: str,
170+
vumark_license_name: str,
171+
vumark_database_name: str,
172+
) -> "VuMarkDatabaseDict":
173+
"""Create a VuMark database, get its details, then delete the license
174+
to
175+
make it inactive.
176+
"""
177+
vws_web_tools.log_in(
178+
driver=driver,
179+
email_address=email_address,
180+
password=password,
181+
)
182+
vws_web_tools.wait_for_logged_in(driver=driver)
183+
vws_web_tools.create_license(
184+
driver=driver, license_name=vumark_license_name
185+
)
186+
vws_web_tools.create_vumark_database(
187+
driver=driver,
188+
database_name=vumark_database_name,
189+
)
190+
vumark_database_details = vws_web_tools.get_vumark_database_details(
139191
driver=driver,
140-
database_name=database_name,
192+
database_name=vumark_database_name,
193+
)
194+
vws_web_tools.delete_license(
195+
driver=driver, license_name=vumark_license_name
141196
)
197+
return vumark_database_details
142198

143199

144200
def _create_vuforia_resource_names() -> tuple[str, str, str, str]:
@@ -147,8 +203,8 @@ def _create_vuforia_resource_names() -> tuple[str, str, str, str]:
147203
format="%Y-%m-%d-%H-%M-%S",
148204
)
149205
return (
150-
f"my-license-{time}",
151-
f"my-database-{time}",
206+
f"my-cloud-license-{time}",
207+
f"my-cloud-database-{time}",
152208
f"my-vumark-database-{time}",
153209
f"my-vumark-template-{time}",
154210
)
@@ -159,19 +215,31 @@ def main() -> None:
159215
email_address = os.environ["VWS_EMAIL_ADDRESS"]
160216
password = os.environ["VWS_PASSWORD"]
161217
new_secrets_dir = Path(os.environ["NEW_SECRETS_DIR"]).expanduser()
162-
inactive_database_name = os.environ[
163-
"INACTIVE_VUFORIA_TARGET_MANAGER_DATABASE_NAME"
164-
]
165218
new_secrets_dir.mkdir(exist_ok=True)
219+
220+
time = datetime.datetime.now(tz=datetime.UTC).strftime(
221+
format="%Y-%m-%d-%H-%M-%S",
222+
)
166223
inactive_driver = vws_web_tools.create_chrome_driver()
167-
inactive_database_details = _fetch_inactive_database_details(
224+
inactive_database_details = _create_and_get_inactive_database_details(
168225
driver=inactive_driver,
169226
email_address=email_address,
170227
password=password,
171-
database_name=inactive_database_name,
228+
cloud_license_name=f"my-inactive-cloud-license-{time}",
229+
cloud_database_name=f"my-inactive-cloud-database-{time}",
172230
)
173231
inactive_driver.quit()
174232

233+
inactive_vumark_driver = vws_web_tools.create_chrome_driver()
234+
inactive_vumark_details = _create_and_get_inactive_vumark_details(
235+
driver=inactive_vumark_driver,
236+
email_address=email_address,
237+
password=password,
238+
vumark_license_name=f"my-inactive-vumark-license-{time}",
239+
vumark_database_name=f"my-inactive-vumark-database-{time}",
240+
)
241+
inactive_vumark_driver.quit()
242+
175243
num_databases = 100
176244
required_files = [
177245
(new_secrets_dir / f"vuforia_secrets_{i}.env")
@@ -186,51 +254,34 @@ def main() -> None:
186254
file = files_to_create[-1]
187255
sys.stdout.write(f"Creating database {file.name}\n")
188256
(
189-
license_name,
190-
database_name,
257+
cloud_license_name,
258+
cloud_database_name,
191259
vumark_database_name,
192260
vumark_template_name,
193261
) = _create_vuforia_resource_names()
194262

195263
try:
196-
database_details = _create_and_get_database_details(
264+
sys.stdout.write("Creating cloud database details\n")
265+
cloud_database_details = _create_and_get_cloud_database_details(
197266
driver=driver,
198267
email_address=email_address,
199268
password=password,
200-
license_name=license_name,
201-
database_name=database_name,
202-
)
203-
except TimeoutException:
204-
sys.stderr.write(
205-
"Timed out waiting for database setup/details after retries\n"
269+
cloud_license_name=cloud_license_name,
270+
cloud_database_name=cloud_database_name,
206271
)
207-
driver.quit()
208-
driver = None
209-
continue
210-
211-
try:
272+
sys.stdout.write("Creating VuMark database details\n")
212273
vumark_details = _create_and_get_vumark_details(
213274
driver=driver,
214275
vumark_database_name=vumark_database_name,
215276
)
216-
except TimeoutException:
217-
sys.stderr.write(
218-
"Timed out waiting for VuMark setup/details after retries\n"
219-
)
220-
driver.quit()
221-
driver = None
222-
continue
223-
224-
try:
277+
sys.stdout.write("Creating VuMark target\n")
225278
vumark_target_id = _create_and_get_vumark_target_id(
226279
driver=driver,
227280
vumark_database_name=vumark_database_name,
228281
vumark_template_name=vumark_template_name,
229282
)
230283
except TimeoutException:
231-
sys.stderr.write(
232-
"Timed out waiting for VuMark template upload after retries\n"
233-
)
284+
sys.stderr.write("Timed out during database setup\n")
234285
driver.quit()
235286
driver = None
236287
continue
@@ -239,9 +290,10 @@ def main() -> None:
239290
driver = None
240291

241292
file_contents = _generate_secrets_file_content(
242-
database_details=database_details,
293+
cloud_database_details=cloud_database_details,
243294
vumark_details=vumark_details,
244295
inactive_database_details=inactive_database_details,
296+
inactive_vumark_details=inactive_vumark_details,
245297
vumark_target_id=vumark_target_id,
246298
)
247299
file.write_text(data=file_contents)

docs/source/basic-example.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Using the mock redirects requests to Vuforia made with `requests`_ to an in-memory implementation.
1+
``MockVWS`` intercepts requests to Vuforia made with `requests`_ or `httpx`_.
22

33
.. code-block:: python
44
@@ -20,3 +20,4 @@ By default, an exception will be raised if any requests to unmocked addresses ar
2020
See :ref:`mock-api-reference` for details of what can be changed and how.
2121

2222
.. _requests: https://pypi.org/project/requests/
23+
.. _httpx: https://pypi.org/project/httpx/

docs/source/contributing.rst

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,9 @@ To find the environment variables to set in the :file:`vuforia_secrets.env` file
8686

8787
Two Cloud databases are necessary in order to run all the Cloud Target tests.
8888
One of those must be an inactive project.
89-
To create an inactive project, delete the license key associated with a database.
89+
The script creates the inactive project automatically by deleting its license.
9090

9191
VuMark tests require one VuMark database.
92-
When creating multiple credentials files, the same inactive database and the
93-
same VuMark database can be reused across all files.
9492

9593
Targets sometimes get stuck at the "Processing" stage meaning that they cannot be deleted.
9694
When this happens, create a new target database to use for testing.
@@ -102,7 +100,6 @@ To create databases without using the browser, use :file:`admin/create_secrets_f
102100
$ export VWS_EMAIL_ADDRESS=...
103101
$ export VWS_PASSWORD=...
104102
$ export NEW_SECRETS_DIR=...
105-
$ export INACTIVE_VUFORIA_TARGET_MANAGER_DATABASE_NAME=...
106103
# You may have to run this a few times, but it is idempotent.
107104
$ python admin/create_secrets_files.py
108105
# Each generated file gets its own Cloud database credentials and shares

docs/source/getting-started.rst

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
Getting started
22
---------------
33

4-
Mocking calls made to Vuforia with Python ``requests``
5-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4+
Mocking calls made to Vuforia
5+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
66

77
.. include:: basic-example.rst
88

9-
Mocking calls made to Vuforia with Python ``httpx``
10-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
11-
129
.. include:: httpx-example.rst

0 commit comments

Comments
 (0)