|
28 | 28 | from types import GenericAlias |
29 | 29 | from string import Template |
30 | 30 | from string import Formatter as StrFormatter |
| 31 | +from string.templatelib import Template as TStringTemplate, Interpolation |
31 | 32 |
|
32 | 33 |
|
33 | 34 | __all__ = ['BASIC_FORMAT', 'BufferingFormatter', 'CRITICAL', 'DEBUG', 'ERROR', |
@@ -289,11 +290,14 @@ class LogRecord(object): |
289 | 290 |
|
290 | 291 | LogRecord instances are created every time something is logged. They |
291 | 292 | 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. |
297 | 301 | """ |
298 | 302 | def __init__(self, name, level, pathname, lineno, |
299 | 303 | msg, args, exc_info, func=None, sinfo=None, **kwargs): |
@@ -321,6 +325,12 @@ def __init__(self, name, level, pathname, lineno, |
321 | 325 | # formatting still seem to suggest a mapping object is required. |
322 | 326 | # Thus, while not removing the isinstance check, it does now look |
323 | 327 | # 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 | + ) |
324 | 334 | if (args and len(args) == 1 and isinstance(args[0], collections.abc.Mapping) |
325 | 335 | and args[0]): |
326 | 336 | args = args[0] |
@@ -394,7 +404,21 @@ def getMessage(self): |
394 | 404 |
|
395 | 405 | Return the message for this LogRecord after merging any user-supplied |
396 | 406 | 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 | + |
398 | 422 | msg = str(self.msg) |
399 | 423 | if self.args: |
400 | 424 | msg = msg % self.args |
|
0 commit comments