Skip to content

Commit 8317702

Browse files
Merge pull request #2268 from VWS-Python/more-beartype
Add more beartype runtime checking
2 parents ca084f5 + 715c189 commit 8317702

17 files changed

+87
-24
lines changed

conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ def pytest_collection_modifyitems(items: list[pytest.Item]) -> None:
3232
).pytest()
3333

3434

35-
@pytest.hookimpl(optionalhook=True)
3635
@beartype
36+
@pytest.hookimpl(optionalhook=True)
3737
def pytest_set_filtered_exceptions() -> tuple[type[Exception], ...]:
3838
"""
3939
Return exceptions to retry on.

src/mock_vws/_constants.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44

55
from enum import Enum
66

7+
from beartype import beartype
78

9+
10+
@beartype
811
class ResultCodes(Enum):
912
"""
1013
Constants representing various VWS result codes.
@@ -37,6 +40,7 @@ class ResultCodes(Enum):
3740
TOO_MANY_REQUESTS = "TooManyRequests"
3841

3942

43+
@beartype
4044
class TargetStatuses(Enum):
4145
"""
4246
Constants representing VWS target statuses.

src/mock_vws/_flask_server/healthcheck.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77
import sys
88
from http import HTTPStatus
99

10+
from beartype import beartype
1011

12+
13+
@beartype
1114
def flask_app_healthy(port: int) -> bool:
1215
"""
1316
Check if the Flask app is healthy.

src/mock_vws/_flask_server/target_manager.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
TARGET_MANAGER = TargetManager()
3131

3232

33+
@beartype
3334
class _TargetRaterChoice(StrEnum):
3435
"""Target rater choices."""
3536

@@ -48,6 +49,7 @@ def to_target_rater(self) -> TargetTrackingRater:
4849
return rater
4950

5051

52+
@beartype
5153
class TargetManagerSettings(BaseSettings):
5254
"""Settings for the Target Manager Flask app."""
5355

@@ -59,6 +61,7 @@ class TargetManagerSettings(BaseSettings):
5961
"/databases/<string:database_name>",
6062
methods=[HTTPMethod.DELETE],
6163
)
64+
@beartype
6265
def delete_database(database_name: str) -> Response:
6366
"""
6467
Delete a database.
@@ -92,6 +95,7 @@ def get_databases() -> Response:
9295

9396

9497
@TARGET_MANAGER_FLASK_APP.route("/databases", methods=[HTTPMethod.POST])
98+
@beartype
9599
def create_database() -> Response:
96100
"""
97101
Create a new database.
@@ -177,6 +181,7 @@ def create_database() -> Response:
177181
"/databases/<string:database_name>/targets",
178182
methods=[HTTPMethod.POST],
179183
)
184+
@beartype
180185
def create_target(database_name: str) -> Response:
181186
"""
182187
Create a new target in a given database.
@@ -212,8 +217,9 @@ def create_target(database_name: str) -> Response:
212217

213218
@TARGET_MANAGER_FLASK_APP.route(
214219
"/databases/<string:database_name>/targets/<string:target_id>",
215-
methods=[HTTPMethod.DELETE],
220+
methods={HTTPMethod.DELETE},
216221
)
222+
@beartype
217223
def delete_target(database_name: str, target_id: str) -> Response:
218224
"""
219225
Delete a target.

src/mock_vws/_flask_server/vwq.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
CLOUDRECO_FLASK_APP.config["PROPAGATE_EXCEPTIONS"] = True
3333

3434

35+
@beartype
3536
class _ImageMatcherChoice(StrEnum):
3637
"""Image matcher choices."""
3738

@@ -49,6 +50,7 @@ def to_image_matcher(self) -> ImageMatcher:
4950
return matcher
5051

5152

53+
@beartype
5254
class VWQSettings(BaseSettings):
5355
"""Settings for the VWQ Flask app."""
5456

@@ -76,6 +78,7 @@ def get_all_databases() -> set[VuforiaDatabase]:
7678

7779

