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:
parent
22424c02e5
commit
46abfc1416
|
@ -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
|
||||||
|
|
|
@ -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 = []
|
||||||
|
|
|
@ -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.
|
Loading…
Reference in New Issue