From 2630049ab74662105f25c9b05f489b6ad1872a6d Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Sat, 9 Dec 2023 16:14:27 -0800 Subject: [PATCH] possible fix for infinite loop issue --- jc/parsers/xrandr.py | 34 +++++++++++++++++++++++++++++++++- tests/test_xrandr.py | 7 ++++++- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/jc/parsers/xrandr.py b/jc/parsers/xrandr.py index dfd480bf..462a7df7 100644 --- a/jc/parsers/xrandr.py +++ b/jc/parsers/xrandr.py @@ -193,7 +193,7 @@ from jc.parsers.pyedid.helpers.edid_helper import EdidHelper class info: """Provides parser metadata (version, author, etc.)""" - version = "1.3" + version = "1.4" description = "`xrandr` command parser" author = "Kevin Lyter" author_email = "code (at) lyterk.com" @@ -205,6 +205,25 @@ class info: __version__ = info.version +# keep parsing state so we know which parsers have already tried the line +parse_state: Dict[str, List] = {} + +def _was_parsed(line: str, parser: str) -> bool: + """ + Check if entered parser has already parsed. If so return True. + If not, return false and add the parser to the list for the line entry. + """ + if line in parse_state: + if parser in parse_state[line]: + return True + + parse_state[line].append(parser) + return False + + parse_state[line] = [parser] + return False + + try: from typing import TypedDict @@ -291,6 +310,10 @@ _screen_pattern = ( def _parse_screen(next_lines: List[str]) -> Optional[Screen]: next_line = next_lines.pop() + + if _was_parsed(next_line, 'screen'): + return None + result = re.match(_screen_pattern, next_line) if not result: next_lines.append(next_line) @@ -333,6 +356,10 @@ def _parse_device(next_lines: List[str], quiet: bool = False) -> Optional[Device return None next_line = next_lines.pop() + + if _was_parsed(next_line, 'device'): + return None + result = re.match(_device_pattern, next_line) if not result: next_lines.append(next_line) @@ -402,6 +429,10 @@ def _parse_model(next_lines: List[str], quiet: bool = False) -> Optional[Model]: return None next_line = next_lines.pop() + + if _was_parsed(next_line, 'model'): + return None + if not re.match(_edid_head_pattern, next_line): next_lines.append(next_line) return None @@ -438,6 +469,7 @@ _frequencies_pattern = r"(((?P\d+\.\d+)(?P\*| |)(?P\+?)?) def _parse_mode(line: str) -> Optional[Mode]: result = re.match(_mode_pattern, line) frequencies: List[Frequency] = [] + if not result: return None diff --git a/tests/test_xrandr.py b/tests/test_xrandr.py index 0c704e88..45414105 100644 --- a/tests/test_xrandr.py +++ b/tests/test_xrandr.py @@ -18,13 +18,17 @@ from jc.parsers.xrandr import ( Mode, Model, Device, - Screen, + Screen ) +import jc.parsers.xrandr import pprint class XrandrTests(unittest.TestCase): + def setUp(self): + jc.parsers.xrandr.parse_state = {} + def test_xrandr_nodata(self): """ Test 'xrandr' with no data @@ -287,6 +291,7 @@ class XrandrTests(unittest.TestCase): "serial_number": "0", } + jc.parsers.xrandr.parse_state = {} actual: Optional[Model] = _parse_model(generic_edid) self.assertIsNotNone(actual)