From 39c6c221e604d12c6f16af4aeb208a6c830f7d08 Mon Sep 17 00:00:00 2001 From: agessaman Date: Sun, 22 Feb 2026 12:01:02 -0800 Subject: [PATCH] fix duplicate option handling in config parser for Python 3.13 compatibility - Updated the `_handle_option` method to accommodate changes in Python 3.13, ensuring proper handling of duplicate options in configuration files. - Enhanced logging to provide clearer error messages when duplicate options are detected, improving troubleshooting capabilities. --- modules/core.py | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/modules/core.py b/modules/core.py index 20f25c7..b59e639 100644 --- a/modules/core.py +++ b/modules/core.py @@ -51,12 +51,23 @@ class _DuplicateAwareConfigParser(configparser.ConfigParser): super().__init__(*args, **kwargs) def _handle_option(self, st, line, fpname): - if st.optname in st.options: - logging.getLogger(__name__).error( - "Duplicate option in config file: section [%s], option '%s' (file %s, line %s). Using last value.", - st.sectname, st.optname, fpname, getattr(st, 'lineno', '?'), - ) - st.options[st.optname] = st.optvalue + # Python 3.13+ uses st.cursect; older internals used st.options (both mean current section dict). + sect = getattr(st, 'cursect', None) or getattr(st, 'options', None) + if sect is not None: + # Duplicate check: in 3.13 optname is set inside base _handle_option, so parse line here for the check. + line_str = getattr(line, 'clean', None) + if line_str is None: + line_str = line if isinstance(line, str) else str(line) + mo = self._optcre.match(line_str) if line_str else None + if mo: + optname = self.optionxform(mo.group('option').rstrip()) + if optname in sect: + logging.getLogger(__name__).error( + "Duplicate option in config file: section [%s], option '%s' (file %s, line %s). Using last value.", + getattr(st, 'sectname', '?'), optname, fpname, getattr(st, 'lineno', '?'), + ) + # Delegate to base to parse line and set option (required on Python 3.13+). + super()._handle_option(st, line, fpname) class MeshCoreBot: