Skip to content

Commit 46abfc1

Browse files
authored
bpo-39142: Avoid converting namedtuple instances to ConvertingTuple. (GH-17773)
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.
1 parent 22424c0 commit 46abfc1

File tree

3 files changed

+37
-1
lines changed

3 files changed

+37
-1
lines changed

Lib/logging/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,7 @@ def convert(self, value):
448448
value = ConvertingList(value)
449449
value.configurator = self
450450
elif not isinstance(value, ConvertingTuple) and\
451-
isinstance(value, tuple):
451+
isinstance(value, tuple) and not hasattr(value, '_fields'):
452452
value = ConvertingTuple(value)
453453
value.configurator = self
454454
elif isinstance(value, str): # str for py3k

Lib/test/test_logging.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3379,6 +3379,37 @@ def test_baseconfig(self):
33793379
self.assertRaises(ValueError, bc.convert, 'cfg://!')
33803380
self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]')
33813381

3382+
def test_namedtuple(self):
3383+
# see bpo-39142
3384+
from collections import namedtuple
3385+
3386+
class MyHandler(logging.StreamHandler):
3387+
def __init__(self, resource, *args, **kwargs):
3388+
super().__init__(*args, **kwargs)
3389+
self.resource: namedtuple = resource
3390+
3391+
def emit(self, record):
3392+
record.msg += f' {self.resource.type}'
3393+
return super().emit(record)
3394+
3395+
Resource = namedtuple('Resource', ['type', 'labels'])
3396+
resource = Resource(type='my_type', labels=['a'])
3397+
3398+
config = {
3399+
'version': 1,
3400+
'handlers': {
3401+
'myhandler': {
3402+
'()': MyHandler,
3403+
'resource': resource
3404+
}
3405+
},
3406+
'root': {'level': 'INFO', 'handlers': ['myhandler']},
3407+
}
3408+
with support.captured_stderr() as stderr:
3409+
self.apply_config(config)
3410+
logging.info('some log')
3411+
self.assertEqual(stderr.getvalue(), 'some log my_type\n')
3412+
33823413
class ManagerTest(BaseTest):
33833414
def test_manager_loggerclass(self):
33843415
logged = []
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
A change was made to logging.config.dictConfig to avoid converting instances
2+
of named tuples to ConvertingTuple. It's assumed that named tuples are too
3+
specialised to be treated like ordinary tuples; if a user of named tuples
4+
requires ConvertingTuple functionality, they will have to implement that
5+
themselves in their named tuple class.

0 commit comments

Comments
 (0)