From 644ab9d28cf403d3796724e1b5a7e582e52073ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicki=20K=C5=99=C3=AD=C5=BEek?= Date: Mon, 16 Jun 2025 15:35:43 +0200 Subject: [PATCH] Abstract WatchLog line buffering to a separate function Move the line buffering functionality into _readline() to improve the readability of code. This also allows reading the file contents from other functions, since the line buffer is now an attribute of the class. (cherry picked from commit 67896ddde2cc9058fc965eb50b263ca7909d24d7) --- bin/tests/system/isctest/log/watchlog.py | 51 +++++++++++++++++------- 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/bin/tests/system/isctest/log/watchlog.py b/bin/tests/system/isctest/log/watchlog.py index 3d35df09e9..0ac18477ac 100644 --- a/bin/tests/system/isctest/log/watchlog.py +++ b/bin/tests/system/isctest/log/watchlog.py @@ -100,6 +100,36 @@ class WatchLog(abc.ABC): self._fd = None # type: Optional[TextIO] self._path = path self._wait_function_called = False + self._linebuf = "" + + def _readline(self) -> Optional[str]: + """ + Wrapper around io.readline() function to handle unfinished lines. + + If a line ends with newline character, it's returned immediately. + If a line doesn't end with a newline character, the read contents are + buffered until the next call of this function and None is returned + instead. + """ + if not self._fd: + raise WatchLogException("file to watch isn't open") + read = self._fd.readline() + if not read.endswith("\n"): + self._linebuf += read + return None + read = self._linebuf + read + self._linebuf = "" + return read + + def _readlines(self) -> Iterator[str]: + """ + Wrapper around io.readline() which only returns finished lines. + """ + while True: + line = self._readline() + if line is None: + return + yield line def wait_for_line(self, string: str, timeout: int = 10) -> None: """ @@ -231,24 +261,15 @@ class WatchLog(abc.ABC): if self._wait_function_called: raise WatchLogException("wait_for_*() was already called") self._wait_function_called = True - if not self._fd: - raise WatchLogException("No file to watch") - leftover = "" assert timeout, "Do not use this class unless you want to WAIT for something." deadline = time.monotonic() + timeout while time.monotonic() < deadline: - for line in self._fd.readlines(): - if line[-1] != "\n": - # Line is not completely written yet, buffer and keep on waiting - leftover += line - else: - line = leftover + line - leftover = "" - for string, retval in patterns.items(): - if isinstance(string, Pattern) and string.search(line): - return retval - if isinstance(string, str) and string in line: - return retval + for line in self._readlines(): + for string, retval in patterns.items(): + if isinstance(string, Pattern) and string.search(line): + return retval + if isinstance(string, str) and string in line: + return retval time.sleep(0.1) raise TimeoutError( "Timeout reached watching {} for {}".format(