Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ updates:
# together, keeping the lockfile in sync so that
# ``uv sync --locked`` in the Dockerfile keeps working.
- package-ecosystem: uv
allow:
- dependency-type: all
directory: /
schedule:
interval: daily
Expand All @@ -14,7 +16,6 @@ updates:
directory: /
schedule:
interval: daily
- package-ecosystem: pre-commit
directory: /
schedule:
interval: daily

# Dependabot cannot read prek.toml yet:
# https://github.com/dependabot/dependabot-core/issues/14624
2 changes: 2 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ jobs:
environment: vuforia
strategy:
fail-fast: false
# Keep the combined polling load on the live Vuforia service bounded.
max-parallel: 10
matrix:
python-version: ['3.15']
ci_pattern:
Expand Down
6 changes: 3 additions & 3 deletions admin/create_secrets_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
See the instructions in the contributing guide in the documentation.
"""

import datetime
import datetime as dt
import os
import sys
import textwrap
Expand Down Expand Up @@ -235,7 +235,7 @@ def _get_model_target_web_api_details(

def _create_vuforia_resource_names() -> tuple[str, str, str, str]:
"""Create names for Vuforia resources."""
time = datetime.datetime.now(tz=datetime.UTC).strftime(
time = dt.datetime.now(tz=dt.UTC).strftime(
format="%Y-%m-%d-%H-%M-%S",
)
return (
Expand All @@ -253,7 +253,7 @@ def main() -> None:
new_secrets_dir = Path(os.environ["NEW_SECRETS_DIR"]).expanduser()
new_secrets_dir.mkdir(exist_ok=True)

time = datetime.datetime.now(tz=datetime.UTC).strftime(
time = dt.datetime.now(tz=dt.UTC).strftime(
format="%Y-%m-%d-%H-%M-%S",
)
inactive_driver = vws_web_tools.create_chrome_driver()
Expand Down
40 changes: 20 additions & 20 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ urls.Source = "https://github.com/VWS-Python/vws-python-mock"
[dependency-groups]
dev = [
"actionlint-py==1.7.12.25",
"beartype==0.23.0",
"beartype==0.23.1",
"check-manifest==0.51",
"check-wheel-contents==0.6.3",
"coverage==7.16.2",
Expand All @@ -80,62 +80,62 @@ dev = [
"interrogate==1.7.0",
"mypy==2.4.0",
"mypy-pytest-parametrize==2026.10.5.1",
"mypy-strict-kwargs==2026.8.25.1",
"mypy-strict-kwargs==2026.10.19",
"myst-parser==5.1.0",
"no-defaults==2026.9.1",
"prek==0.5.5",
"prek==0.5.6",
"pydocstringformatter==1.0.0",
"pydocstyle==6.3",
"pylint[spelling]==4.1.2",
"pylint[spelling]==4.1.3",
"pylint-per-file-ignores==4.0.0",
"pyproject-fmt==2.30.1",
"pyproject-fmt==2.30.3",
"pyprojroot==0.3.0",
"pyrefly==1.3.2",
"pyright==1.1.414",
"pyroma==5.0.1",
"pytest==9.1.1",
"pytest-beartype==0.3.0",
"pytest-multi-backend==2026.9.7",
"pytest-partition-check==2026.8.23",
"pytest-partition-check==2026.10.11",
"pytest-retry==1.7.0",
"pytest-xdist==3.8.0",
"pyyaml==6.0.3",
"requests-mock-flask==2026.9.8",
"ruff==0.16.10",
"requests-mock-flask==2026.10.9",
"ruff==0.17.1",
# We add shellcheck-py not only for shell scripts and shell code blocks,
# but also because having it installed means that ``actionlint-py`` will
# use it to lint shell commands in GitHub workflow files.
"shellcheck-py==0.11.0.1",
"shfmt-py==4.2.0",
"snapper-fmt==0.11.9",
"sphinx==9.1.0",
"snapper-fmt==0.11.10",
"sphinx==9.1.1",
"sphinx-copybutton==0.5.2",
"sphinx-lint==1.0.2",
"sphinx-paramlinks==0.6",
"sphinx-pyproject==0.3.0",
"sphinx-substitution-extensions==2026.8.13.1",
"sphinx-substitution-extensions==2026.10.9",
"sphinx-toolbox==4.3.1",
"sphinxcontrib-httpdomain==2.1.0",
"sphinxcontrib-httpdomain==2.2.1",
"sphinxcontrib-spelling==8.0.2",
# ``sphinxcontrib-towncrier`` renders unreleased news fragments
# as Markdown in docs/source/unreleased.md during Sphinx builds.
"sphinxcontrib-towncrier==0.5.0a0",
"strict-kwargs==2026.8.28.post2",
"strict-kwargs==2026.10.9",
"sybil==10.1.0",
"tenacity==9.1.4",
"tenacity==9.2.1",
"towncrier==26.9.0",
"ty==0.0.85",
"types-docker==7.2.0.20260923",
"ty==0.0.89",
"types-docker==7.2.0.20261006",
"types-pyyaml==6.0.12.20260906",
"types-requests==2.33.0.20260906",
"types-requests==2.33.0.20261006",
"urllib3==2.8.0",
"vale==3.22.0.0",
"vulture==2.16",
"vws-python==2026.9.7",
"vws-test-fixtures==2026.8.26",
"vws-python==2026.10.9",
"vws-test-fixtures==2026.10.8",
"vws-web-tools==2026.8.27",
"yamlfix==1.19.1",
"zizmor==1.30.1",
"zizmor==1.31.1",
]
release = [ "check-wheel-contents==0.6.3", "towncrier==26.9.0" ]

Expand Down
6 changes: 3 additions & 3 deletions src/mock_vws/_flask_server/target_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import base64
import copy
import datetime
import datetime as dt
import json
from collections.abc import Callable, Sequence
from enum import Enum, StrEnum, auto
Expand Down Expand Up @@ -877,7 +877,7 @@ def delete_target(database_name: str, target_id: str) -> Response:
return Response(response="", status=HTTPStatus.NOT_FOUND)

target = database.get_target(target_id=target_id)
now = datetime.datetime.now(tz=target.upload_date.tzinfo)
now = dt.datetime.now(tz=target.upload_date.tzinfo)
new_target = copy.replace(
target,
delete_date=now,
Expand Down Expand Up @@ -914,7 +914,7 @@ def update_target(database_name: str, target_id: str) -> Response:
active_flag = request_body.get("active_flag", target.active_flag)

gmt = ZoneInfo(key="GMT")
last_modified_date = datetime.datetime.now(tz=gmt)
last_modified_date = dt.datetime.now(tz=gmt)

width = request_body.get("width", target.width)
application_metadata = request_body.get(
Expand Down
4 changes: 2 additions & 2 deletions src/mock_vws/_mock_common.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Common utilities for creating mock routes."""

