Skip to content

Commit a1bf514

Browse files
Merge pull request #2264 from VWS-Python/switch-to-responses
Switch to responses from requests_mock
2 parents 82f9da8 + 5355291 commit a1bf514

File tree

8 files changed

+200
-203
lines changed

8 files changed

+200
-203
lines changed

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ dependencies = [
4444
"piq",
4545
"pydantic-settings",
4646
"requests",
47-
"requests-mock",
47+
"responses",
4848
"torch",
4949
"torchmetrics",
5050
"tzdata; sys_platform=='win32'",
@@ -78,7 +78,7 @@ optional-dependencies.dev = [
7878
"pytest-xdist==3.6.1",
7979
"python-dotenv==1.0.1",
8080
"pyyaml==6.0.2",
81-
"requests-mock-flask==2023.5.14",
81+
"requests-mock-flask==2024.8.30.1",
8282
"ruff==0.6.2",
8383
"sphinx==8.0.2",
8484
"sphinx-copybutton==0.5.2",
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
"""
2-
An interface to the mock Vuforia which uses ``requests_mock``.
2+
An interface to the mock Vuforia which uses ``responses``.
33
"""

src/mock_vws/_requests_mock_server/decorators.py

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from urllib.parse import urljoin, urlparse
99

1010
import requests
11-
from requests_mock.mocker import Mocker
11+
from responses import RequestsMock
1212

1313
from mock_vws.database import VuforiaDatabase
1414
from mock_vws.image_matchers import (
@@ -69,7 +69,7 @@ def __init__(
6969
"""
7070
super().__init__()
7171
self._real_http = real_http
72-
self._mock: Mocker
72+
self._mock: RequestsMock
7373
self._target_manager = TargetManager()
7474

7575
self._base_vws_url = base_vws_url
@@ -116,33 +116,45 @@ def __enter__(self) -> Self:
116116
Returns:
117117
``self``.
118118
"""
119-
mock = Mocker(real_http=self._real_http)
119+
compiled_url_patterns: set[re.Pattern[str]] = set()
120+
121+
mock = RequestsMock(assert_all_requests_are_fired=False)
120122
for vws_route in self._mock_vws_api.routes:
121123
url_pattern = urljoin(
122124
base=self._base_vws_url,
123125
url=f"{vws_route.path_pattern}$",
124126
)
127+
compiled_url_pattern = re.compile(pattern=url_pattern)
128+
compiled_url_patterns.add(compiled_url_pattern)
125129

126130
for vws_http_method in vws_route.http_methods:
127-
mock.register_uri(
131+
mock.add_callback(
128132
method=vws_http_method,
129-
url=re.compile(url_pattern),
130-
text=getattr(self._mock_vws_api, vws_route.route_name),
133+
url=compiled_url_pattern,
134+
callback=getattr(self._mock_vws_api, vws_route.route_name),
135+
content_type=None,
131136
)
132137

133138
for vwq_route in self._mock_vwq_api.routes:
134139
url_pattern = urljoin(
135140
base=self._base_vwq_url,
136141
url=f"{vwq_route.path_pattern}$",
137142
)
143+
compiled_url_pattern = re.compile(pattern=url_pattern)
144+
compiled_url_patterns.add(compiled_url_pattern)
138145

139146
for vwq_http_method in vwq_route.http_methods:
140-
mock.register_uri(
147+
mock.add_callback(
141148
method=vwq_http_method,
142-
url=re.compile(url_pattern),
143-
text=getattr(self._mock_vwq_api, vwq_route.route_name),
149+
url=compiled_url_pattern,
150+
callback=getattr(self._mock_vwq_api, vwq_route.route_name),
151+
content_type=None,
144152
)
145153

154+
if self._real_http:
155+
all_requests_pattern = re.compile(pattern=".*")
156+
mock.add_passthru(prefix=all_requests_pattern)
157+
146158
self._mock = mock
147159
self._mock.start()
148160

src/mock_vws/_requests_mock_server/mock_web_query_api.py

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77

88
import email.utils
99
from collections.abc import Callable
10-
from http import HTTPMethod
11-
from typing import TYPE_CHECKING
10+
from http import HTTPMethod, HTTPStatus
11+
12+
from requests.models import PreparedRequest
1213

1314
from mock_vws._mock_common import Route
1415
from mock_vws._query_tools import (
@@ -21,14 +22,9 @@
2122
from mock_vws.image_matchers import ImageMatcher
2223
from mock_vws.target_manager import TargetManager
2324

24-
if TYPE_CHECKING:
25-
from requests_mock.request import Request
26-
from requests_mock.response import Context
27-
28-
2925
_ROUTES: set[Route] = set()
3026

31-
_ResponseType = str
27+
_ResponseType = tuple[int, dict[str, str], str]
3228

3329

3430
def route(
@@ -70,18 +66,22 @@ def decorator(
7066
return decorator
7167

7268

73-
def _body_bytes(request: "Request") -> bytes:
69+
def _body_bytes(request: PreparedRequest) -> bytes:
7470
"""
7571
Return the body of a request as bytes.
7672
"""
77-
return request.body or b""
73+
if request.body is None:
74+
return b""
75+
76+
assert isinstance(request.body, bytes)
77+
return request.body
7878

7979

8080
class MockVuforiaWebQueryAPI:
8181
"""
8282
A fake implementation of the Vuforia Web Query API.
8383
84-
This implementation is tied to the implementation of `requests_mock`.
84+
This implementation is tied to the implementation of ``responses``.
8585
"""
8686

8787
def __init__(
@@ -103,28 +103,26 @@ def __init__(
103103
self._query_match_checker = query_match_checker
104104

105105
@route(path_pattern="/v1/query", http_methods={HTTPMethod.POST})
106-
def query(self, request: "Request", context: "Context") -> _ResponseType:
106+
def query(self, request: PreparedRequest) -> _ResponseType:
107107
"""
108108
Perform an image recognition query.
109109
"""
110110
try:
111111
run_query_validators(
112-
request_path=request.path,
112+
request_path=request.path_url,
113113
request_headers=request.headers,
114114
request_body=_body_bytes(request=request),
115-
request_method=request.method,
115+
request_method=request.method or "",
116116
databases=self._target_manager.databases,
117117
)
118118
except ValidatorError as exc:
119-
context.headers = exc.headers
120-
context.status_code = exc.status_code
121-
return exc.response_text
119+
return exc.status_code, exc.headers, exc.response_text
122120

123121
response_text = get_query_match_response_text(
124122
request_headers=request.headers,
125123
request_body=_body_bytes(request=request),
126-
request_method=request.method,
127-
request_path=request.path,
124+
request_method=request.method or "",
125+
request_path=request.path_url,
128126
databases=self._target_manager.databases,
129127
query_match_checker=self._query_match_checker,
130128
)
@@ -134,11 +132,11 @@ def query(self, request: "Request", context: "Context") -> _ResponseType:
134132
localtime=False,
135133
usegmt=True,
136134
)
137-
context.headers = {
135+
headers = {
138136
"Connection": "keep-alive",
139137
"Content-Type": "application/json",
140138
"Server": "nginx",
141139
"Date": date,
142140
"Content-Length": str(len(response_text)),
143141
}
144-
return response_text
142+
return HTTPStatus.OK, headers, response_text

0 commit comments

Comments
 (0)