From b5e50fa26eac46d0261f54edf176330b1064e5c0 Mon Sep 17 00:00:00 2001 From: Vinay Sajip Date: Thu, 26 Feb 2026 09:09:23 +0000 Subject: [PATCH 1/2] gh-135683: Ensure that WatchedFileHandler calls handleError on exceptions. --- Lib/logging/__init__.py | 9 ++++++--- Lib/logging/handlers.py | 9 ++++++--- Lib/test/test_logging.py | 35 ++++++++++++++++++++++++++++++++--- 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py index 39689a57e6ecd6..c71e1060e51d6b 100644 --- a/Lib/logging/__init__.py +++ b/Lib/logging/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2001-2022 by Vinay Sajip. All Rights Reserved. +# Copyright 2001-2026 by Vinay Sajip. All Rights Reserved. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose and without fee is hereby granted, @@ -18,7 +18,7 @@ Logging package for Python. Based on PEP 282 and comments thereto in comp.lang.python. -Copyright (C) 2001-2022 Vinay Sajip. All Rights Reserved. +Copyright (C) 2001-2026 Vinay Sajip. All Rights Reserved. To use, simply 'import logging' and log away! """ @@ -1257,7 +1257,10 @@ def emit(self, record): """ if self.stream is None: if self.mode != 'w' or not self._closed: - self.stream = self._open() + try: + self.stream = self._open() + except Exception: + self.handleError(record) if self.stream: StreamHandler.emit(self, record) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py index 575f2babbc4785..5ed60c52290fe9 100644 --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -1,4 +1,4 @@ -# Copyright 2001-2021 by Vinay Sajip. All Rights Reserved. +# Copyright 2001-2026 by Vinay Sajip. All Rights Reserved. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose and without fee is hereby granted, @@ -18,7 +18,7 @@ Additional handlers for the logging package for Python. The core package is based on PEP 282 and comments thereto in comp.lang.python. -Copyright (C) 2001-2021 Vinay Sajip. All Rights Reserved. +Copyright (C) 2001-2026 Vinay Sajip. All Rights Reserved. To use, simply 'import logging.handlers' and log away! """ @@ -540,7 +540,10 @@ def emit(self, record): If underlying file has changed, reopen the file before emitting the record to it. """ - self.reopenIfNeeded() + try: + self.reopenIfNeeded() + except Exception: + self.handleError(record) logging.FileHandler.emit(self, record) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index 05dcea6ce0e98a..5658b840a55086 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -1,4 +1,4 @@ -# Copyright 2001-2022 by Vinay Sajip. All Rights Reserved. +# Copyright 2001-2026 by Vinay Sajip. All Rights Reserved. # # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose and without fee is hereby granted, @@ -16,7 +16,7 @@ """Test harness for the logging module. Run all tests. -Copyright (C) 2001-2022 Vinay Sajip. All Rights Reserved. +Copyright (C) 2001-2026 Vinay Sajip. All Rights Reserved. """ import logging import logging.handlers @@ -800,6 +800,36 @@ def lock_holder_thread_fn(): support.wait_process(pid, exitcode=0) + def test_135683(self): + # See gh-135683 + + def tester(): + with tempfile.TemporaryDirectory(prefix='test_logging_') as tmp: + tmp_dir = pathlib.Path(tmp) + dir_path = tmp_dir / 'dir' + link_path = tmp_dir / 'link' + dir_path.mkdir() + link_path.symlink_to(dir_path) + r = logging.makeLogRecord({'msg': 'Test'}) + h = logging.handlers.WatchedFileHandler(link_path / 'file.log') + m = Mock() + h.handleError = m + try: + h.handle(r) + m.assert_not_called() + shutil.rmtree(dir_path) + h.handle(r) + m.assert_called() + finally: + h.close() + + old_raiseExceptions = logging.raiseExceptions + try: + for test_value in (False, True): + logging.raiseExceptions = test_value + tester() + finally: + logging.raiseExceptions = old_raiseExceptions class BadStream(object): def write(self, data): @@ -4439,7 +4469,6 @@ def test_queue_listener_with_multiple_handlers(self): if hasattr(logging.handlers, 'QueueListener'): import multiprocessing - from unittest.mock import patch @skip_if_tsan_fork @threading_helper.requires_working_threading() From 33a9869a9b60e72a11cf7b08cb69cc1ee4d16a08 Mon Sep 17 00:00:00 2001 From: Vinay Sajip Date: Thu, 26 Feb 2026 09:42:05 +0000 Subject: [PATCH 2/2] Skip test on platforms without symlinks. --- Lib/test/test_logging.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index 5658b840a55086..7ce0ca930b1891 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -800,6 +800,7 @@ def lock_holder_thread_fn(): support.wait_process(pid, exitcode=0) + @unittest.skipIf(support.is_wasi or support.MS_WINDOWS, "Platform does not support symlinks.") def test_135683(self): # See gh-135683