Fix mypy issues

This commit is contained in:
Odd Stråbø 2023-12-09 16:35:45 +01:00
parent 8282ec3956
commit 457e7cf8a3
10 changed files with 56 additions and 50 deletions

View file

@ -5,7 +5,7 @@ repos:
rev: v4.4.0 rev: v4.4.0
hooks: hooks:
- id: trailing-whitespace - id: trailing-whitespace
- id: end-of-file-fixer #- id: end-of-file-fixer
- id: fix-byte-order-marker - id: fix-byte-order-marker
- id: fix-encoding-pragma - id: fix-encoding-pragma
- id: check-executables-have-shebangs - id: check-executables-have-shebangs
@ -41,6 +41,9 @@ repos:
args: args:
- "--install-types" - "--install-types"
- "--non-interactive" - "--non-interactive"
- "--check-untyped-defs"
additional_dependencies:
- typing_extensions==4.8.0
- repo: https://github.com/psf/black - repo: https://github.com/psf/black
rev: 23.3.0 rev: 23.3.0

View file

@ -4,5 +4,11 @@
"--disable=missing-function-docstring,missing-class-docstring,missing-module-docstring" "--disable=missing-function-docstring,missing-class-docstring,missing-module-docstring"
], ],
"python.testing.unittestEnabled": false, "python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true "python.testing.pytestEnabled": true,
"mypy-type-checker.importStrategy": "fromEnvironment",
"mypy-type-checker.reportingScope": "workspace",
"mypy-type-checker.preferDaemon": true,
"mypy-type-checker.args": [
"--check-untyped-defs"
]
} }

View file

@ -1,7 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import os import os
import sys import sys
from io import RawIOBase
from typing import List from typing import List
sys.path.insert(1, os.path.dirname(os.path.dirname(sys.argv[0]))) sys.path.insert(1, os.path.dirname(os.path.dirname(sys.argv[0])))
@ -9,10 +8,11 @@ sys.path.insert(1, os.path.dirname(os.path.dirname(sys.argv[0])))
from draw_memory_map import memory_table # noqa: E402 from draw_memory_map import memory_table # noqa: E402
from srnemqtt.config import get_config, get_interface # noqa: E402 from srnemqtt.config import get_config, get_interface # noqa: E402
from srnemqtt.interfaces import BaseInterface # noqa: E402
from srnemqtt.protocol import readMemory # noqa: E402 from srnemqtt.protocol import readMemory # noqa: E402
def get_device_name(iface: RawIOBase) -> str | None: def get_device_name(iface: BaseInterface) -> str | None:
data = readMemory(iface, 0x0C, 8) data = readMemory(iface, 0x0C, 8)
if data is None: if data is None:
return None return None
@ -20,7 +20,7 @@ def get_device_name(iface: RawIOBase) -> str | None:
return data.decode("utf-8").strip() return data.decode("utf-8").strip()
def get_device_version(iface: RawIOBase) -> str | None: def get_device_version(iface: BaseInterface) -> str | None:
data = readMemory(iface, 0x14, 4) data = readMemory(iface, 0x14, 4)
if data is None: if data is None:
return None return None
@ -32,7 +32,7 @@ def get_device_version(iface: RawIOBase) -> str | None:
return f"{major}.{minor}.{patch}" return f"{major}.{minor}.{patch}"
def get_device_serial(iface: RawIOBase) -> str | None: def get_device_serial(iface: BaseInterface) -> str | None:
data = readMemory(iface, 0x18, 3) data = readMemory(iface, 0x18, 3)
if data is None: if data is None:
return None return None

View file

@ -11,7 +11,8 @@ sys.path.insert(1, os.path.dirname(os.path.dirname(sys.argv[0])))
# from srnemqtt.lib.feasycom_ble import BTLEUart # from srnemqtt.lib.feasycom_ble import BTLEUart
from srnemqtt.protocol import construct_request, write # noqa: E402 from srnemqtt.protocol import construct_request, write # noqa: E402
for rate in [1200, 2400, 4800, 9600, 115200]: # for rate in [1200, 2400, 4800, 9600, 115200]:
for rate in [9600]:
print(rate) print(rate)
with Serial("/dev/ttyUSB0", baudrate=rate, timeout=2) as x: with Serial("/dev/ttyUSB0", baudrate=rate, timeout=2) as x:
sleep(2) sleep(2)

View file

@ -6,9 +6,8 @@ from typing import Any, Dict, List, Optional, Type
import yaml import yaml
from srnemqtt.interfaces import BaseInterface
from .consumers import BaseConsumer from .consumers import BaseConsumer
from .interfaces import BaseInterface
def get_consumer(name: str) -> Optional[Type[BaseConsumer]]: def get_consumer(name: str) -> Optional[Type[BaseConsumer]]:

View file

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import json import json
from time import sleep from time import sleep
from typing import Any, Dict, List, Optional from typing import Any, Dict, List, Optional, TypeAlias
from uuid import uuid4 from uuid import uuid4
import paho.mqtt.client as mqtt import paho.mqtt.client as mqtt
@ -112,6 +112,9 @@ MAP_VALUES: Dict[DataName, Dict[str, Any]] = {
} }
PayloadType: TypeAlias = str | bytes | bytearray | int | float | None
class MqttConsumer(BaseConsumer): class MqttConsumer(BaseConsumer):
client: mqtt.Client client: mqtt.Client
initialized: List[str] initialized: List[str]
@ -170,8 +173,8 @@ class MqttConsumer(BaseConsumer):
def get_ha_config( def get_ha_config(
self, self,
id, id: str,
name, name: str,
unit: Optional[str] = None, unit: Optional[str] = None,
type: Optional[str] = None, type: Optional[str] = None,
expiry: int = 90, expiry: int = 90,
@ -247,7 +250,7 @@ class MqttConsumer(BaseConsumer):
return super().poll() return super().poll()
def write(self, data: Dict[str, Any]): def write(self, data: Dict[str, PayloadType]):
self.client.publish(f"{self.topic_prefix}/raw", payload=json.dumps(data)) self.client.publish(f"{self.topic_prefix}/raw", payload=json.dumps(data))
for k, v in data.items(): for k, v in data.items():
@ -257,6 +260,7 @@ class MqttConsumer(BaseConsumer):
pretty_name = k.replace("_", " ").capitalize() pretty_name = k.replace("_", " ").capitalize()
disc_prefix = self.settings["discovery_prefix"] disc_prefix = self.settings["discovery_prefix"]
device_id = self.settings["device_id"] device_id = self.settings["device_id"]
self.client.publish( self.client.publish(
f"{disc_prefix}/sensor/{device_id}_{k}/config", f"{disc_prefix}/sensor/{device_id}_{k}/config",
payload=json.dumps(self.get_ha_config(k, pretty_name, **km)), payload=json.dumps(self.get_ha_config(k, pretty_name, **km)),

View file

@ -4,4 +4,4 @@ from io import RawIOBase
class BaseInterface(RawIOBase, metaclass=ABCMeta): class BaseInterface(RawIOBase, metaclass=ABCMeta):
pass timeout: float | None

View file

@ -6,10 +6,6 @@ from typing import TYPE_CHECKING, Optional, cast
from bluepy import btle # type: ignore from bluepy import btle # type: ignore
if TYPE_CHECKING:
from _typeshed import ReadableBuffer, WriteableBuffer
WRITE_DEVICE = "0000ffd1-0000-1000-8000-00805f9b34fb" WRITE_DEVICE = "0000ffd1-0000-1000-8000-00805f9b34fb"
READ_DEVICE = "0000fff1-0000-1000-8000-00805f9b34fb" READ_DEVICE = "0000fff1-0000-1000-8000-00805f9b34fb"
@ -18,7 +14,7 @@ class BTLEUart(io.RawIOBase):
mac: str mac: str
write_endpoint: str write_endpoint: str
read_endpoint: str read_endpoint: str
timeout: float timeout: float | None
device: Optional[btle.Peripheral] = None device: Optional[btle.Peripheral] = None
_write_handle: Optional[btle.Characteristic] = None _write_handle: Optional[btle.Characteristic] = None
@ -86,13 +82,12 @@ class BTLEUart(io.RawIOBase):
self._write_handle = self.device.getCharacteristics(uuid=self.write_endpoint)[0] self._write_handle = self.device.getCharacteristics(uuid=self.write_endpoint)[0]
# print("Handles:", self._read_handle.handle, self._write_handle.handle) # print("Handles:", self._read_handle.handle, self._write_handle.handle)
def _read(self, num: Optional[int] = None, timeout: Optional[float] = None): def _read(self, num: Optional[int] = None):
self._ensure_connected() self._ensure_connected()
if TYPE_CHECKING: if TYPE_CHECKING:
self.device = cast(btle.Peripheral, self.device) self.device = cast(btle.Peripheral, self.device)
if timeout is None: timeout = self.timeout or 30
timeout = self.timeout
if num is None: if num is None:
start = time.time() start = time.time()
@ -132,7 +127,9 @@ class BTLEUart(io.RawIOBase):
del self._read_buffer[:num] del self._read_buffer[:num]
return data or None return data or None
def readinto(self, buffer: "WriteableBuffer") -> Optional[int]: def readinto(self, buffer: bytearray | memoryview) -> Optional[int]: # type: ignore [override]
# Buffer does not provide Sized, and bytes is read only.
# bytearray | memoryview is the default implementations that provide WriteableBuffer
data = self._read(len(buffer)) data = self._read(len(buffer))
if data is None: if data is None:
@ -144,23 +141,15 @@ class BTLEUart(io.RawIOBase):
def readall(self) -> bytes: def readall(self) -> bytes:
return self._read() return self._read()
def read( def read(self, size: Optional[int] = None) -> Optional[bytes]:
self, size: Optional[int] = None, timeout: Optional[float] = None
) -> Optional[bytes]:
if timeout:
_timeout = self.timeout
self.timeout = timeout
if size is None: if size is None:
res = super().read() res = super().read()
else: else:
res = super().read(size) res = super().read(size)
if timeout:
self.timeout = _timeout
return res return res
def write(self, b: "ReadableBuffer") -> Optional[int]: def write(self, b: bytes | bytearray | memoryview) -> Optional[int]: # type: ignore [override]
self._ensure_connected() self._ensure_connected()
if TYPE_CHECKING: if TYPE_CHECKING:
self.device = cast(btle.Peripheral, self.device) self.device = cast(btle.Peripheral, self.device)
@ -174,8 +163,9 @@ class BTLEUart(io.RawIOBase):
return self return self
def __exit__(self, type, value, traceback): def __exit__(self, type, value, traceback):
if self.device is not None:
self.device.disconnect() self.device.disconnect()
del self.device self.device = None
def seekable(self) -> bool: def seekable(self) -> bool:
return False return False

View file

@ -2,13 +2,12 @@
import struct import struct
import sys import sys
import time import time
from io import RawIOBase
from typing import Callable, Collection, Optional from typing import Callable, Collection, Optional
from libscrc import modbus # type: ignore from libscrc import modbus # type: ignore
from .constants import ACTION_READ, POSSIBLE_MARKER from .constants import ACTION_READ, POSSIBLE_MARKER
from .lib.feasycom_ble import BTLEUart from .interfaces import BaseInterface
from .solar_types import DATA_BATTERY_STATE, HISTORICAL_DATA, DataItem from .solar_types import DATA_BATTERY_STATE, HISTORICAL_DATA, DataItem
from .util import log from .util import log
@ -61,23 +60,23 @@ def parse_packet(data):
if crc != calculated_crc: if crc != calculated_crc:
e = ValueError(f"CRC missmatch: expected {crc:04X}, got {calculated_crc:04X}.") e = ValueError(f"CRC missmatch: expected {crc:04X}, got {calculated_crc:04X}.")
e.tag = tag # e.tag = tag
e.operation = operation # e.operation = operation
e.size = size # e.size = size
e.payload = payload # e.payload = payload
e.crc = crc # e.crc = crc
e.calculated_crc = calculated_crc # e.calculated_crc = calculated_crc
raise e raise e
return payload return payload
def discardUntil(fh: RawIOBase, byte: int, timeout=10) -> Optional[int]: def discardUntil(fh: BaseInterface, byte: int, timeout=10) -> Optional[int]:
assert byte >= 0 and byte < 256, f"byte: Expected 8bit unsigned int, got {byte}" assert byte >= 0 and byte < 256, f"byte: Expected 8bit unsigned int, got {byte}"
def expand(b: Optional[bytes]): def expand(b: Optional[bytes]):
if b is None: if not b:
return b return None
return b[0] return b[0]
start = time.time() start = time.time()
@ -88,6 +87,7 @@ def discardUntil(fh: RawIOBase, byte: int, timeout=10) -> Optional[int]:
if not discarded: if not discarded:
log("Discarding", end="") log("Discarding", end="")
discarded += 1 discarded += 1
print(read_byte)
print(f" {read_byte:02X}", end="") print(f" {read_byte:02X}", end="")
sys.stdout.flush() sys.stdout.flush()
@ -104,7 +104,7 @@ def discardUntil(fh: RawIOBase, byte: int, timeout=10) -> Optional[int]:
return read_byte return read_byte
def readMemory(fh: RawIOBase, address: int, words: int = 1) -> Optional[bytes]: def readMemory(fh: BaseInterface, address: int, words: int = 1) -> Optional[bytes]:
# log(f"Reading {words} words from 0x{address:04X}") # log(f"Reading {words} words from 0x{address:04X}")
request = construct_request(address, words=words) request = construct_request(address, words=words)
# log("Request:", request) # log("Request:", request)
@ -135,7 +135,7 @@ def readMemory(fh: RawIOBase, address: int, words: int = 1) -> Optional[bytes]:
def try_read_parse( def try_read_parse(
dev: BTLEUart, dev: BaseInterface,
address: int, address: int,
words: int = 1, words: int = 1,
parser: Optional[Callable] = None, parser: Optional[Callable] = None,
@ -151,7 +151,10 @@ def try_read_parse(
except struct.error as e: except struct.error as e:
log(e) log(e)
log("0x0100 Unpack error:", len(res), res) log("0x0100 Unpack error:", len(res), res)
log("Flushed from read buffer; ", dev.read(timeout=0.5)) _timeout = dev.timeout
dev.timeout = 0.5
log("Flushed from read buffer; ", dev.read())
dev.timeout = _timeout
else: else:
log(f"No data read, expected {words*2} bytes (attempts left: {attempts})") log(f"No data read, expected {words*2} bytes (attempts left: {attempts})")
return None return None

View file

@ -1,5 +1,5 @@
[flake8] [flake8]
max-line-length = 88 max-line-length = 120
extend-ignore = E203, I201, I101 extend-ignore = E203, I201, I101
[pytest] [pytest]