import datetime
import datetime as dt
import email.utils
import json
import uuid
Expand Down Expand Up @@ -120,7 +120,7 @@ def bind(self, *, api: API) -> Route:


@beartype
def _upload_order_key(target: ImageTarget) -> tuple[datetime.datetime, str]:
def _upload_order_key(target: ImageTarget) -> tuple[dt.datetime, str]:
"""Give the sort key which orders targets by upload date, then ID.

Args:
Expand Down
14 changes: 6 additions & 8 deletions src/mock_vws/_query_validators/date_validators.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Validators of the date header to use in the mock query API."""

import contextlib
import datetime
import datetime as dt
import logging
from collections.abc import Mapping
from zoneinfo import ZoneInfo
Expand Down Expand Up @@ -67,9 +67,7 @@ def validate_date_format(*, request_headers: Mapping[str, str]) -> None:

for date_format in _accepted_date_formats():
with contextlib.suppress(ValueError):
_ = datetime.datetime.strptime(
date_header, date_format
).astimezone()
_ = dt.datetime.strptime(date_header, date_format).astimezone()
return

_LOGGER.warning(msg="The date header is in the wrong format.")
Expand All @@ -89,21 +87,21 @@ def validate_date_in_range(*, request_headers: Mapping[str, str]) -> None:
date_header = request_headers["Date"]
gmt = ZoneInfo(key="GMT")

