Skip to content

Commit

Permalink
Merge pull request #2268 from VWS-Python/more-beartype
Browse files Browse the repository at this point in the history
Add more beartype runtime checking
  • Loading branch information
adamtheturtle authored Aug 30, 2024
2 parents ca084f5 + 715c189 commit 8317702
Show file tree
Hide file tree
Showing 17 changed files with 87 additions and 24 deletions.
2 changes: 1 addition & 1 deletion conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ def pytest_collection_modifyitems(items: list[pytest.Item]) -> None:
).pytest()


@pytest.hookimpl(optionalhook=True)
@beartype
@pytest.hookimpl(optionalhook=True)
def pytest_set_filtered_exceptions() -> tuple[type[Exception], ...]:
"""
Return exceptions to retry on.
Expand Down
4 changes: 4 additions & 0 deletions src/mock_vws/_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@

from enum import Enum

from beartype import beartype


@beartype
class ResultCodes(Enum):
"""
Constants representing various VWS result codes.
Expand Down Expand Up @@ -37,6 +40,7 @@ class ResultCodes(Enum):
TOO_MANY_REQUESTS = "TooManyRequests"


@beartype
class TargetStatuses(Enum):
"""
Constants representing VWS target statuses.
Expand Down
3 changes: 3 additions & 0 deletions src/mock_vws/_flask_server/healthcheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
import sys
from http import HTTPStatus

from beartype import beartype


@beartype
def flask_app_healthy(port: int) -> bool:
"""
Check if the Flask app is healthy.
Expand Down
8 changes: 7 additions & 1 deletion src/mock_vws/_flask_server/target_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
TARGET_MANAGER = TargetManager()


@beartype
class _TargetRaterChoice(StrEnum):
"""Target rater choices."""

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


@beartype
class TargetManagerSettings(BaseSettings):
"""Settings for the Target Manager Flask app."""

Expand All @@ -59,6 +61,7 @@ class TargetManagerSettings(BaseSettings):
"/databases/<string:database_name>",
methods=[HTTPMethod.DELETE],
)
@beartype
def delete_database(database_name: str) -> Response:
"""
Delete a database.
Expand Down Expand Up @@ -92,6 +95,7 @@ def get_databases() -> Response:


@TARGET_MANAGER_FLASK_APP.route("/databases", methods=[HTTPMethod.POST])
@beartype
def create_database() -> Response:
"""
Create a new database.
Expand Down Expand Up @@ -177,6 +181,7 @@ def create_database() -> Response:
"/databases/<string:database_name>/targets",
methods=[HTTPMethod.POST],
)
@beartype
def create_target(database_name: str) -> Response:
"""
Create a new target in a given database.
Expand Down Expand Up @@ -212,8 +217,9 @@ def create_target(database_name: str) -> Response:

@TARGET_MANAGER_FLASK_APP.route(
"/databases/<string:database_name>/targets/<string:target_id>",
methods=[HTTPMethod.DELETE],
methods={HTTPMethod.DELETE},
)
@beartype
def delete_target(database_name: str, target_id: str) -> Response:
"""
Delete a target.
Expand Down
3 changes: 3 additions & 0 deletions src/mock_vws/_flask_server/vwq.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
CLOUDRECO_FLASK_APP.config["PROPAGATE_EXCEPTIONS"] = True


@beartype
class _ImageMatcherChoice(StrEnum):
"""Image matcher choices."""

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


@beartype
class VWQSettings(BaseSettings):
"""Settings for the VWQ Flask app."""

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


@CLOUDRECO_FLASK_APP.before_request
@beartype
def set_terminate_wsgi_input() -> None:
"""
We set ``wsgi.input_terminated`` to ``True`` when going through
Expand Down
4 changes: 4 additions & 0 deletions src/mock_vws/_flask_server/vws.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
_LOGGER = logging.getLogger(name=__name__)


@beartype
class _ImageMatcherChoice(StrEnum):
"""Image matcher choices."""

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


@beartype
class VWSSettings(BaseSettings):
"""Settings for the VWS Flask app."""

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


@VWS_FLASK_APP.route("/targets", methods=[HTTPMethod.POST])
@beartype
def add_target() -> Response:
"""
Add a target.
Expand Down Expand Up @@ -334,6 +337,7 @@ def delete_target(target_id: str) -> Response:


@VWS_FLASK_APP.route("/summary", methods=[HTTPMethod.GET])
@beartype
def database_summary() -> Response:
"""
Get a database summary report.
Expand Down
24 changes: 24 additions & 0 deletions src/mock_vws/_query_validators/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@
import uuid
from http import HTTPStatus

from beartype import beartype

from mock_vws._constants import ResultCodes
from mock_vws._mock_common import json_dump


@beartype
class ValidatorError(Exception):
"""
A base class for exceptions thrown from mock Vuforia cloud recognition
Expand All @@ -22,6 +25,7 @@ class ValidatorError(Exception):
headers: dict[str, str]


@beartype
class DateHeaderNotGivenError(ValidatorError):
"""
Exception raised when a date header is not given.
Expand Down Expand Up @@ -52,6 +56,7 @@ def __init__(self) -> None:
}


@beartype
class DateFormatNotValidError(ValidatorError):
"""
Exception raised when the date format is not valid.
Expand Down Expand Up @@ -83,6 +88,7 @@ def __init__(self) -> None:
}


