]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-39142: Avoid converting namedtuple instances to ConvertingTuple. (GH-17773)
authorVinay Sajip <vinay_sajip@yahoo.co.uk>
Wed, 1 Jan 2020 19:32:11 +0000 (19:32 +0000)
committerGitHub <noreply@github.com>
Wed, 1 Jan 2020 19:32:11 +0000 (19:32 +0000)
This uses the heuristic of assuming a named tuple is a subclass of
tuple with a _fields attribute. This change means that contents of
a named tuple wouldn't be converted - if a user wants to have
ConvertingTuple functionality from a namedtuple, they will have to
implement it themselves.

Lib/logging/config.py
Lib/test/test_logging.py
Misc/NEWS.d/next/Library/2019-12-31-19-27-23.bpo-39142.oqU5iD.rst [new file with mode: 0644]

index 4a3b8966ede1c098720a3d5e4effc6e867b30d04..fd3aded7608cbfebcc7002d456aa3b631eec9453 100644 (file)
@@ -448,7 +448,7 @@ class BaseConfigurator(object):
             value = ConvertingList(value)
             value.configurator = self
         elif not isinstance(value, ConvertingTuple) and\
-                 isinstance(value, tuple):
+                 isinstance(value, tuple) and not hasattr(value, '_fields'):
             value = ConvertingTuple(value)
             value.configurator = self
         elif isinstance(value, str): # str for py3k
index 4feed03fec2a814c6d7bff573e4d6c11be04a19a..c38fdae03385eea49c97d601aa0a013f81fab2ff 100644 (file)
@@ -3379,6 +3379,37 @@ class ConfigDictTest(BaseTest):
         self.assertRaises(ValueError, bc.convert, 'cfg://!')
         self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
 
+    def test_namedtuple(self):
+        # see bpo-39142
+        from collections import namedtuple
+
+        class MyHandler(logging.StreamHandler):
+            def __init__(self, resource, *args, **kwargs):
+                super().__init__(*args, **kwargs)
+                self.resource: namedtuple = resource
+
+            def emit(self, record):
+                record.msg += f' {self.resource.type}'
+                return super().emit(record)
+
+        Resource = namedtuple('Resource', ['type', 'labels'])
+        resource = Resource(type='my_type', labels=['a'])
+
+        config = {
+            'version': 1,
+            'handlers': {
+                'myhandler': {
+                    '()': MyHandler,
+                    'resource': resource
+                }
+            },
+            'root':  {'level': 'INFO', 'handlers': ['myhandler']},
+        }
+        with support.captured_stderr() as stderr:
+            self.apply_config(config)
+            logging.info('some log')
+        self.assertEqual(stderr.getvalue(), 'some log my_type\n')
+
 class ManagerTest(BaseTest):
     def test_manager_loggerclass(self):
         logged = []
diff --git a/Misc/NEWS.d/next/Library/2019-12-31-19-27-23.bpo-39142.oqU5iD.rst b/Misc/NEWS.d/next/Library/2019-12-31-19-27-23.bpo-39142.oqU5iD.rst
new file mode 100644 (file)
index 0000000..508d133
--- /dev/null
@@ -0,0 +1,5 @@
+A change was made to logging.config.dictConfig to avoid converting instances
+of named tuples to ConvertingTuple. It's assumed that named tuples are too
+specialised to be treated like ordinary tuples; if a user of named tuples
+requires ConvertingTuple functionality, they will have to implement that
+themselves in their named tuple class.