-
-
Notifications
You must be signed in to change notification settings - Fork 33.3k
Description
Bug report
Bug description:
When the library tries to initialize a formatter and comes across the old format property, it falls back to an error handler, but before it does that, it pops the . dicationary from the config making it impossible to process it later during the second call to self.configure_custom(config)
https://github.com/python/cpython/blob/main/Lib/logging/config.py#L480
This is whrere configure_custom calls props = config.pop('.', None), but it does that before result = c(**kwargs) which throws an exception when it finds the format property.
def configure_custom(self, config):
"""Configure an object with a user-supplied factory."""
c = config.pop('()')
if not callable(c):
c = self.resolve(c)
props = config.pop('.', None) # <-- '.' gets removed on first try and is gone on the second attempt
# Check for valid identifiers
kwargs = {k: config[k] for k in config if valid_ident(k)}
result = c(**kwargs) # <-- throws an error when `format` property is used
# props = config.pop('.', None) # <-- this is where it probably needs to get called so that '.' remains in 'config'
if props:
for name, value in props.items():
setattr(result, name, value)
return resultThen then initialization continues here inside the except that calls configure_custom for the second time, but this time without the . in the config so it's skipped.
https://github.com/python/cpython/blob/main/Lib/logging/config.py#L670
def configure_formatter(self, config):
"""Configure a formatter from a dictionary."""
if '()' in config:
factory = config['()'] # for use in exception handler
try:
result = self.configure_custom(config)
except TypeError as te:
if "'format'" not in str(te):
raise
#Name of parameter changed from fmt to format.
#Retry with old name.
#This is so that code can be used with older Python versions
#(e.g. by Django)
config['fmt'] = config.pop('format')
config['()'] = factory
result = self.configure_custom(config)I guess the function configure_custom should call props = config.pop('.', None) after result = c(**kwargs) so that the . remains in the config for the second call in case an exception is thrown during the first try.
Example
This config won't initialize the custom_property of MyFormatter:
"custom_formatter": {
"()": MyFormatter,
"style": "{",
"datefmt": "%Y-%m-%d %H:%M:%S",
"format": "<custom-format>", # <-- when removed or changed to `fmt` then the '.' works
".": {
"custom_property": "value"
}
}The formatter is implemented like this:
class MyFormatter(logging.Formatter):
custom_property: str = "."
def format(self, record: logging.LogRecord) -> str:
# ...
return super().format(record)CPython versions tested on:
3.10
Operating systems tested on:
Windows
Linked PRs
Metadata
Metadata
Assignees
Labels
Projects
Status