@beartype
class RequestTimeTooSkewedError(ValidatorError):
"""
Exception raised when Vuforia returns a response with a result code
Expand Down Expand Up @@ -118,6 +124,7 @@ def __init__(self) -> None:
}


@beartype
class BadImageError(ValidatorError):
"""
Exception raised when Vuforia returns a response with a result code
Expand Down Expand Up @@ -160,6 +167,7 @@ def __init__(self) -> None:
}


@beartype
class AuthenticationFailureError(ValidatorError):
"""
Exception raised when Vuforia returns a response with a result code
Expand Down Expand Up @@ -202,6 +210,7 @@ def __init__(self) -> None:
}


@beartype
class AuthenticationFailureGoodFormattingError(ValidatorError):
"""
Exception raised when Vuforia returns a response with a result code
Expand Down Expand Up @@ -239,6 +248,7 @@ def __init__(self) -> None:
}


@beartype
class ImageNotGivenError(ValidatorError):
"""
Exception raised when an image is not given.
Expand Down Expand Up @@ -270,6 +280,7 @@ def __init__(self) -> None:
}


@beartype
class AuthHeaderMissingError(ValidatorError):
"""
Exception raised when an auth header is not given.
Expand Down Expand Up @@ -302,6 +313,7 @@ def __init__(self) -> None:
}


@beartype
class MalformedAuthHeaderError(ValidatorError):
"""
Exception raised when an auth header is not given.
Expand Down Expand Up @@ -335,6 +347,7 @@ def __init__(self) -> None:
}


@beartype
class UnknownParametersError(ValidatorError):
"""
Exception raised when unknown parameters are given.
Expand Down Expand Up @@ -366,6 +379,7 @@ def __init__(self) -> None:
}


@beartype
class InactiveProjectError(ValidatorError):
"""
Exception raised when Vuforia returns a response with a result code
Expand Down Expand Up @@ -407,6 +421,7 @@ def __init__(self) -> None:
}


@beartype
class InvalidMaxNumResultsError(ValidatorError):
"""
Exception raised when an invalid value is given as the
Expand Down Expand Up @@ -443,6 +458,7 @@ def __init__(self, given_value: str) -> None:
}


@beartype
class MaxNumResultsOutOfRangeError(ValidatorError):
"""
Exception raised when an integer value is given as the "max_num_results"
Expand Down Expand Up @@ -479,6 +495,7 @@ def __init__(self, given_value: str) -> None:
}


@beartype
class InvalidIncludeTargetDataError(ValidatorError):
"""
Exception raised when an invalid value is given as the
Expand Down Expand Up @@ -517,6 +534,7 @@ def __init__(self, given_value: str) -> None:
}


@beartype
class UnsupportedMediaTypeError(ValidatorError):
"""
Exception raised when no boundary is found for multipart data.
Expand Down Expand Up @@ -547,6 +565,7 @@ def __init__(self) -> None:
}


@beartype
class InvalidAcceptHeaderError(ValidatorError):
"""
Exception raised when there is an invalid accept header given.
Expand Down Expand Up @@ -577,6 +596,7 @@ def __init__(self) -> None:
}


@beartype
class NoBoundaryFoundError(ValidatorError):
"""
Exception raised when an invalid media type is given.
Expand Down Expand Up @@ -611,6 +631,7 @@ def __init__(self) -> None:
}


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


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


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


@beartype
class NoContentTypeError(ValidatorError):
"""
Exception raised when a content type is either not given or is empty.
Expand Down
4 changes: 3 additions & 1 deletion src/mock_vws/_requests_mock_server/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from urllib.parse import urljoin, urlparse

import requests
from beartype import BeartypeConf, beartype
from responses import RequestsMock

from mock_vws.database import VuforiaDatabase
Expand All @@ -28,6 +29,7 @@
_BRISQUE_TRACKING_RATER = BrisqueTargetTrackingRater()


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

self._mock_vws_api = MockVuforiaWebServicesAPI(
target_manager=self._target_manager,
processing_time_seconds=processing_time_seconds,
processing_time_seconds=float(processing_time_seconds),
duplicate_match_checker=duplicate_match_checker,
target_tracking_rater=target_tracking_rater,
)
Expand Down
4 changes: 4 additions & 0 deletions src/mock_vws/_requests_mock_server/mock_web_query_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from collections.abc import Callable
from http import HTTPMethod, HTTPStatus

from beartype import beartype
from requests.models import PreparedRequest

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


@beartype
def route(
path_pattern: str,
http_methods: set[str],
Expand Down Expand Up @@ -66,6 +68,7 @@ def decorator(
return decorator


@beartype
def _body_bytes(request: PreparedRequest) -> bytes:
"""
Return the body of a request as bytes.
Expand All @@ -77,6 +80,7 @@ def _body_bytes(request: PreparedRequest) -> bytes:
return request.body


@beartype
class MockVuforiaWebQueryAPI:
"""
A fake implementation of the Vuforia Web Query API.
Expand Down
Loading

0 comments on commit 8317702

Please sign in to comment.