Skip to content

Commit dabfd44

Browse files
committed
Add native support for t-strings in the stdlib logging library
1 parent 3b7888b commit dabfd44

1 file changed

Lines changed: 30 additions & 6 deletions

File tree

Lib/logging/__init__.py

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from types import GenericAlias
2929
from string import Template
3030
from string import Formatter as StrFormatter
31+
from string.templatelib import Template as TStringTemplate, Interpolation
3132

3233

3334
__all__ = ['BASIC_FORMAT', 'BufferingFormatter', 'CRITICAL', 'DEBUG', 'ERROR',
@@ -289,11 +290,14 @@ class LogRecord(object):
289290
290291
LogRecord instances are created every time something is logged. They
291292
contain all the information pertinent to the event being logged. The
292-
main information passed in is in msg and args, which are combined
293-
using str(msg) % args to create the message field of the record. The
294-
record also includes information such as when the record was created,
295-
the source line where the logging call was made, and any exception
296-
information to be logged.
293+
main information passed in is in msg and args. These ware combined
294+
using str(msg) % args to create the message field of the record. A
295+
special case here is that if the msg is a t-string, it will be
296+
formatted as if it was an f-string without using the provided args.
297+
298+
The record also includes information such as when the record was
299+
created, the source line where the logging call was made, and any
300+
exception information to be logged.
297301
"""
298302
def __init__(self, name, level, pathname, lineno,
299303
msg, args, exc_info, func=None, sinfo=None, **kwargs):
@@ -321,6 +325,12 @@ def __init__(self, name, level, pathname, lineno,
321325
# formatting still seem to suggest a mapping object is required.
322326
# Thus, while not removing the isinstance check, it does now look
323327
# for collections.abc.Mapping rather than, as before, dict.
328+
if isinstance(msg, TStringTemplate):
329+
# Pull args out of the tstring and prepend them to any provided args
330+
args = (
331+
{x.expression: x.value for x in msg if isinstance(x, Interpolation)},
332+
*args
333+
)
324334
if (args and len(args) == 1 and isinstance(args[0], collections.abc.Mapping)
325335
and args[0]):
326336
args = args[0]
@@ -394,7 +404,21 @@ def getMessage(self):
394404
395405
Return the message for this LogRecord after merging any user-supplied
396406
arguments with the message.
397-
"""
407+
If the messsage is a t-string object it will be formatted in the same
408+
way as an f-string without any extra user-supplied arguments.
409+
"""
410+
if isinstance(self.msg, TStringTemplate):
411+
return "".join(
412+
(
413+
_str_formatter.format_field(
414+
_str_formatter.convert_field(x.value, x.conversion),
415+
x.format_spec
416+
)
417+
) if isinstance(x, Interpolation)
418+
else x
419+
for x in self.msg
420+
)
421+
398422
msg = str(self.msg)
399423
if self.args:
400424
msg = msg % self.args

0 commit comments

Comments
 (0)