Bug: update() broken for mapping-like objects
dargueta opened this issue · comments
To reproduce:
import collections
conf = Configuration({})
data = collections.ChainMap({"abc": {"def": "ghi"}})
conf.update(data)
print(conf["abc.def"])
If data
is a plain dict or a Configuration object, conf["abc.def"]
will give "ghi". However, if it's a mapping-like object, it crashes:
In [60]: c['foo.abc']
Traceback (most recent call last):
File "/Users/diegoargueta/.pyenv/versions/aircraft/lib/python3.7/site-packages/IPython/core/interactiveshell.py", line 3524, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-60-e7c3c391a86e>", line 1, in <module>
c['abc.def']
File "/Users/diegoargueta/.pyenv/versions/3.7.8/envs/aircraft/lib/python3.7/site-packages/config/configuration.py", line 155, in __getitem__
raise KeyError(item)
KeyError: 'abc.def'
Your problem is in _flatten_dict()
; you need to change
nested = {k for k, v in d.items() if isinstance(v, (dict, Configuration))}
to
nested = {k for k, v in d.items() if isinstance(v, Mapping)}
I don't have time to test it but I believe you'll run into this problem with as_attrdict()
which also compares against dict
. Use Mapping
or MutableMapping
as needed instead, and this will work as expected.
This KeyError behavior is reproduced when unittest.mock.patch.dict is used to modify a ConfigurationSet object as part of unit testing. Subsequent unit tests will find that the ConfigurationSet object has been corrupted as patch.dict()
is unable to restore the original dictionary after the test that performed the patching.
Example
The following decorator-style use of @patch.dict
will corrupt the CONFIG object:
@patch.dict('app.rest.permissions.CONFIG', {'config_key': 'config_value'})
A workaround is to use @patch
instead like this:
@patch('app.rest.permissions.CONFIG', Configuration({'config_key': 'config_value'}))
@alexholtz, do you have an example? Does the suggestion from @dargueta fix it for you?