diff options
author | Jonathon Reinhart <jrreinhart@google.com> | 2023-03-15 19:57:19 +0000 |
---|---|---|
committer | CQ Bot Account <pigweed-scoped@luci-project-accounts.iam.gserviceaccount.com> | 2023-03-15 19:57:19 +0000 |
commit | 5b670fb60053a170375f76a46a088db6b827bdd1 (patch) | |
tree | 86a04362c3e5dee622dddba5e0910998cc1aa4cc | |
parent | c2df1e4942303b0e91f753f2e68b944b96fa9a93 (diff) | |
download | pigweed-5b670fb60053a170375f76a46a088db6b827bdd1.tar.gz |
python: Fix typing for pyserial
General changes:
- Remove 'type: ignore' from all 'import serial'
- Add pyserial and types-pyserial to install_requires in all packages
that use serial. The version constraint was copied from
pw_system/py/setup.cfg.
Module-specific changes/notes:
pw_tokenizer:
- Fix incorrect type of 'device' arg in _detokenize_serial(). This comes
from argparse without specifying a type, so it defaults to str.
- Change BinaryIO to _RawIO (BinaryIO | RawIOBase) for the input file
argument type. AFAICT there is no better or simpler way to reconcile
types.BinaryIO (sys.stdin.buffer, or the result of open()) with
io.RawIOBase (the base type of serial.Serial). See
https://stackoverflow.com/a/75726512/119527.
pw_console:
- Fix SerialWithLogging read() and write() method signatures to match
those of the serial.Serial base class. This involved taking a shortcut
in write() which only applied the logging if the argument is of the
'bytes' type (the most common case).
- Note that the ReadableBuffer union type is only available via the
_typeshed package, and is used as directed here:
https://github.com/python/typeshed/tree/main/stdlib/_typeshed
targets/stm32f429i_disc1:
- ListPortInfo.serial_number is Optional[str], so we annotate
BoardInfo.serial_number the same.
Downstream effects:
- A log message in this module is updated to handle the None case.
- All other downstream code already appears to handle None,
specifically, stm32f429i_disc1_utils.unit_test_runner.flash_device().
Note that this changed needs to be submitted as one commit due to the
fact that a single pigweed-venv is used, and once types-pyserial is
installed, mypy detects issues across all packages.
Change-Id: I81cb779c0f769e4f3ff79c0c1217192c1f698317
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/133970
Reviewed-by: Wyatt Hepler <hepler@google.com>
Commit-Queue: Jonathon Reinhart <jrreinhart@google.com>
-rwxr-xr-x | pw_arduino_build/py/pw_arduino_build/unit_test_runner.py | 4 | ||||
-rw-r--r-- | pw_arduino_build/py/setup.cfg | 1 | ||||
-rw-r--r-- | pw_console/py/pw_console/pyserial_wrapper.py | 21 | ||||
-rw-r--r-- | pw_console/py/setup.cfg | 3 | ||||
-rwxr-xr-x | pw_hdlc/rpc_example/example_script.py | 2 | ||||
-rw-r--r-- | pw_system/py/pw_system/console.py | 2 | ||||
-rw-r--r-- | pw_system/py/setup.cfg | 1 | ||||
-rwxr-xr-x | pw_tokenizer/py/pw_tokenizer/detokenize.py | 14 | ||||
-rw-r--r-- | pw_tokenizer/py/pw_tokenizer/serial_detokenizer.py | 4 | ||||
-rw-r--r-- | pw_tokenizer/py/setup.cfg | 3 | ||||
-rwxr-xr-x | pw_trace_tokenized/py/pw_trace_tokenized/get_trace.py | 2 | ||||
-rw-r--r-- | pw_trace_tokenized/py/setup.cfg | 2 | ||||
-rw-r--r-- | targets/stm32f429i_disc1/py/setup.cfg | 1 | ||||
-rw-r--r-- | targets/stm32f429i_disc1/py/stm32f429i_disc1_utils/stm32f429i_detector.py | 7 | ||||
-rwxr-xr-x | targets/stm32f429i_disc1/py/stm32f429i_disc1_utils/unit_test_runner.py | 2 |
15 files changed, 42 insertions, 27 deletions
diff --git a/pw_arduino_build/py/pw_arduino_build/unit_test_runner.py b/pw_arduino_build/py/pw_arduino_build/unit_test_runner.py index abc4359e7..05678f751 100755 --- a/pw_arduino_build/py/pw_arduino_build/unit_test_runner.py +++ b/pw_arduino_build/py/pw_arduino_build/unit_test_runner.py @@ -25,8 +25,8 @@ import time from pathlib import Path from typing import List -import serial # type: ignore -import serial.tools.list_ports # type: ignore +import serial +import serial.tools.list_ports import pw_arduino_build.log from pw_arduino_build import teensy_detector from pw_arduino_build.file_operations import decode_file_json diff --git a/pw_arduino_build/py/setup.cfg b/pw_arduino_build/py/setup.cfg index 05f6d2a00..f59cba7f4 100644 --- a/pw_arduino_build/py/setup.cfg +++ b/pw_arduino_build/py/setup.cfg @@ -23,6 +23,7 @@ packages = find: zip_safe = False install_requires = pyserial>=3.5,<4.0 + types-pyserial>=3.5,<4.0 coloredlogs parameterized diff --git a/pw_console/py/pw_console/pyserial_wrapper.py b/pw_console/py/pw_console/pyserial_wrapper.py index fd7467938..57c297a52 100644 --- a/pw_console/py/pw_console/pyserial_wrapper.py +++ b/pw_console/py/pw_console/pyserial_wrapper.py @@ -12,15 +12,20 @@ # License for the specific language governing permissions and limitations under # the License. """Wrapers for pyserial classes to log read and write data.""" +from __future__ import annotations from contextvars import ContextVar import logging import textwrap +from typing import TYPE_CHECKING -import serial # type: ignore +import serial from pw_console.widgets.event_count_history import EventCountHistory +if TYPE_CHECKING: + from _typeshed import ReadableBuffer + _LOG = logging.getLogger('pw_console.serial_debug_logger') @@ -87,8 +92,8 @@ class SerialWithLogging(serial.Serial): # pylint: disable=too-many-ancestors super().__init__(*args, **kwargs) self.pw_bps_history = BANDWIDTH_HISTORY_CONTEXTVAR.get() - def read(self, *args, **kwargs): - data = super().read(*args, **kwargs) + def read(self, size: int = 1) -> bytes: + data = super().read(size) self.pw_bps_history['read'].log(len(data)) self.pw_bps_history['total'].log(len(data)) @@ -126,11 +131,11 @@ class SerialWithLogging(serial.Serial): # pylint: disable=too-many-ancestors return data - def write(self, data: bytes, *args, **kwargs): - self.pw_bps_history['write'].log(len(data)) - self.pw_bps_history['total'].log(len(data)) + def write(self, data: ReadableBuffer) -> None: + if isinstance(data, bytes) and len(data) > 0: + self.pw_bps_history['write'].log(len(data)) + self.pw_bps_history['total'].log(len(data)) - if len(data) > 0: prefix = 'Write %2d B: ' % len(data) _LOG.debug( '%s%s', @@ -162,4 +167,4 @@ class SerialWithLogging(serial.Serial): # pylint: disable=too-many-ancestors ), ) - super().write(data, *args, **kwargs) + super().write(data) diff --git a/pw_console/py/setup.cfg b/pw_console/py/setup.cfg index 97b921a15..60021a431 100644 --- a/pw_console/py/setup.cfg +++ b/pw_console/py/setup.cfg @@ -28,9 +28,10 @@ install_requires = ptpython>=3.0.20 pygments pyperclip - pyserial + pyserial>=3.5,<4.0 pyyaml types-pygments + types-pyserial>=3.5,<4.0 types-pyyaml websockets diff --git a/pw_hdlc/rpc_example/example_script.py b/pw_hdlc/rpc_example/example_script.py index ec071e97f..36a3cf85d 100755 --- a/pw_hdlc/rpc_example/example_script.py +++ b/pw_hdlc/rpc_example/example_script.py @@ -18,7 +18,7 @@ import argparse import os from pathlib import Path -import serial # type: ignore +import serial from pw_hdlc.rpc import HdlcRpcClient, default_channels diff --git a/pw_system/py/pw_system/console.py b/pw_system/py/pw_system/console.py index 80fd2c3f3..49950884a 100644 --- a/pw_system/py/pw_system/console.py +++ b/pw_system/py/pw_system/console.py @@ -51,7 +51,7 @@ from typing import ( ) import socket -import serial # type: ignore +import serial import IPython # type: ignore from pw_cli import log as pw_cli_log diff --git a/pw_system/py/setup.cfg b/pw_system/py/setup.cfg index 9db8b71e6..fea637c72 100644 --- a/pw_system/py/setup.cfg +++ b/pw_system/py/setup.cfg @@ -23,6 +23,7 @@ packages = find: zip_safe = False install_requires = pyserial>=3.5,<4.0 + types-pyserial>=3.5,<4.0 [options.entry_points] console_scripts = pw-system-console = pw_system.console:main diff --git a/pw_tokenizer/py/pw_tokenizer/detokenize.py b/pw_tokenizer/py/pw_tokenizer/detokenize.py index 6169f4a7c..3aa7a3a8b 100755 --- a/pw_tokenizer/py/pw_tokenizer/detokenize.py +++ b/pw_tokenizer/py/pw_tokenizer/detokenize.py @@ -73,6 +73,8 @@ ENCODED_TOKEN = struct.Struct('<I') BASE64_PREFIX = encode.BASE64_PREFIX.encode() DEFAULT_RECURSION = 9 +_RawIO = Union[io.RawIOBase, BinaryIO] + class DetokenizedString: """A detokenized string, with all results if there are collisions.""" @@ -264,7 +266,7 @@ class Detokenizer: def detokenize_base64_live( self, - input_file: BinaryIO, + input_file: _RawIO, output: BinaryIO, prefix: Union[str, bytes] = BASE64_PREFIX, recursion: int = DEFAULT_RECURSION, @@ -428,16 +430,14 @@ class PrefixedMessageDecoder: self.data = bytearray() - def _read_next(self, fd: BinaryIO) -> Tuple[bytes, int]: + def _read_next(self, fd: _RawIO) -> Tuple[bytes, int]: """Returns the next character and its index.""" - char = fd.read(1) + char = fd.read(1) or b'' index = len(self.data) self.data += char return char, index - def read_messages( - self, binary_fd: BinaryIO - ) -> Iterator[Tuple[bool, bytes]]: + def read_messages(self, binary_fd: _RawIO) -> Iterator[Tuple[bool, bytes]]: """Parses prefixed messages; yields (is_message, contents) chunks.""" message_start = None @@ -464,7 +464,7 @@ class PrefixedMessageDecoder: yield False, char def transform( - self, binary_fd: BinaryIO, transform: Callable[[bytes], bytes] + self, binary_fd: _RawIO, transform: Callable[[bytes], bytes] ) -> Iterator[bytes]: """Yields the file with a transformation applied to the messages.""" for is_message, chunk in self.read_messages(binary_fd): diff --git a/pw_tokenizer/py/pw_tokenizer/serial_detokenizer.py b/pw_tokenizer/py/pw_tokenizer/serial_detokenizer.py index 793f95b26..ab673a55e 100644 --- a/pw_tokenizer/py/pw_tokenizer/serial_detokenizer.py +++ b/pw_tokenizer/py/pw_tokenizer/serial_detokenizer.py @@ -21,7 +21,7 @@ import argparse import sys from typing import BinaryIO, Iterable -import serial # type: ignore +import serial from pw_tokenizer import database, detokenize, tokens @@ -80,7 +80,7 @@ def _parse_args(): def _detokenize_serial( databases: Iterable, - device: serial.Serial, + device: str, baudrate: int, show_errors: bool, output: BinaryIO, diff --git a/pw_tokenizer/py/setup.cfg b/pw_tokenizer/py/setup.cfg index 99e075d61..f7a20b7a7 100644 --- a/pw_tokenizer/py/setup.cfg +++ b/pw_tokenizer/py/setup.cfg @@ -21,6 +21,9 @@ description = Tools for working with tokenized strings [options] packages = pw_tokenizer zip_safe = False +install_requires = + pyserial>=3.5,<4.0 + types-pyserial>=3.5,<4.0 [options.package_data] pw_tokenizer = py.typed diff --git a/pw_trace_tokenized/py/pw_trace_tokenized/get_trace.py b/pw_trace_tokenized/py/pw_trace_tokenized/get_trace.py index 38056f37b..041c6bcdf 100755 --- a/pw_trace_tokenized/py/pw_trace_tokenized/get_trace.py +++ b/pw_trace_tokenized/py/pw_trace_tokenized/get_trace.py @@ -33,7 +33,7 @@ import socket import sys from typing import Collection, Iterable, Iterator -import serial # type: ignore +import serial from pw_tokenizer import database from pw_trace import trace from pw_hdlc.rpc import HdlcRpcClient, default_channels diff --git a/pw_trace_tokenized/py/setup.cfg b/pw_trace_tokenized/py/setup.cfg index 6c643bb4a..98038d397 100644 --- a/pw_trace_tokenized/py/setup.cfg +++ b/pw_trace_tokenized/py/setup.cfg @@ -22,6 +22,8 @@ description = pw_trace backend to tokenize trace events packages = find: zip_safe = False install_requires = + pyserial>=3.5,<4.0 + types-pyserial>=3.5,<4.0 [options.package_data] pw_trace_tokenized = py.typed diff --git a/targets/stm32f429i_disc1/py/setup.cfg b/targets/stm32f429i_disc1/py/setup.cfg index 26ec850a4..a3f377296 100644 --- a/targets/stm32f429i_disc1/py/setup.cfg +++ b/targets/stm32f429i_disc1/py/setup.cfg @@ -23,6 +23,7 @@ packages = find: zip_safe = False install_requires = pyserial>=3.5,<4.0 + types-pyserial>=3.5,<4.0 coloredlogs [options.entry_points] diff --git a/targets/stm32f429i_disc1/py/stm32f429i_disc1_utils/stm32f429i_detector.py b/targets/stm32f429i_disc1/py/stm32f429i_disc1_utils/stm32f429i_detector.py index 857408287..bc09d282b 100644 --- a/targets/stm32f429i_disc1/py/stm32f429i_disc1_utils/stm32f429i_detector.py +++ b/targets/stm32f429i_disc1/py/stm32f429i_disc1_utils/stm32f429i_detector.py @@ -16,9 +16,10 @@ import logging import typing +from typing import Optional import coloredlogs # type: ignore -import serial.tools.list_ports # type: ignore +import serial.tools.list_ports # Vendor/device ID to search for in USB devices. _ST_VENDOR_ID = 0x0483 @@ -31,7 +32,7 @@ class BoardInfo(typing.NamedTuple): """Information about a connected dev board.""" dev_name: str - serial_number: str + serial_number: Optional[str] def detect_boards() -> list: @@ -67,7 +68,7 @@ def main(): for idx, board in enumerate(boards): _LOG.info('Board %d:', idx) _LOG.info(' - Port: %s', board.dev_name) - _LOG.info(' - Serial #: %s', board.serial_number) + _LOG.info(' - Serial #: %s', board.serial_number or '<not set>') if __name__ == '__main__': diff --git a/targets/stm32f429i_disc1/py/stm32f429i_disc1_utils/unit_test_runner.py b/targets/stm32f429i_disc1/py/stm32f429i_disc1_utils/unit_test_runner.py index d79e47038..b17d62790 100755 --- a/targets/stm32f429i_disc1/py/stm32f429i_disc1_utils/unit_test_runner.py +++ b/targets/stm32f429i_disc1/py/stm32f429i_disc1_utils/unit_test_runner.py @@ -23,7 +23,7 @@ import threading from typing import List import coloredlogs # type: ignore -import serial # type: ignore +import serial from stm32f429i_disc1_utils import stm32f429i_detector # Path used to access non-python resources in this python module. |