From a5f29c9faf046b9ef3e498a0bc63dbc29017b5e3 Mon Sep 17 00:00:00 2001 From: Vinay Sajip Date: Thu, 9 Nov 2023 18:55:22 +0000 Subject: [PATCH] =?UTF-8?q?gh-110875:=20Handle=20'.'=20properties=20in=20l?= =?UTF-8?q?ogging=20formatter=20configuration=20c=E2=80=A6=20(GH-110943)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Lib/logging/config.py | 8 ++++---- Lib/test/test_logging.py | 38 +++++++++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/Lib/logging/config.py b/Lib/logging/config.py index 951bba73913..4b520e3b1e0 100644 --- a/Lib/logging/config.py +++ b/Lib/logging/config.py @@ -482,10 +482,10 @@ class BaseConfigurator(object): c = config.pop('()') if not callable(c): c = self.resolve(c) - props = config.pop('.', None) # Check for valid identifiers - kwargs = {k: config[k] for k in config if valid_ident(k)} + kwargs = {k: config[k] for k in config if (k != '.' and valid_ident(k))} result = c(**kwargs) + props = config.pop('.', None) if props: for name, value in props.items(): setattr(result, name, value) @@ -835,8 +835,7 @@ class DictConfigurator(BaseConfigurator): factory = functools.partial(self._configure_queue_handler, klass) else: factory = klass - props = config.pop('.', None) - kwargs = {k: config[k] for k in config if valid_ident(k)} + kwargs = {k: config[k] for k in config if (k != '.' and valid_ident(k))} try: result = factory(**kwargs) except TypeError as te: @@ -854,6 +853,7 @@ class DictConfigurator(BaseConfigurator): result.setLevel(logging._checkLevel(level)) if filters: self.add_filters(result, filters) + props = config.pop('.', None) if props: for name, value in props.items(): setattr(result, name, value) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index ab969ce26a6..89be432e4b7 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -2998,6 +2998,39 @@ class ConfigDictTest(BaseTest): }, } + class CustomFormatter(logging.Formatter): + custom_property = "." + + def format(self, record): + return super().format(record) + + config17 = { + 'version': 1, + 'formatters': { + "custom": { + "()": CustomFormatter, + "style": "{", + "datefmt": "%Y-%m-%d %H:%M:%S", + "format": "{message}", # <-- to force an exception when configuring + ".": { + "custom_property": "value" + } + } + }, + 'handlers' : { + 'hand1' : { + 'class' : 'logging.StreamHandler', + 'formatter' : 'custom', + 'level' : 'NOTSET', + 'stream' : 'ext://sys.stdout', + }, + }, + 'root' : { + 'level' : 'WARNING', + 'handlers' : ['hand1'], + }, + } + bad_format = { "version": 1, "formatters": { @@ -3479,7 +3512,10 @@ class ConfigDictTest(BaseTest): {'msg': 'Hello'})) self.assertEqual(result, 'Hello ++ defaultvalue') - + def test_config17_ok(self): + self.apply_config(self.config17) + h = logging._handlers['hand1'] + self.assertEqual(h.formatter.custom_property, 'value') def setup_via_listener(self, text, verify=None): text = text.encode("utf-8")