7880
@CLOUDRECO_FLASK_APP.before_request
81+
@beartype
7982
def set_terminate_wsgi_input() -> None:
8083
"""
8184
We set ``wsgi.input_terminated`` to ``True`` when going through

src/mock_vws/_flask_server/vws.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
_LOGGER = logging.getLogger(name=__name__)
4747

4848

49+
@beartype
4950
class _ImageMatcherChoice(StrEnum):
5051
"""Image matcher choices."""
5152

@@ -63,6 +64,7 @@ def to_image_matcher(self) -> ImageMatcher:
6364
return matcher
6465

6566

67+
@beartype
6668
class VWSSettings(BaseSettings):
6769
"""Settings for the VWS Flask app."""
6870

@@ -151,6 +153,7 @@ def handle_exceptions(exc: ValidatorError) -> Response:
151153

152154

153155
@VWS_FLASK_APP.route("/targets", methods=[HTTPMethod.POST])
156+
@beartype
154157
def add_target() -> Response:
155158
"""
156159
Add a target.
@@ -334,6 +337,7 @@ def delete_target(target_id: str) -> Response:
334337

335338

336339
@VWS_FLASK_APP.route("/summary", methods=[HTTPMethod.GET])
340+
@beartype
337341
def database_summary() -> Response:
338342
"""
339343
Get a database summary report.

src/mock_vws/_query_validators/exceptions.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,13 @@
77
import uuid
88
from http import HTTPStatus
99

10+
from beartype import beartype
11+
1012
from mock_vws._constants import ResultCodes
1113
from mock_vws._mock_common import json_dump
1214

1315

16+
@beartype
1417
class ValidatorError(Exception):
1518
"""
1619
A base class for exceptions thrown from mock Vuforia cloud recognition
@@ -22,6 +25,7 @@ class ValidatorError(Exception):
2225
headers: dict[str, str]
2326

2427

28+
@beartype
2529
class DateHeaderNotGivenError(ValidatorError):
2630
"""
2731
Exception raised when a date header is not given.
@@ -52,6 +56,7 @@ def __init__(self) -> None:
5256
}
5357

5458

59+
@beartype
5560
class DateFormatNotValidError(ValidatorError):
5661
"""
5762
Exception raised when the date format is not valid.
@@ -83,6 +88,7 @@ def __init__(self) -> None:
8388
}
8489

8590

91+
@beartype
8692
class RequestTimeTooSkewedError(ValidatorError):
8793
"""
8894
Exception raised when Vuforia returns a response with a result code
@@ -118,6 +124,7 @@ def __init__(self) -> None:
118124
}
119125

120126

127+
@beartype
121128
class BadImageError(ValidatorError):
122129
"""
123130
Exception raised when Vuforia returns a response with a result code
@@ -160,6 +167,7 @@ def __init__(self) -> None:
160167
}
161168

162169

170+
@beartype
163171
class AuthenticationFailureError(ValidatorError):
164172
"""
165173
Exception raised when Vuforia returns a response with a result code
@@ -202,6 +210,7 @@ def __init__(self) -> None:
202210
}
203211

204212

213+
@beartype
205214
class AuthenticationFailureGoodFormattingError(ValidatorError):
206215
"""
207216
Exception raised when Vuforia returns a response with a result code
@@ -239,6 +248,7 @@ def __init__(self) -> None:
239248
}
240249

241250

251+
@beartype
242252
class ImageNotGivenError(ValidatorError):
243253
"""
244254
Exception raised when an image is not given.
@@ -270,6 +280,7 @@ def __init__(self) -> None:
270280
}
271281

272282

283+
@beartype
273284
class AuthHeaderMissingError(ValidatorError):
274285
"""
275286
Exception raised when an auth header is not given.
@@ -302,6 +313,7 @@ def __init__(self) -> None:
302313
}
303314

304315

316+
@beartype
305317
class MalformedAuthHeaderError(ValidatorError):
306318
"""
307319
Exception raised when an auth header is not given.
@@ -335,6 +347,7 @@ def __init__(self) -> None:
335347
}
336348

337349

350+
@beartype
338351
class UnknownParametersError(ValidatorError):
339352
"""
340353
Exception raised when unknown parameters are given.
@@ -366,6 +379,7 @@ def __init__(self) -> None:
366379
}
367380

368381

382+
@beartype
369383
class InactiveProjectError(ValidatorError):
370384
"""
371385
Exception raised when Vuforia returns a response with a result code
@@ -407,6 +421,7 @@ def __init__(self) -> None:
407421
}
408422

409423

424+
@beartype
410425
class InvalidMaxNumResultsError(ValidatorError):
411426
"""
412427
Exception raised when an invalid value is given as the
@@ -443,6 +458,7 @@ def __init__(self, given_value: str) -> None:
443458
}
444459

