GeezerVison is showing github.com — Configure mypy to run in venv and fix resulting issues · python-kasa/python-kasa@a6fcd08
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: .github/workflows/ci.yml +1Lines changed: 1 addition & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 27 | 27 | python-version: ${{ matrix.python-version }} | 28 | 28 | cache-pre-commit: true | 29 | 29 | poetry-version: ${{ env.POETRY_VERSION }} | | 30 | + poetry-install-options: "--all-extras" | 30 | 31 | - name: "Check supported device md files are up to date" | 31 | 32 | run: | | 32 | 33 | poetry run pre-commit run generate-supported --all-files | |
Collapse file Copy file name to clipboardExpand all lines: .pre-commit-config.yaml +12-11Lines changed: 12 additions & 11 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -16,17 +16,6 @@ repos: | 16 | 16 | args: [--fix, --exit-non-zero-on-fix] | 17 | 17 | - id: ruff-format | 18 | 18 |
| 19 | | -- repo: https://github.com/pre-commit/mirrors-mypy | 20 | | - rev: v1.9.0 | 21 | | - hooks: | 22 | | - - id: mypy | 23 | | - additional_dependencies: [types-click] | 24 | | - exclude: | | 25 | | - (?x)^( | 26 | | - kasa/modulemapping\.py| | 27 | | - )$ | 28 | | -
| 29 | | -
| 30 | 19 | - repo: https://github.com/PyCQA/doc8 | 31 | 20 | rev: 'v1.1.1' | 32 | 21 | hooks: | @@ -35,6 +24,18 @@ repos: | 35 | 24 |
| 36 | 25 | - repo: local | 37 | 26 | hooks: | | 27 | + # Run mypy in the virtual environment so it uses the installed dependencies | | 28 | + # for more accurate checking than using the pre-commit mypy mirror | | 29 | + - id: mypy | | 30 | + name: mypy | | 31 | + entry: devtools/run-in-env.sh mypy | | 32 | + language: script | | 33 | + types_or: [python, pyi] | | 34 | + require_serial: true | | 35 | + exclude: | # exclude required because --all-files passes py and pyi | | 36 | + (?x)^( | | 37 | + kasa/modulemapping\.py| | | 38 | + )$ | 38 | 39 | - id: generate-supported | 39 | 40 | name: Generate supported devices | 40 | 41 | description: This hook generates the supported device sections of README.md and SUPPORTED.md | |
Collapse file Copy file name to clipboardExpand all lines: devtools/bench/benchmark.py +3-2Lines changed: 3 additions & 2 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 5 | 5 |
| 6 | 6 | import orjson | 7 | 7 | from kasa_crypt import decrypt, encrypt | 8 | | -from utils.data import REQUEST, WIRE_RESPONSE | 9 | | -from utils.original import OriginalTPLinkSmartHomeProtocol | | 8 | + | | 9 | +from .utils.data import REQUEST, WIRE_RESPONSE | | 10 | +from .utils.original import OriginalTPLinkSmartHomeProtocol | 10 | 11 |
| 11 | 12 |
| 12 | 13 | def original_request_response() -> None: | |
Collapse file Copy file name to clipboard +3Lines changed: 3 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 1 | +#!/bin/bash | | 2 | +source $(poetry env info --path)/bin/activate | | 3 | +exec "$@" |
Collapse file Copy file name to clipboardExpand all lines: kasa/aestransport.py +4-1Lines changed: 4 additions & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -371,7 +371,10 @@ def create_from_keypair(handshake_key: str, keypair): | 371 | 371 | handshake_key_bytes: bytes = base64.b64decode(handshake_key.encode("UTF-8")) | 372 | 372 | private_key_data = base64.b64decode(keypair.get_private_key().encode("UTF-8")) | 373 | 373 |
| 374 | | - private_key = serialization.load_der_private_key(private_key_data, None, None) | | 374 | + private_key = cast( | | 375 | + rsa.RSAPrivateKey, | | 376 | + serialization.load_der_private_key(private_key_data, None, None), | | 377 | + ) | 375 | 378 | key_and_iv = private_key.decrypt( | 376 | 379 | handshake_key_bytes, asymmetric_padding.PKCS1v15() | 377 | 380 | ) | |
Collapse file Copy file name to clipboardExpand all lines: kasa/cli.py +6-8Lines changed: 6 additions & 8 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -101,9 +101,7 @@ def error(msg: str): | 101 | 101 | # Block list of commands which require no update | 102 | 102 | SKIP_UPDATE_COMMANDS = ["raw-command", "command"] | 103 | 103 |
| 104 | | -click.anyio_backend = "asyncio" | 105 | | - | 106 | | -pass_dev = click.make_pass_decorator(Device) | | 104 | +pass_dev = click.make_pass_decorator(Device) # type: ignore[type-abstract] | 107 | 105 |
| 108 | 106 |
| 109 | 107 | def CatchAllExceptions(cls): | @@ -996,7 +994,7 @@ async def time_get(dev: Device): | 996 | 994 |
| 997 | 995 | @time.command(name="sync") | 998 | 996 | @pass_dev | 999 | | -async def time_sync(dev: SmartDevice): | | 997 | +async def time_sync(dev: Device): | 1000 | 998 | """Set the device time to current time.""" | 1001 | 999 | if not isinstance(dev, SmartDevice): | 1002 | 1000 | raise NotImplementedError("setting time currently only implemented on smart") | @@ -1134,7 +1132,7 @@ async def presets(ctx): | 1134 | 1132 |
| 1135 | 1133 | @presets.command(name="list") | 1136 | 1134 | @pass_dev | 1137 | | -def presets_list(dev: IotBulb): | | 1135 | +def presets_list(dev: Device): | 1138 | 1136 | """List presets.""" | 1139 | 1137 | if not dev.is_bulb or not isinstance(dev, IotBulb): | 1140 | 1138 | error("Presets only supported on iot bulbs") | @@ -1153,7 +1151,7 @@ def presets_list(dev: IotBulb): | 1153 | 1151 | @click.option("--saturation", type=int) | 1154 | 1152 | @click.option("--temperature", type=int) | 1155 | 1153 | @pass_dev | 1156 | | -async def presets_modify(dev: IotBulb, index, brightness, hue, saturation, temperature): | | 1154 | +async def presets_modify(dev: Device, index, brightness, hue, saturation, temperature): | 1157 | 1155 | """Modify a preset.""" | 1158 | 1156 | for preset in dev.presets: | 1159 | 1157 | if preset.index == index: | @@ -1181,7 +1179,7 @@ async def presets_modify(dev: IotBulb, index, brightness, hue, saturation, tempe | 1181 | 1179 | @click.option("--type", type=click.Choice(["soft", "hard"], case_sensitive=False)) | 1182 | 1180 | @click.option("--last", is_flag=True) | 1183 | 1181 | @click.option("--preset", type=int) | 1184 | | -async def turn_on_behavior(dev: IotBulb, type, last, preset): | | 1182 | +async def turn_on_behavior(dev: Device, type, last, preset): | 1185 | 1183 | """Modify bulb turn-on behavior.""" | 1186 | 1184 | if not dev.is_bulb or not isinstance(dev, IotBulb): | 1187 | 1185 | error("Presets only supported on iot bulbs") | @@ -1239,7 +1237,7 @@ async def shell(dev: Device): | 1239 | 1237 | logging.getLogger("asyncio").setLevel(logging.WARNING) | 1240 | 1238 | loop = asyncio.get_event_loop() | 1241 | 1239 | try: | 1242 | | - await embed( | | 1240 | + await embed( # type: ignore[func-returns-value] | 1243 | 1241 | globals=globals(), | 1244 | 1242 | locals=locals(), | 1245 | 1243 | return_asyncio_coroutine=True, | |
Collapse file Copy file name to clipboardExpand all lines: kasa/httpclient.py +1-1Lines changed: 1 addition & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -36,7 +36,7 @@ class HttpClient: | 36 | 36 |
| 37 | 37 | def __init__(self, config: DeviceConfig) -> None: | 38 | 38 | self._config = config | 39 | | - self._client_session: aiohttp.ClientSession = None | | 39 | + self._client_session: aiohttp.ClientSession | None = None | 40 | 40 | self._jar = aiohttp.CookieJar(unsafe=True, quote_cookie=False) | 41 | 41 | self._last_url = URL(f"http://{self._config.host}/") | 42 | 42 |
| |
Collapse file Copy file name to clipboardExpand all lines: kasa/tests/discovery_fixtures.py +3-1Lines changed: 3 additions & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -231,7 +231,9 @@ def discovery_data(request, mocker): | 231 | 231 | return {"system": {"get_sysinfo": fixture_data["system"]["get_sysinfo"]}} | 232 | 232 |
| 233 | 233 |
| 234 | | -@pytest.fixture(params=UNSUPPORTED_DEVICES.values(), ids=UNSUPPORTED_DEVICES.keys()) | | 234 | +@pytest.fixture( | | 235 | + params=UNSUPPORTED_DEVICES.values(), ids=list(UNSUPPORTED_DEVICES.keys()) | | 236 | +) | 235 | 237 | def unsupported_device_info(request, mocker): | 236 | 238 | """Return unsupported devices for cli and discovery tests.""" | 237 | 239 | discovery_data = request.param | |
Collapse file Copy file name to clipboardExpand all lines: kasa/tests/fakeprotocol_smart.py +2-2Lines changed: 2 additions & 2 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -276,7 +276,7 @@ def _send_request(self, request_dict: dict): | 276 | 276 | ): | 277 | 277 | result["sum"] = len(result[list_key]) | 278 | 278 | if self.warn_fixture_missing_methods: | 279 | | - pytest.fixtures_missing_methods.setdefault( | | 279 | + pytest.fixtures_missing_methods.setdefault( # type: ignore[attr-defined] | 280 | 280 | self.fixture_name, set() | 281 | 281 | ).add(f"{method} (incomplete '{list_key}' list)") | 282 | 282 |
| @@ -305,7 +305,7 @@ def _send_request(self, request_dict: dict): | 305 | 305 | } | 306 | 306 | # Reduce warning spam by consolidating and reporting at the end of the run | 307 | 307 | if self.warn_fixture_missing_methods: | 308 | | - pytest.fixtures_missing_methods.setdefault( | | 308 | + pytest.fixtures_missing_methods.setdefault( # type: ignore[attr-defined] | 309 | 309 | self.fixture_name, set() | 310 | 310 | ).add(method) | 311 | 311 | return retval | |
Collapse file Copy file name to clipboardExpand all lines: kasa/tests/smart/modules/test_firmware.py +12-1Lines changed: 12 additions & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
| 2 | 2 |
| 3 | 3 | import asyncio | 4 | 4 | import logging | | 5 | +from typing import TypedDict | 5 | 6 |
| 6 | 7 | import pytest | 7 | 8 | from pytest_mock import MockerFixture | @@ -71,7 +72,17 @@ async def test_firmware_update( | 71 | 72 | assert fw | 72 | 73 |
| 73 | 74 | upgrade_time = 5 | 74 | | - extras = {"reboot_time": 5, "upgrade_time": upgrade_time, "auto_upgrade": False} | | 75 | + | | 76 | + class Extras(TypedDict): | | 77 | + reboot_time: int | | 78 | + upgrade_time: int | | 79 | + auto_upgrade: bool | | 80 | + | | 81 | + extras: Extras = { | | 82 | + "reboot_time": 5, | | 83 | + "upgrade_time": upgrade_time, | | 84 | + "auto_upgrade": False, | | 85 | + } | 75 | 86 | update_states = [ | 76 | 87 | # Unknown 1 | 77 | 88 | DownloadState(status=1, download_progress=0, **extras), | |
|