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.
This commit is contained in:
Vinay Sajip 2020-01-01 19:32:11 +00:00 committed by GitHub
parent 22424c02e5
commit 46abfc1416
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 37 additions and 1 deletions

View File

@ -448,7 +448,7 @@ class BaseConfigurator(object):
value = ConvertingList(value) value = ConvertingList(value)
value.configurator = self value.configurator = self
elif not isinstance(value, ConvertingTuple) and\ elif not isinstance(value, ConvertingTuple) and\
isinstance(value, tuple): isinstance(value, tuple) and not hasattr(value, '_fields'):
value = ConvertingTuple(value) value = ConvertingTuple(value)
value.configurator = self value.configurator = self
elif isinstance(value, str): # str for py3k elif isinstance(value, str): # str for py3k

View File

@ -3379,6 +3379,37 @@ class ConfigDictTest(BaseTest):
self.assertRaises(ValueError, bc.convert, 'cfg://!') self.assertRaises(ValueError, bc.convert, 'cfg://!')
self.assertRaises(KeyError, bc.convert, 'cfg://adict[2]') 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): class ManagerTest(BaseTest):
def test_manager_loggerclass(self): def test_manager_loggerclass(self):
logged = [] logged = []

View File

@ -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.