From c345dad179f47cbb6d5c19849834dd120b3a5a17 Mon Sep 17 00:00:00 2001 From: Vinay Sajip Date: Mon, 16 Oct 2023 19:20:20 +0100 Subject: [PATCH 1/3] gh-110875: Handle '.' properties in logging formatter configuration correctly. --- Lib/logging/config.py | 4 ++-- Lib/test/test_logging.py | 38 +++++++++++++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/Lib/logging/config.py b/Lib/logging/config.py index 951bba73913cb3..2d7116bf1103e3 100644 --- a/Lib/logging/config.py +++ b/Lib/logging/config.py @@ -482,10 +482,10 @@ def configure_custom(self, config): 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 (False if k == '.' else valid_ident(k))} result = c(**kwargs) + 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 ab969ce26a69e7..89be432e4b78c0 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 @@ def test_config16_ok(self): {'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") From 81b91d138040b85895a22e6e877c942d120d8880 Mon Sep 17 00:00:00 2001 From: Vinay Sajip Date: Fri, 3 Nov 2023 17:36:14 +0000 Subject: [PATCH 2/3] Improve readability of condition. Thanks to Petr Viktorin for the suggestion. --- Lib/logging/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/logging/config.py b/Lib/logging/config.py index 2d7116bf1103e3..c7cd1e23c4eb17 100644 --- a/Lib/logging/config.py +++ b/Lib/logging/config.py @@ -483,7 +483,7 @@ def configure_custom(self, config): if not callable(c): c = self.resolve(c) # Check for valid identifiers - kwargs = {k: config[k] for k in config if (False if k == '.' else 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: From 1a6a8d81fe40ec5a1d280f5753ab45fae84bd32e Mon Sep 17 00:00:00 2001 From: Vinay Sajip Date: Thu, 9 Nov 2023 18:22:38 +0000 Subject: [PATCH 3/3] Make kwargs processing consistent, per review comments. --- Lib/logging/config.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/logging/config.py b/Lib/logging/config.py index c7cd1e23c4eb17..4b520e3b1e0da6 100644 --- a/Lib/logging/config.py +++ b/Lib/logging/config.py @@ -835,8 +835,7 @@ def configure_handler(self, config): 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 @@ def configure_handler(self, config): 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)