8000 gh-115233: Fix currentframe to get the frame of original caller by Agent-Hellboy · Pull Request #115241 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

gh-115233: Fix currentframe to get the frame of original caller #115241

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 10 commits into from
Closed
26 changes: 11 additions & 15 deletions Lib/logging/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1830,6 +1830,7 @@ def __reduce__(self):

_loggerClass = Logger


class LoggerAdapter(object):
"""
An adapter for loggers which makes it easier to specify contextual
Expand Down Expand Up @@ -1904,7 +1905,7 @@ def error(self, msg, *args, **kwargs):
"""
self.log(ERROR, msg, *args, **kwargs)

def exception(self, msg, *args, exc_info=True, **kwargs):
def exception(self, msg, *args,exc_info=True, **kwargs):
"""
Delegate an exception call to the underlying logger.
"""
Expand All @@ -1921,9 +1922,16 @@ def log(self, level, msg, *args, **kwargs):
Delegate a log call to the underlying logger, after adding
contextual information from this adapter instance.
"""
self._log(level, msg, *args, **kwargs)

def _log(self, level, msg, *args, **kwargs):
"""
Low-level log implementation, proxied to allow nested logger adapters.
"""
stacklevel = kwargs.pop('stacklevel', 1)
if self.isEnabledFor(level):
msg, kwargs = self.process(msg, kwargs)
self.logger.log(level, msg, *args, **kwargs)
self.logger._log(level, msg, args, **kwargs, stacklevel=stacklevel + 3)

def isEnabledFor(self, level):
"""
Expand All @@ -1949,19 +1957,6 @@ def hasHandlers(self):
"""
return self.logger.hasHandlers()

def _log(self, level, msg, args, exc_info=None, extra=None, stack_info=False):
"""
Low-level log implementation, proxied to allow nested logger adapters.
"""
return self.logger._log(
level,
msg,
args,
exc_info=exc_info,
extra=extra,
stack_info=stack_info,
)

@property
def manager(self):
return self.logger.manager
Expand All @@ -1981,6 +1976,7 @@ def __repr__(self):

__class_getitem__ = classmethod(GenericAlias)


root = RootLogger(WARNING)
Logger.root = root
Logger.manager = Manager(Logger.root)
Expand Down
84 changes: 83 additions & 1 deletion Lib/test/test_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -5512,7 +5512,7 @@ def process(self, msg, kwargs):
record = self.recording.records[0]
self.assertEqual(record.levelno, logging.CRITICAL)
self.assertEqual(record.msg, f"Adapter AdapterAdapter {msg}")
self.assertEqual(record.args, (self.recording,))
self.assertEqual(record.args, ((self.recording,),))
orig_manager = adapter_adapter.manager
self.assertIs(adapter.manager, orig_manager)
self.assertIs(self.logger.manager, orig_manager)
Expand All @@ -5528,6 +5528,41 @@ def process(self, msg, kwargs):
self.assertIs(adapter.manager, orig_manager)
self.assertIs(self.logger.manager, orig_manager)

def test_find_caller_with_stacklevel(self):
the_level = 1
trigger = self.logger.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
root_logger = logging.getLogger()
root_logger.addHandler(self.recording)
trigger = logging.warning
outer()
self.assertEqual(records[-1].funcName, 'outer')
root_logger.removeHandler(self.recording)


def test_extra_in_records(self):
self.adapter = logging.LoggerAdapter(logger=self.logger,
extra={'foo': '1'})
Expand Down Expand Up @@ -5569,6 +5604,53 @@ def test_extra_merged_log_call_has_precedence(self):
self.assertEqual(record.foo, '2')


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 __init__(self, logger, extra=None):
super().__init__(logger, extra or {})

def log(self, level, msg, /, *args, **kwargs):
if self.isEnabledFor(level):
msg, kwargs = self.process(msg, kwargs)
self.logger._log(level, Message(msg, args), (), **kwargs)


class TestIssue115233(unittest.TestCase):
_logger = StyleAdapter(logging.getLogger(__name__))

def main(self):
self.logger.info('Logger initialized.')
self._logger.info('test')

def setUp(self):
self.logger = logging.getLogger(__name__)
self.stream = io.StringIO()
formatter = logging.Formatter(
'%(asctime)s %(name)s %(funcName)s %(levelname)s %(message)s')
self.handler = logging.StreamHandler(self.stream)
self.logger.addHandler(self.handler)
self.handler.setFormatter(formatter)
self.logger.setLevel(logging.INFO)

def tearDown(self):
self.logger.removeHandler(self.handler)

def test_main_function_logs_info_message(self):
self.main()
self.handler.flush()
log_output = self.stream.getvalue()
assert 'main' in log_output



class LoggerTest(BaseTest, AssertErrorMessage):

def setUp(self):
Expand Down
0