This patch is a melding of upstream's changes and Arch Linux's patch to logutils/dictconf.py and tests/test_dictconfig.py https://bitbucket.org/vinay.sajip/logutils/commits/c032f726c36d4f932b5a902fdb048f9f07c40d0d https://gitlab.archlinux.org/archlinux/packaging/packages/python-logutils/-/raw/main/logutils-python3-13.patch Neither works for us. Upstream's change depends on logging._lock_acquire and logging._lock_release, neither of which seem to be available in either python 3.12 or 3.14. Arch Linux's change works fine for python 3.14 but breaks with 3.12. -- diff --git a/logutils/dictconfig.py b/logutils/dictconfig.py index c774552..498e5d9 100644 --- a/logutils/dictconfig.py +++ b/logutils/dictconfig.py @@ -290,7 +290,10 @@ class DictConfigurator(BaseConfigurator): raise ValueError("Unsupported version: %s" % config['version']) incremental = config.pop('incremental', False) EMPTY_DICT = {} - logging._acquireLock() + if hasattr(logging, '_acquireLock'): + logging._acquireLock() + else: + logging._prepareFork() try: if incremental: handlers = config.get('handlers', EMPTY_DICT) @@ -431,7 +434,10 @@ class DictConfigurator(BaseConfigurator): raise ValueError('Unable to configure root ' 'logger: %s' % e) finally: - logging._releaseLock() + if hasattr(logging, '_releaseLock'): + logging._releaseLock() + else: + logging._afterFork() def configure_formatter(self, config): """Configure a formatter from a dictionary.""" diff --git a/tests/test_dictconfig.py b/tests/test_dictconfig.py index 3aee984..7d819a9 100644 --- a/tests/test_dictconfig.py +++ b/tests/test_dictconfig.py @@ -39,7 +39,10 @@ class ConfigDictTest(unittest.TestCase): self.adapter = LoggerAdapter(l, {}) logger_dict = logging.getLogger().manager.loggerDict - logging._acquireLock() + if hasattr(logging, '_acquireLock'): + logging._acquireLock() + else: + logging._prepareFork() try: self.saved_handlers = logging._handlers.copy() self.saved_handler_list = logging._handlerList[:] @@ -50,7 +53,10 @@ class ConfigDictTest(unittest.TestCase): self.saved_level_to_name = logging._levelToName.copy() self.saved_name_to_level = logging._nameToLevel.copy() finally: - logging._releaseLock() + if hasattr(logging, '_releaseLock'): + logging._releaseLock() + else: + logging._afterFork() self.root_logger = logging.getLogger("") self.original_logging_level = self.root_logger.getEffectiveLevel() @@ -58,7 +64,10 @@ class ConfigDictTest(unittest.TestCase): def tearDown(self): self.root_logger.setLevel(self.original_logging_level) - logging._acquireLock() + if hasattr(logging, '_acquireLock'): + logging._acquireLock() + else: + logging._prepareFork() try: if hasattr(logging, '_levelNames'): logging._levelNames.clear() @@ -75,7 +84,10 @@ class ConfigDictTest(unittest.TestCase): loggerDict.clear() loggerDict.update(self.saved_loggers) finally: - logging._releaseLock() + if hasattr(logging, '_releaseLock'): + logging._releaseLock() + else: + logging._afterFork() message_num = 0