Skip to content

Commit 5d59d23

Browse files
Import logging and create _CapturingHandler only once.
1 parent 3f1fc37 commit 5d59d23

File tree

2 files changed

+35
-22
lines changed

2 files changed

+35
-22
lines changed

Lib/unittest/case.py

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
from .util import (strclass, safe_repr, _count_diff_all_purpose,
1616
_count_diff_hashable, _common_shorten_repr)
1717

18+
logging = None # imported lazily
19+
1820
__unittest = True
1921

2022
_subtest_msg_sentinel = object()
@@ -299,6 +301,35 @@ def __exit__(self, exc_type, exc_value, tb):
299301
_LoggingWatcher = collections.namedtuple("_LoggingWatcher",
300302
["records", "output"])
301303

304+
# Import logging lazily for assertLogs().
305+
# assertLogs() is one of the least used assertions, and most tests do
306+
# not need to import logging.
307+
308+
def _lazy_logging_import():
309+
global logging
310+
global _CapturingHandler
311+
if logging:
312+
return
313+
314+
import logging
315+
class _CapturingHandler(logging.Handler):
316+
"""
317+
A logging handler capturing all (raw and formatted) logging output.
318+
"""
319+
320+
def __init__(self):
321+
logging.Handler.__init__(self)
322+
self.watcher = _LoggingWatcher([], [])
323+
324+
def flush(self):
325+
pass
326+
327+
def emit(self, record):
328+
self.watcher.records.append(record)
329+
msg = self.format(record)
330+
self.watcher.output.append(msg)
331+
332+
302333
class _AssertLogsContext(_BaseTestCaseContext):
303334
"""A context manager used to implement TestCase.assertLogs()."""
304335

@@ -307,39 +338,19 @@ class _AssertLogsContext(_BaseTestCaseContext):
307338
def __init__(self, test_case, logger_name, level):
308339
_BaseTestCaseContext.__init__(self, test_case)
309340
self.logger_name = logger_name
310-
import logging
311-
self.logging = logging
341+
_lazy_logging_import()
312342
if level:
313343
self.level = logging._nameToLevel.get(level, level)
314344
else:
315345
self.level = logging.INFO
316346
self.msg = None
317347

318348
def __enter__(self):
319-
logging = self.logging
320349
if isinstance(self.logger_name, logging.Logger):
321350
logger = self.logger = self.logger_name
322351
else:
323352
logger = self.logger = logging.getLogger(self.logger_name)
324353
formatter = logging.Formatter(self.LOGGING_FORMAT)
325-
326-
class _CapturingHandler(logging.Handler):
327-
"""
328-
A logging handler capturing all (raw and formatted) logging output.
329-
"""
330-
331-
def __init__(self):
332-
logging.Handler.__init__(self)
333-
self.watcher = _LoggingWatcher([], [])
334-
335-
def flush(self):
336-
pass
337-
338-
def emit(self, record):
339-
self.watcher.records.append(record)
340-
msg = self.format(record)
341-
self.watcher.output.append(msg)
342-
343354
handler = _CapturingHandler()
344355
handler.setFormatter(formatter)
345356
self.watcher = handler.watcher
@@ -361,7 +372,7 @@ def __exit__(self, exc_type, exc_value, tb):
361372
if len(self.watcher.records) == 0:
362373
self._raiseFailure(
363374
"no logs of level {} or higher triggered on {}"
364-
.format(self.logging.getLevelName(self.level), self.logger.name))
375+
.format(logging.getLevelName(self.level), self.logger.name))
365376

366377

367378
class _OrderedChainMap(collections.ChainMap):
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
The :mod:`logging` package is now imported lazily in :mod:`unittest` only
2+
when the :meth:`~unittest.TestCase.assertLogs` assertion is used.

0 commit comments

Comments
 (0)