mypy fixes

This commit is contained in:
Sebastian Goscik
2024-08-10 00:17:55 +01:00
parent 0a6a259120
commit 78be4808d9
8 changed files with 95 additions and 57 deletions

View File

@@ -19,9 +19,11 @@ repos:
# Run the formatter.
- id: ruff-format
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.901
rev: v1.11.1
hooks:
- id: mypy
exclude: tests/
additional_dependencies:
- types-click
- types-pytz
- types-cryptography
- types-python-dateutil

75
poetry.lock generated
View File

@@ -869,53 +869,60 @@ files = [
[[package]]
name = "mypy"
version = "0.900"
version = "1.11.1"
description = "Optional static typing for Python"
optional = false
python-versions = ">=3.5"
python-versions = ">=3.8"
files = [
{file = "mypy-0.900-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:07efc88486877d595cca7f7d237e6d04d1ba6f01dc8f74a81b716270f6770968"},
{file = "mypy-0.900-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:80c96f97de241ee7383cfe646bfc51113a48089d50c33275af0033b98dee3b1c"},
{file = "mypy-0.900-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:0e703c0afe36511746513d168e1d2a52f88e2a324169b87a6b6a58901c3afcf3"},
{file = "mypy-0.900-cp35-cp35m-win_amd64.whl", hash = "sha256:23100137579d718cd6f05d572574ca00701fa2bfc7b645ebc5130d93e2af3bee"},
{file = "mypy-0.900-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:468b3918b26f81d003e8e9b788c62160acb885487cf4d83a3f22ba9061cb49e2"},
{file = "mypy-0.900-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d90c296cd5cdef86e720a0994d41d72c06d6ff8ab8fc6aaaf0ee6c675835d596"},
{file = "mypy-0.900-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:42d66b3d716fe5e22b32915d1fa59e7183a0e02f00b337b834a596c1f5e37f01"},
{file = "mypy-0.900-cp36-cp36m-win_amd64.whl", hash = "sha256:a354613b4cc6e0e9f1ba7811083cd8f63ccee97333d1df7594c438399c83249a"},
{file = "mypy-0.900-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:22f97de97373dd6180c4abee90b20c60780820284d2cdc5579927c0e37854cf6"},
{file = "mypy-0.900-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e75f0c97cfe8d86da89b22ad7039f5af44b8f6b0af12bd2877791a92b4b9e987"},
{file = "mypy-0.900-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:41f082275a20e3eea48364915f7bc6ec5338be89db1ed8b2e570b9e3d12d4dc6"},
{file = "mypy-0.900-cp37-cp37m-win_amd64.whl", hash = "sha256:83adbf3f8c5023f4276557fbcb3b6306f9dce01783e8ac5f8c11fcb29f62e899"},
{file = "mypy-0.900-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2220f97804890f3e6da3f849f81f3e56e367a2027a51dde5ce3b7ebb2ad3342b"},
{file = "mypy-0.900-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:3f1d0601842c6b4248923963fc59a6fdd05dee0fddc8b07e30c508b6a269e68f"},
{file = "mypy-0.900-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:c2f87505840c0f3557ea4aa5893f2459daf6516adac30b15d1d5cf567e0d7939"},
{file = "mypy-0.900-cp38-cp38-win_amd64.whl", hash = "sha256:a0461da00ed23d17fcb04940db2b72f920435cf79be943564b717e378ffeeddf"},
{file = "mypy-0.900-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9560b1f572cdaab43fdcdad5ef45138e89dc191729329db1b8ce5636f4cdeacf"},
{file = "mypy-0.900-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d794f10b9f28d21af7a93054e217872aaf9b9ad1bd354ae5e1a3a923d734b73f"},
{file = "mypy-0.900-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:68fd1c1c1fc9b405f0ed6cfcd00541de7e83f41007419a125c20fa5db3881cb1"},
{file = "mypy-0.900-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:7eb1e5820deb71e313aa2b5a5220803a9b2e3efa43475537a71d0ffed7495e1e"},
{file = "mypy-0.900-cp39-cp39-win_amd64.whl", hash = "sha256:6598e39cd5aa1a09d454ad39687b89cf3f3fd7cf1f9c3f81a1a2775f6f6b16f8"},
{file = "mypy-0.900-py3-none-any.whl", hash = "sha256:3be7c68fab8b318a2d5bcfac8e028dc77b9096ea1ec5594e9866c8fb57ae0296"},
{file = "mypy-0.900.tar.gz", hash = "sha256:65c78570329c54fb40f956f7645e2359af5da9d8c54baa44f461cdc7f4984108"},
{file = "mypy-1.11.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a32fc80b63de4b5b3e65f4be82b4cfa362a46702672aa6a0f443b4689af7008c"},
{file = "mypy-1.11.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c1952f5ea8a5a959b05ed5f16452fddadbaae48b5d39235ab4c3fc444d5fd411"},
{file = "mypy-1.11.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e1e30dc3bfa4e157e53c1d17a0dad20f89dc433393e7702b813c10e200843b03"},
{file = "mypy-1.11.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2c63350af88f43a66d3dfeeeb8d77af34a4f07d760b9eb3a8697f0386c7590b4"},
{file = "mypy-1.11.1-cp310-cp310-win_amd64.whl", hash = "sha256:a831671bad47186603872a3abc19634f3011d7f83b083762c942442d51c58d58"},
{file = "mypy-1.11.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7b6343d338390bb946d449677726edf60102a1c96079b4f002dedff375953fc5"},
{file = "mypy-1.11.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e4fe9f4e5e521b458d8feb52547f4bade7ef8c93238dfb5bbc790d9ff2d770ca"},
{file = "mypy-1.11.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:886c9dbecc87b9516eff294541bf7f3655722bf22bb898ee06985cd7269898de"},
{file = "mypy-1.11.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fca4a60e1dd9fd0193ae0067eaeeb962f2d79e0d9f0f66223a0682f26ffcc809"},
{file = "mypy-1.11.1-cp311-cp311-win_amd64.whl", hash = "sha256:0bd53faf56de9643336aeea1c925012837432b5faf1701ccca7fde70166ccf72"},
{file = "mypy-1.11.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f39918a50f74dc5969807dcfaecafa804fa7f90c9d60506835036cc1bc891dc8"},
{file = "mypy-1.11.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0bc71d1fb27a428139dd78621953effe0d208aed9857cb08d002280b0422003a"},
{file = "mypy-1.11.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b868d3bcff720dd7217c383474008ddabaf048fad8d78ed948bb4b624870a417"},
{file = "mypy-1.11.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a707ec1527ffcdd1c784d0924bf5cb15cd7f22683b919668a04d2b9c34549d2e"},
{file = "mypy-1.11.1-cp312-cp312-win_amd64.whl", hash = "sha256:64f4a90e3ea07f590c5bcf9029035cf0efeae5ba8be511a8caada1a4893f5525"},
{file = "mypy-1.11.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:749fd3213916f1751fff995fccf20c6195cae941dc968f3aaadf9bb4e430e5a2"},
{file = "mypy-1.11.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b639dce63a0b19085213ec5fdd8cffd1d81988f47a2dec7100e93564f3e8fb3b"},
{file = "mypy-1.11.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c956b49c5d865394d62941b109728c5c596a415e9c5b2be663dd26a1ff07bc0"},
{file = "mypy-1.11.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:45df906e8b6804ef4b666af29a87ad9f5921aad091c79cc38e12198e220beabd"},
{file = "mypy-1.11.1-cp38-cp38-win_amd64.whl", hash = "sha256:d44be7551689d9d47b7abc27c71257adfdb53f03880841a5db15ddb22dc63edb"},
{file = "mypy-1.11.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2684d3f693073ab89d76da8e3921883019ea8a3ec20fa5d8ecca6a2db4c54bbe"},
{file = "mypy-1.11.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:79c07eb282cb457473add5052b63925e5cc97dfab9812ee65a7c7ab5e3cb551c"},
{file = "mypy-1.11.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11965c2f571ded6239977b14deebd3f4c3abd9a92398712d6da3a772974fad69"},
{file = "mypy-1.11.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a2b43895a0f8154df6519706d9bca8280cda52d3d9d1514b2d9c3e26792a0b74"},
{file = "mypy-1.11.1-cp39-cp39-win_amd64.whl", hash = "sha256:1a81cf05975fd61aec5ae16501a091cfb9f605dc3e3c878c0da32f250b74760b"},
{file = "mypy-1.11.1-py3-none-any.whl", hash = "sha256:0624bdb940255d2dd24e829d99a13cfeb72e4e9031f9492148f410ed30bcab54"},
{file = "mypy-1.11.1.tar.gz", hash = "sha256:f404a0b069709f18bbdb702eb3dcfe51910602995de00bd39cea3050b5772d08"},
]
[package.dependencies]
mypy-extensions = ">=0.4.3,<0.5.0"
toml = "*"
typing-extensions = ">=3.7.4"
mypy-extensions = ">=1.0.0"
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
typing-extensions = ">=4.6.0"
[package.extras]
dmypy = ["psutil (>=4.0)"]
python2 = ["typed-ast (>=1.4.0,<1.5.0)"]
install-types = ["pip"]
mypyc = ["setuptools (>=50)"]
reports = ["lxml"]
[[package]]
name = "mypy-extensions"
version = "0.4.4"
description = "Experimental type system extensions for programs checked with the mypy typechecker."
version = "1.0.0"
description = "Type system extensions for programs checked with the mypy type checker."
optional = false
python-versions = ">=2.7"
python-versions = ">=3.5"
files = [
{file = "mypy_extensions-0.4.4.tar.gz", hash = "sha256:c8b707883a96efe9b4bb3aaf0dcc07e7e217d7d8368eec4db4049ee9e142f4fd"},
{file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"},
{file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
]
[[package]]
@@ -1992,4 +1999,4 @@ multidict = ">=4.0"
[metadata]
lock-version = "2.0"
python-versions = ">=3.10.0,<4.0"
content-hash = "81ee0cdb5af9e498001e3e8239c0ba259d114e19a2099f133b2de9645f596788"
content-hash = "dea68a0cc11ccb56faf879210d124f44b2ee73a7a36205f1214dd8ab35451d1c"

View File

@@ -36,7 +36,7 @@ uiprotect = "^5.4.0"
optional = true
[tool.poetry.group.dev.dependencies]
mypy = "^0.900"
mypy = "^1.11.1"
types-pytz = "^2021.3.5"
types-cryptography = "^3.3.18"
types-python-dateutil = "^2.8.19.10"

View File

@@ -12,10 +12,10 @@ from .uploader import VideoUploader
from .missing_event_checker import MissingEventChecker
__all__ = [
VideoDownloader,
VideoDownloaderExperimental,
EventListener,
Purge,
VideoUploader,
MissingEventChecker,
"VideoDownloader",
"VideoDownloaderExperimental",
"EventListener",
"Purge",
"VideoUploader",
"MissingEventChecker",
]

View File

@@ -85,6 +85,8 @@ class VideoDownloaderExperimental:
else:
self._has_ffprobe = False
raise RuntimeError("The `uiprotect` library is currently missing the features for this to work.")
async def start(self):
"""Main loop."""
self.logger.info("Starting Downloader")
@@ -149,7 +151,10 @@ class VideoDownloaderExperimental:
self._failures[event.id] = 1
else:
self._failures[event.id] += 1
self.logger.warning(f"Event failed download attempt {self._failures[event.id]}", exc_info=e)
self.logger.warning(
f"Event failed download attempt {self._failures[event.id]}",
exc_info=e,
)
if self._failures[event.id] >= 10:
self.logger.error(
@@ -171,7 +176,10 @@ class VideoDownloaderExperimental:
self.current_event = None
except Exception as e:
self.logger.error(f"Unexpected exception occurred, abandoning event {event.id}:", exc_info=e)
self.logger.error(
f"Unexpected exception occurred, abandoning event {event.id}:",
exc_info=e,
)
async def _download(self, event: Event) -> Optional[bytes]:
"""Downloads the video clip for the given event."""
@@ -181,8 +189,12 @@ class VideoDownloaderExperimental:
assert isinstance(event.start, datetime)
assert isinstance(event.end, datetime)
try:
prepared_video_file = await self._protect.prepare_camera_video(event.camera_id, event.start, event.end)
video = await self._protect.download_camera_video(event.camera_id, prepared_video_file["fileName"])
prepared_video_file = await self._protect.prepare_camera_video( # type: ignore
event.camera_id, event.start, event.end
)
video = await self._protect.download_camera_video( # type: ignore
event.camera_id, prepared_video_file["fileName"]
)
assert isinstance(video, bytes)
break
except (AssertionError, ClientPayloadError, TimeoutError) as e:

View File

@@ -3,7 +3,7 @@
import asyncio
import logging
from datetime import datetime
from typing import List
from typing import AsyncIterator, List
import aiosqlite
from dateutil.relativedelta import relativedelta
@@ -54,14 +54,14 @@ class MissingEventChecker:
self.ignore_cameras: List[str] = ignore_cameras
self.interval: int = interval
async def _get_missing_events(self) -> List[Event]:
async def _get_missing_events(self) -> AsyncIterator[Event]:
start_time = datetime.now() - self.retention
end_time = datetime.now()
chunk_size = 500
while True:
# Get list of events that need to be backed up from unifi protect
logger.extra_debug(f"Fetching events for interval: {start_time} - {end_time}")
logger.extra_debug(f"Fetching events for interval: {start_time} - {end_time}") # type: ignore
events_chunk = await self._protect.get_events(
start=start_time,
end=end_time,
@@ -72,6 +72,7 @@ class MissingEventChecker:
if not events_chunk:
break # There were no events to backup
assert events_chunk[-1].end is not None
start_time = events_chunk[-1].end
unifi_events = {event.id: event for event in events_chunk}
@@ -166,6 +167,9 @@ class MissingEventChecker:
await self._download_queue.put(event)
except Exception as e:
logger.error("Unexpected exception occurred during missing event check:", exc_info=e)
logger.error(
"Unexpected exception occurred during missing event check:",
exc_info=e,
)
await asyncio.sleep(self.interval)

View File

@@ -21,7 +21,13 @@ from unifi_protect_backup import (
VideoUploader,
notifications,
)
from unifi_protect_backup.utils import SubprocessException, VideoQueue, human_readable_size, run_command, setup_logging
from unifi_protect_backup.utils import (
SubprocessException,
VideoQueue,
human_readable_size,
run_command,
setup_logging,
)
logger = logging.getLogger(__name__)
@@ -67,7 +73,7 @@ class UnifiProtectBackup:
max_event_length: int,
sqlite_path: str = "events.sqlite",
color_logging: bool = False,
download_rate_limit: float = None,
download_rate_limit: float | None = None,
port: int = 443,
use_experimental_downloader: bool = False,
):
@@ -196,7 +202,10 @@ class UnifiProtectBackup:
await self._protect.update()
break
except Exception as e:
logger.warning(f"Failed to connect to UniFi Protect, retrying in {attempts}s...", exc_info=e)
logger.warning(
f"Failed to connect to UniFi Protect, retrying in {attempts}s...",
exc_info=e,
)
await asyncio.sleep(attempts)
else:
raise ConnectionError("Failed to connect to UniFi Protect after 10 attempts")
@@ -269,7 +278,11 @@ class UnifiProtectBackup:
# Create purge task
# This will, every midnight, purge old backups from the rclone remotes and database
purge = Purge(
self._db, self.retention, self.rclone_destination, self._purge_interval, self.rclone_purge_args
self._db,
self.retention,
self.rclone_destination,
self._purge_interval,
self.rclone_purge_args,
)
tasks.append(purge.start())

View File

@@ -294,7 +294,7 @@ async def get_camera_name(protect: ProtectApiClient, id: str):
# Refresh cameras
logger.debug(f"Unknown camera id: '{id}', checking API")
await protect.update(force=True)
await protect.update()
try:
name = protect.bootstrap.cameras[id].name
@@ -377,7 +377,7 @@ class VideoQueue(asyncio.Queue):
self._queue.append(item) # type: ignore
self._bytes_sum += len(item[1])
def full(self, item: tuple[Event, bytes] = None):
def full(self, item: tuple[Event, bytes] | None = None):
"""Return True if there are maxsize bytes in the queue.
optionally if `item` is provided, it will return False if there is enough space to