Skip to content

Commit 57c93dd

Browse files
bittnerCopilot
andcommitted
Fix Windows permission errors by closing logging handlers before cleanup
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
1 parent 13f305d commit 57c93dd

File tree

3 files changed

+62
-33
lines changed

3 files changed

+62
-33
lines changed

cli_test_helpers/decorators.py

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,42 +3,14 @@
33
"""
44

55
import contextlib
6-
import logging
76
import os
87
import sys
98
from tempfile import TemporaryDirectory
109
from unittest.mock import patch
1110

12-
__all__ = []
13-
14-
15-
class LoggingIsolationMixin:
16-
"""
17-
Mixin that provides automatic logging configuration isolation.
18-
19-
Isolates logging configuration by temporarily clearing logging handlers
20-
when entering the context and restoring them when exiting. This allows
21-
code under test to call ``logging.basicConfig()`` successfully even when
22-
test frameworks (like pytest) have already configured logging handlers.
23-
"""
11+
from .mixins import LoggingIsolationMixin
2412

25-
def __enter__(self):
26-
"""Save and clear logging handlers before entering the context."""
27-
self._old_handlers = logging.root.handlers[:]
28-
logging.root.handlers.clear()
29-
# Call parent __enter__ if it exists (for cooperative inheritance)
30-
if hasattr(super(), "__enter__"):
31-
return super().__enter__()
32-
return self
33-
34-
def __exit__(self, exc_type, exc_val, exc_tb):
35-
"""Restore logging handlers after exiting the context."""
36-
if hasattr(self, "_old_handlers"):
37-
logging.root.handlers[:] = self._old_handlers
38-
# Call parent __exit__ if it exists (for cooperative inheritance)
39-
if hasattr(super(), "__exit__"):
40-
return super().__exit__(exc_type, exc_val, exc_tb)
41-
return None
13+
__all__ = []
4214

4315

4416
class ArgvContext(LoggingIsolationMixin):

cli_test_helpers/mixins.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
"""
2+
Mixins for all context managers (decorators). Not for direct, public use.
3+
"""
4+
5+
import logging
6+
7+
8+
class LoggingIsolationMixin:
9+
"""
10+
Mixin that provides automatic logging configuration isolation.
11+
12+
Isolates logging configuration by temporarily clearing logging handlers
13+
when entering the context and restoring them when exiting. This allows
14+
code under test to call ``logging.basicConfig()`` successfully even when
15+
test frameworks (like pytest) have already configured logging handlers.
16+
17+
All context managers use this mixin.
18+
"""
19+
20+
def __enter__(self):
21+
"""Save and clear logging handlers before entering the context."""
22+
self._old_handlers = logging.root.handlers[:]
23+
logging.root.handlers.clear()
24+
if hasattr(super(), "__enter__"): # cooperative inheritance (MRO)
25+
return super().__enter__()
26+
return self
27+
28+
def __exit__(self, exc_type, exc_val, exc_tb):
29+
"""
30+
Restore logging handlers after exiting the context.
31+
32+
Closes and removes any handlers that were added during the context.
33+
"""
34+
handlers_to_close = [
35+
handler
36+
for handler in logging.root.handlers
37+
if handler not in self._old_handlers
38+
]
39+
40+
for handler in handlers_to_close:
41+
handler.close()
42+
logging.root.handlers.remove(handler)
43+
44+
logging.root.handlers[:] = self._old_handlers
45+
46+
if hasattr(super(), "__exit__"): # cooperative inheritance (MRO)
47+
return super().__exit__(exc_type, exc_val, exc_tb)
48+
return None

docs/api.rst

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,20 @@ by the CLI test helpers package.
99
Context Managers
1010
----------------
1111

12-
.. autoclass:: ArgvContext
12+
.. autoclass:: cli_test_helpers.ArgvContext
1313

14-
.. autoclass:: EnvironContext
14+
.. autoclass:: cli_test_helpers.EnvironContext
1515

16-
.. autoclass:: RandomDirectoryContext
16+
.. autoclass:: cli_test_helpers.RandomDirectoryContext
17+
18+
Mixins
19+
------
20+
21+
.. note::
22+
23+
Used internally by all context managers, not meant for direct use.
24+
25+
.. autoclass:: cli_test_helpers.mixins.LoggingIsolationMixin
1726

1827
Utilities
1928
---------

0 commit comments

Comments
 (0)