dates: list[datetime.datetime] = []
dates: list[dt.datetime] = []
for date_format in _accepted_date_formats():
with contextlib.suppress(ValueError):
date = datetime.datetime.strptime(
date = dt.datetime.strptime(
date_header,
date_format,
).astimezone()
dates.append(date)

date = dates[0]
now = datetime.datetime.now(tz=gmt)
now = dt.datetime.now(tz=gmt)
date_from_header = date.replace(tzinfo=gmt)
time_difference = now - date_from_header

maximum_time_difference = datetime.timedelta(minutes=65)
maximum_time_difference = dt.timedelta(minutes=65)

if abs(time_difference) < maximum_time_difference:
return
Expand Down
14 changes: 7 additions & 7 deletions src/mock_vws/_reco_counts_web_api.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""A fake implementation of the Vuforia reco counts report endpoints."""

import base64
import datetime
import datetime as dt
import email.utils
import logging
import re
Expand Down Expand Up @@ -65,9 +65,9 @@ def add_reco_counts_report(


@beartype
def _now() -> datetime.datetime:
def _now() -> dt.datetime:
"""Return the current time in UTC."""
return datetime.datetime.now(tz=ZoneInfo(key="UTC"))
return dt.datetime.now(tz=ZoneInfo(key="UTC"))


@beartype
Expand Down Expand Up @@ -161,7 +161,7 @@ def _months_in_range() -> set[str]:
"""
now = _now()
first_of_month = now.replace(day=1)
last_of_previous_month = first_of_month - datetime.timedelta(days=1)
last_of_previous_month = first_of_month - dt.timedelta(days=1)
return {
_current_month(),
last_of_previous_month.strftime(format="%Y-%m"),
Expand Down Expand Up @@ -189,7 +189,7 @@ def _report_file_name(*, month: str) -> str:


@beartype
def _presigned_query(*, signed_at: datetime.datetime) -> str:
def _presigned_query(*, signed_at: dt.datetime) -> str:
"""Return the query string of a presigned URL.

The parameters are the ones which real Vuforia's presigned URLs carry, in
Expand Down Expand Up @@ -355,11 +355,11 @@ def _expiry_error(*, query: Mapping[str, list[str]]) -> _ResponseType | None:
try:
(date_value,) = query.get("X-Amz-Date", [])
(expires_value,) = query.get("X-Amz-Expires", [])
signed_at = datetime.datetime.strptime(
signed_at = dt.datetime.strptime(
date_value,
_AMZ_DATE_FORMAT,
).replace(tzinfo=ZoneInfo(key="UTC"))
expires_after = datetime.timedelta(seconds=int(expires_value))
expires_after = dt.timedelta(seconds=int(expires_value))
except ValueError:
return access_denied

Expand Down
6 changes: 3 additions & 3 deletions src/mock_vws/_requests_mock_server/mock_web_services_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import base64
import copy
import datetime
import datetime as dt
import email.utils
import uuid
from collections.abc import Callable, Iterable, Mapping
Expand Down Expand Up @@ -653,7 +653,7 @@ def delete_target(self, request: RequestData) -> _ResponseType:
target_processing_exception.response_text,
)

now = datetime.datetime.now(tz=target.upload_date.tzinfo)
now = dt.datetime.now(tz=target.upload_date.tzinfo)
new_target = copy.replace(
target,
delete_date=now,
Expand Down Expand Up @@ -1048,7 +1048,7 @@ def update_target(self, request: RequestData) -> _ResponseType:
)

gmt = ZoneInfo(key="GMT")
last_modified_date = datetime.datetime.now(tz=gmt)
last_modified_date = dt.datetime.now(tz=gmt)

width = request_json.get("width", target.width)
application_metadata = request_json.get(
Expand Down
10 changes: 5 additions & 5 deletions src/mock_vws/_services_validators/date_validators.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Validators of the date header to use in the mock services API."""

import datetime
import datetime as dt
import logging
from http import HTTPStatus
from zoneinfo import ZoneInfo
Expand Down Expand Up @@ -47,7 +47,7 @@ def validate_date_format(*, context: ValidatorContext) -> None:
"""
date_header = context.request_headers["Date"]
try:
_ = datetime.datetime.strptime(date_header, _DATE_FORMAT).astimezone()
_ = dt.datetime.strptime(date_header, _DATE_FORMAT).astimezone()
except ValueError as exc:
_LOGGER.warning(msg="The date header is in the wrong format.")
raise FailError(status_code=HTTPStatus.BAD_REQUEST) from exc
Expand All @@ -64,15 +64,15 @@ def validate_date_in_range(*, context: ValidatorContext) -> None:
RequestTimeTooSkewedError: The date is out of range.
"""
gmt = ZoneInfo(key="GMT")
date_from_header = datetime.datetime.strptime(
date_from_header = dt.datetime.strptime(
context.request_headers["Date"],
_DATE_FORMAT,
).replace(tzinfo=gmt)

now = datetime.datetime.now(tz=gmt)
now = dt.datetime.now(tz=gmt)
time_difference = now - date_from_header

maximum_time_difference = datetime.timedelta(minutes=5)
maximum_time_difference = dt.timedelta(minutes=5)

if abs(time_difference) >= maximum_time_difference:
_LOGGER.warning(msg="The date header is out of range.")
Expand Down
Loading
Loading