aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathon Reinhart <jrreinhart@google.com>2023-03-15 19:57:19 +0000
committerCQ Bot Account <pigweed-scoped@luci-project-accounts.iam.gserviceaccount.com>2023-03-15 19:57:19 +0000
commit5b670fb60053a170375f76a46a088db6b827bdd1 (patch)
tree86a04362c3e5dee622dddba5e0910998cc1aa4cc
parentc2df1e4942303b0e91f753f2e68b944b96fa9a93 (diff)
downloadpigweed-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-xpw_arduino_build/py/pw_arduino_build/unit_test_runner.py4
-rw-r--r--pw_arduino_build/py/setup.cfg1
-rw-r--r--pw_console/py/pw_console/pyserial_wrapper.py21
-rw-r--r--pw_console/py/setup.cfg3
-rwxr-xr-xpw_hdlc/rpc_example/example_script.py2
-rw-r--r--pw_system/py/pw_system/console.py2
-rw-r--r--pw_system/py/setup.cfg1
-rwxr-xr-xpw_tokenizer/py/pw_tokenizer/detokenize.py14
-rw-r--r--pw_tokenizer/py/pw_tokenizer/serial_detokenizer.py4
-rw-r--r--pw_tokenizer/py/setup.cfg3
-rwxr-xr-xpw_trace_tokenized/py/pw_trace_tokenized/get_trace.py2
-rw-r--r--pw_trace_tokenized/py/setup.cfg2
-rw-r--r--targets/stm32f429i_disc1/py/setup.cfg1
-rw-r--r--targets/stm32f429i_disc1/py/stm32f429i_disc1_utils/stm32f429i_detector.py7
-rwxr-xr-xtargets/stm32f429i_disc1/py/stm32f429i_disc1_utils/unit_test_runner.py2
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.