gh-115233: Fix an example in the Logging Cookbook (GH-115325)

Also add more tests for LoggerAdapter.

Also support stacklevel in LoggerAdapter._log().
This commit is contained in:
Serhiy Storchaka 2024-02-12 18:24:45 +02:00 committed by GitHub
parent 8144661017
commit 91822018ee
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 90 additions and 23 deletions

View file

@ -5478,6 +5478,7 @@ class LoggerAdapterTest(unittest.TestCase):
self.assertEqual(record.levelno, logging.CRITICAL)
self.assertEqual(record.msg, msg)
self.assertEqual(record.args, (self.recording,))
self.assertEqual(record.funcName, 'test_critical')
def test_is_enabled_for(self):
old_disable = self.adapter.logger.manager.disable
@ -5496,15 +5497,9 @@ class LoggerAdapterTest(unittest.TestCase):
self.assertFalse(self.adapter.hasHandlers())
def test_nested(self):
class Adapter(logging.LoggerAdapter):
prefix = 'Adapter'
def process(self, msg, kwargs):
return f"{self.prefix} {msg}", kwargs
msg = 'Adapters can be nested, yo.'
adapter = Adapter(logger=self.logger, extra=None)
adapter_adapter = Adapter(logger=adapter, extra=None)
adapter = PrefixAdapter(logger=self.logger, extra=None)
adapter_adapter = PrefixAdapter(logger=adapter, extra=None)
adapter_adapter.prefix = 'AdapterAdapter'
self.assertEqual(repr(adapter), repr(adapter_adapter))
adapter_adapter.log(logging.CRITICAL, msg, self.recording)
@ -5513,6 +5508,7 @@ class LoggerAdapterTest(unittest.TestCase):
self.assertEqual(record.levelno, logging.CRITICAL)
self.assertEqual(record.msg, f"Adapter AdapterAdapter {msg}")
self.assertEqual(record.args, (self.recording,))
self.assertEqual(record.funcName, 'test_nested')
orig_manager = adapter_adapter.manager
self.assertIs(adapter.manager, orig_manager)
self.assertIs(self.logger.manager, orig_manager)
@ -5528,6 +5524,61 @@ class LoggerAdapterTest(unittest.TestCase):
self.assertIs(adapter.manager, orig_manager)
self.assertIs(self.logger.manager, orig_manager)
def test_styled_adapter(self):
# Test an example from the Cookbook.
records = self.recording.records
adapter = StyleAdapter(self.logger)
adapter.warning('Hello, {}!', 'world')
self.assertEqual(str(records[-1].msg), 'Hello, world!')
self.assertEqual(records[-1].funcName, 'test_styled_adapter')
adapter.log(logging.WARNING, 'Goodbye {}.', 'world')
self.assertEqual(str(records[-1].msg), 'Goodbye world.')
self.assertEqual(records[-1].funcName, 'test_styled_adapter')
def test_nested_styled_adapter(self):
records = self.recording.records
adapter = PrefixAdapter(self.logger)
adapter.prefix = '{}'
adapter2 = StyleAdapter(adapter)
adapter2.warning('Hello, {}!', 'world')
self.assertEqual(str(records[-1].msg), '{} Hello, world!')
self.assertEqual(records[-1].funcName, 'test_nested_styled_adapter')
adapter2.log(logging.WARNING, 'Goodbye {}.', 'world')
self.assertEqual(str(records[-1].msg), '{} Goodbye world.')
self.assertEqual(records[-1].funcName, 'test_nested_styled_adapter')
def test_find_caller_with_stacklevel(self):
the_level = 1
trigger = self.adapter.warning
def innermost():
trigger('test', stacklevel=the_level)
def inner():
innermost()
def outer():
inner()
records = self.recording.records
outer()
self.assertEqual(records[-1].funcName, 'innermost')
lineno = records[-1].lineno
the_level += 1
outer()
self.assertEqual(records[-1].funcName, 'inner')
self.assertGreater(records[-1].lineno, lineno)
lineno = records[-1].lineno
the_level += 1
outer()
self.assertEqual(records[-1].funcName, 'outer')
self.assertGreater(records[-1].lineno, lineno)
lineno = records[-1].lineno
the_level += 1
outer()
self.assertEqual(records[-1].funcName, 'test_find_caller_with_stacklevel')
self.assertGreater(records[-1].lineno, lineno)
def test_extra_in_records(self):
self.adapter = logging.LoggerAdapter(logger=self.logger,
extra={'foo': '1'})
@ -5569,6 +5620,30 @@ class LoggerAdapterTest(unittest.TestCase):
self.assertEqual(record.foo, '2')
class PrefixAdapter(logging.LoggerAdapter):
prefix = 'Adapter'
def process(self, msg, kwargs):
return f"{self.prefix} {msg}", kwargs
class Message:
def __init__(self, fmt, args):
self.fmt = fmt
self.args = args
def __str__(self):
return self.fmt.format(*self.args)
class StyleAdapter(logging.LoggerAdapter):
def log(self, level, msg, /, *args, stacklevel=1, **kwargs):
if self.isEnabledFor(level):
msg, kwargs = self.process(msg, kwargs)
self.logger.log(level, Message(msg, args), **kwargs,
stacklevel=stacklevel+1)
class LoggerTest(BaseTest, AssertErrorMessage):
def setUp(self):