445460

461+
@beartype
446462
class MaxNumResultsOutOfRangeError(ValidatorError):
447463
"""
448464
Exception raised when an integer value is given as the "max_num_results"
@@ -479,6 +495,7 @@ def __init__(self, given_value: str) -> None:
479495
}
480496

481497

498+
@beartype
482499
class InvalidIncludeTargetDataError(ValidatorError):
483500
"""
484501
Exception raised when an invalid value is given as the
@@ -517,6 +534,7 @@ def __init__(self, given_value: str) -> None:
517534
}
518535

519536

537+
@beartype
520538
class UnsupportedMediaTypeError(ValidatorError):
521539
"""
522540
Exception raised when no boundary is found for multipart data.
@@ -547,6 +565,7 @@ def __init__(self) -> None:
547565
}
548566

549567

568+
@beartype
550569
class InvalidAcceptHeaderError(ValidatorError):
551570
"""
552571
Exception raised when there is an invalid accept header given.
@@ -577,6 +596,7 @@ def __init__(self) -> None:
577596
}
578597

579598

599+
@beartype
580600
class NoBoundaryFoundError(ValidatorError):
581601
"""
582602
Exception raised when an invalid media type is given.
@@ -611,6 +631,7 @@ def __init__(self) -> None:
611631
}
612632

613633

634+
@beartype
614635
class ContentLengthHeaderTooLargeError(ValidatorError):
615636
"""
616637
Exception raised when the given content length header is too large.
@@ -634,6 +655,7 @@ def __init__(self) -> None: # pragma: no cover
634655
}
635656

636657

658+
@beartype
637659
class ContentLengthHeaderNotIntError(ValidatorError):
638660
"""
639661
Exception raised when the given content length header is not an integer.
@@ -656,6 +678,7 @@ def __init__(self) -> None:
656678
}
657679

658680

681+
@beartype
659682
class RequestEntityTooLargeError(ValidatorError):
660683
"""
661684
Exception raised when the given image file size is too large.
@@ -699,6 +722,7 @@ def __init__(self) -> None: # pragma: no cover
699722
}
700723

701724

725+
@beartype
702726
class NoContentTypeError(ValidatorError):
703727
"""
704728
Exception raised when a content type is either not given or is empty.

src/mock_vws/_requests_mock_server/decorators.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from urllib.parse import urljoin, urlparse
99

1010
import requests
11+
from beartype import BeartypeConf, beartype
1112
from responses import RequestsMock
1213

1314
from mock_vws.database import VuforiaDatabase
@@ -28,6 +29,7 @@
2829
_BRISQUE_TRACKING_RATER = BrisqueTargetTrackingRater()
2930

3031

32+
@beartype(conf=BeartypeConf(is_pep484_tower=True))
3133
class MockVWS(ContextDecorator):
3234
"""
3335
Route requests to Vuforia's Web Service APIs to fakes of those APIs.
@@ -86,7 +88,7 @@ def __init__(
8688

8789
self._mock_vws_api = MockVuforiaWebServicesAPI(
8890
target_manager=self._target_manager,
89-
processing_time_seconds=processing_time_seconds,
91+
processing_time_seconds=float(processing_time_seconds),
9092
duplicate_match_checker=duplicate_match_checker,
9193
target_tracking_rater=target_tracking_rater,
9294
)

src/mock_vws/_requests_mock_server/mock_web_query_api.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from collections.abc import Callable
1010
from http import HTTPMethod, HTTPStatus
1111

12+
from beartype import beartype
1213
from requests.models import PreparedRequest
1314

1415
from mock_vws._mock_common import Route
@@ -27,6 +28,7 @@
2728
_ResponseType = tuple[int, dict[str, str], str]
2829

2930

31+
@beartype
3032
def route(
3133
path_pattern: str,
3234
http_methods: set[str],
@@ -66,6 +68,7 @@ def decorator(
6668
return decorator
6769

6870

71+
@beartype
6972
def _body_bytes(request: PreparedRequest) -> bytes:
7073
"""
7174
Return the body of a request as bytes.
@@ -77,6 +80,7 @@ def _body_bytes(request: PreparedRequest) -> bytes:
7780
return request.body
7881

7982

83+
@beartype
8084
class MockVuforiaWebQueryAPI:
8185
"""
8286
A fake implementation of the Vuforia Web Query API.

0 commit comments

Comments
 (0)