From a7eff0af144b081a59cddf8e1c612a562e3868d5 Mon Sep 17 00:00:00 2001 From: Ruben Vandamme Date: Mon, 6 May 2024 17:29:41 +0000 Subject: [PATCH] Improve read_byte retry mechanism #8 --- comfospot40/parser.py | 10 ++++++-- tests/parser_test.py | 55 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 tests/parser_test.py diff --git a/comfospot40/parser.py b/comfospot40/parser.py index dde620c..c20aba7 100644 --- a/comfospot40/parser.py +++ b/comfospot40/parser.py @@ -5,6 +5,7 @@ import copy from datetime import datetime from serial import SerialException +import asyncio class Parser: @@ -19,12 +20,17 @@ def __init__(self, serial, packetlog=None, state=State()): def get_state(self): return self._state - async def read_byte(self): + async def read_byte(self, retries=5): while True: try: return await self._ser.read(1) except SerialException as e: - logging.warn("Failed to read serial", e) + logging.warning("Failed to read serial: {}".format(e)) + if retries > 0: + await asyncio.sleep(0.1 * retries) + retries -= 1 + else: + raise e async def search_length(self, data): logging.info("z") diff --git a/tests/parser_test.py b/tests/parser_test.py new file mode 100644 index 0000000..67ab3e1 --- /dev/null +++ b/tests/parser_test.py @@ -0,0 +1,55 @@ +import asyncio +import unittest +import comfospot40 +import logging +from serial import SerialException + + +class TestStateLoad(unittest.IsolatedAsyncioTestCase): + async def test_read_byte_ok(self): + class TestSerial: + async def read(self, _): + return b"A" + + s = TestSerial() + p = comfospot40.Parser(s) + self.assertEqual(b"A", await p.read_byte()) + + async def test_read_byte_error(self): + logging.disable(logging.CRITICAL) + + class TestSerial: + async def read(self, _): + raise SerialException("something") + return b"A" + + s = TestSerial() + p = comfospot40.Parser(s) + with self.assertRaises(SerialException): + await p.read_byte(0) + + async def test_read_byte_retry(self): + logging.disable(logging.CRITICAL) + + class TestSerial: + async def read(self, _): + raise SerialException("something") + return b"A" + + s = TestSerial() + p = comfospot40.Parser(s) + with self.assertRaises(SerialException): + await asyncio.wait_for(p.read_byte(0), timeout=1) + + async def test_read_byte_retry_timeout(self): + logging.disable(logging.CRITICAL) + + class TestSerial: + async def read(self, _): + raise SerialException("something") + return b"A" + + s = TestSerial() + p = comfospot40.Parser(s) + with self.assertRaises(asyncio.exceptions.TimeoutError): + await asyncio.wait_for(p.read_byte(2), timeout=0.1)