Clean up overly complicated typing in read_file_lines

The `read_file_lines` context manager supported either text or binary
streams, based on a parameter passed to the constructor. But the type
annotation on the iterator claimed that all lines were text. The version of
mypy that we use on the CI was happy with that, but modern versions are not.

The advantage of `read_file_lines` over built-in functions is better
tracking of line numbers. We never took advantage of this in our code with
binary streams. Change the one place where `read_file_lines` was used with a
binary stream to use built-in functions instead, and specialize
`read_file_lines` to text streams.

This fixes a legitimate complaint of modern mypy on `macro_collectory.py`.

There was no runtime bug: the behavior was correct, only the type
annotations were wrong.

Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
This commit is contained in:
Gilles Peskine
2026-03-31 13:15:44 +02:00
parent a0e5850d61
commit 7f537471bd
+6 -7
View File
@@ -37,14 +37,13 @@ class read_file_lines:
except that if process(line) raises an exception, then the read_file_lines
snippet annotates the exception with the file name and line number.
"""
def __init__(self, filename: str, binary: bool = False) -> None:
def __init__(self, filename: str) -> None:
self.filename = filename
self.file = None #type: Optional[IO[str]]
self.line_number = 'entry' #type: Union[int, str]
self.generator = None #type: Optional[Iterable[Tuple[int, str]]]
self.binary = binary
def __enter__(self) -> 'read_file_lines':
self.file = open(self.filename, 'rb' if self.binary else 'r')
self.file = open(self.filename)
self.generator = enumerate(self.file)
return self
def __iter__(self) -> Iterator[str]:
@@ -517,10 +516,10 @@ enumerate
_nonascii_re = re.compile(rb'[^\x00-\x7f]+') #type: Pattern
def parse_header(self, filename: str) -> None:
"""Parse a C header file, looking for "#define PSA_xxx"."""
with read_file_lines(filename, binary=True) as lines:
for line in lines:
line = re.sub(self._nonascii_re, rb'', line).decode('ascii')
self.parse_header_line(line)
with open(filename, 'rb') as input_:
for line in input_:
line = re.sub(self._nonascii_re, rb'', line)
self.parse_header_line(line.decode('ascii'))
_macro_identifier_re = re.compile(r'[A-Z]\w+')
def generate_undeclared_names(self, expr: str) -> Iterable[str]: