Configure mypy to run in virtual environment and fix resulting issues (#989)

For some time I've noticed that my IDE is reporting mypy errors that the
pre-commit hook is not picking up. This is because [mypy
mirror](https://github.com/pre-commit/mirrors-mypy) runs in an isolated
pre-commit environment which does not have dependencies installed and it
enables `--ignore-missing-imports` to avoid errors.

This is [advised against by
mypy](https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-library-stubs-or-py-typed-marker)
for obvious reasons:

> We recommend avoiding --ignore-missing-imports if possible: it’s
equivalent to adding a # type: ignore to all unresolved imports in your
codebase.

This PR configures the mypy pre-commit hook to run in the virtual
environment and addresses the additional errors identified as a result.
It also introduces a minimal mypy config into the `pyproject.toml`

[mypy errors identified without the fixes in this
PR](https://github.com/user-attachments/files/15896693/mypyerrors.txt)
This commit is contained in:
Steven B
2024-06-19 14:07:59 +01:00
committed by GitHub
parent 5b7e59056c
commit 416d3118bf
17 changed files with 138 additions and 42 deletions

View File

@@ -231,7 +231,9 @@ def discovery_data(request, mocker):
return {"system": {"get_sysinfo": fixture_data["system"]["get_sysinfo"]}}
@pytest.fixture(params=UNSUPPORTED_DEVICES.values(), ids=UNSUPPORTED_DEVICES.keys())
@pytest.fixture(
params=UNSUPPORTED_DEVICES.values(), ids=list(UNSUPPORTED_DEVICES.keys())
)
def unsupported_device_info(request, mocker):
"""Return unsupported devices for cli and discovery tests."""
discovery_data = request.param

View File

@@ -276,7 +276,7 @@ class FakeSmartTransport(BaseTransport):
):
result["sum"] = len(result[list_key])
if self.warn_fixture_missing_methods:
pytest.fixtures_missing_methods.setdefault(
pytest.fixtures_missing_methods.setdefault( # type: ignore[attr-defined]
self.fixture_name, set()
).add(f"{method} (incomplete '{list_key}' list)")
@@ -305,7 +305,7 @@ class FakeSmartTransport(BaseTransport):
}
# Reduce warning spam by consolidating and reporting at the end of the run
if self.warn_fixture_missing_methods:
pytest.fixtures_missing_methods.setdefault(
pytest.fixtures_missing_methods.setdefault( # type: ignore[attr-defined]
self.fixture_name, set()
).add(method)
return retval

View File

@@ -2,6 +2,7 @@ from __future__ import annotations
import asyncio
import logging
from typing import TypedDict
import pytest
from pytest_mock import MockerFixture
@@ -71,7 +72,17 @@ async def test_firmware_update(
assert fw
upgrade_time = 5
extras = {"reboot_time": 5, "upgrade_time": upgrade_time, "auto_upgrade": False}
class Extras(TypedDict):
reboot_time: int
upgrade_time: int
auto_upgrade: bool
extras: Extras = {
"reboot_time": 5,
"upgrade_time": upgrade_time,
"auto_upgrade": False,
}
update_states = [
# Unknown 1
DownloadState(status=1, download_progress=0, **extras),

View File

@@ -6,6 +6,7 @@ import importlib
import inspect
import pkgutil
import sys
from contextlib import AbstractContextManager
from unittest.mock import Mock, patch
import pytest
@@ -161,7 +162,7 @@ async def _test_attribute(
dev: Device, attribute_name, is_expected, module_name, *args, will_raise=False
):
if is_expected and will_raise:
ctx = pytest.raises(will_raise)
ctx: AbstractContextManager = pytest.raises(will_raise)
elif is_expected:
ctx = pytest.deprecated_call(match=(f"{attribute_name} is deprecated, use:"))
else:

View File

@@ -5,7 +5,7 @@ import pytest
from voluptuous import (
All,
Any,
Coerce, # type: ignore
Coerce,
Range,
Schema,
)
@@ -21,14 +21,14 @@ CURRENT_CONSUMPTION_SCHEMA = Schema(
Any(
{
"voltage": Any(All(float, Range(min=0, max=300)), None),
"power": Any(Coerce(float, Range(min=0)), None),
"total": Any(Coerce(float, Range(min=0)), None),
"current": Any(All(float, Range(min=0)), None),
"power": Any(Coerce(float), None),
"total": Any(Coerce(float), None),
"current": Any(All(float), None),
"voltage_mv": Any(All(float, Range(min=0, max=300000)), int, None),
"power_mw": Any(Coerce(float, Range(min=0)), None),
"total_wh": Any(Coerce(float, Range(min=0)), None),
"current_ma": Any(All(float, Range(min=0)), int, None),
"slot_id": Any(Coerce(int, Range(min=0)), None),
"power_mw": Any(Coerce(float), None),
"total_wh": Any(Coerce(float), None),
"current_ma": Any(All(float), int, None),
"slot_id": Any(Coerce(int), None),
},
None,
)

View File

@@ -38,7 +38,7 @@ from ..httpclient import HttpClient
),
(Exception(), KasaException, "Unable to query the device: "),
(
aiohttp.ServerFingerprintMismatch("exp", "got", "host", 1),
aiohttp.ServerFingerprintMismatch(b"exp", b"got", "host", 1),
KasaException,
"Unable to query the device: ",
),
@@ -84,7 +84,7 @@ async def test_httpclient_errors(mocker, error, error_raises, error_message, moc
client = HttpClient(DeviceConfig(host))
# Exceptions with parameters print with double quotes, without use single quotes
full_msg = (
"\(" # type: ignore
re.escape("(")
+ "['\"]"
+ re.escape(f"{error_message}{host}: {error}")
+ "['\"]"

View File

@@ -207,7 +207,7 @@ async def test_mac(dev):
@device_iot
async def test_representation(dev):
pattern = re.compile("<DeviceType\..+ at .+? - .*? \(.+?\)>")
pattern = re.compile(r"<DeviceType\..+ at .+? - .*? \(.+?\)>")
assert pattern.match(str(dev))