inspect: perform thorough namespace resolution in namesdict (#51591)

This commit is contained in:
Paul Marillonnet 2021-03-03 16:21:48 +01:00 committed by Benjamin Dauvergne
parent c6a9bfb535
commit 20c6163de8
2 changed files with 40 additions and 26 deletions

View File

@ -4397,6 +4397,12 @@ def test_inspect_page(pub, local_user):
upload.receive([b'hello world'])
formdata.data['4'] = upload
formdata.user_id = local_user.id
formdata.workflow_data = {
'foo': {
'bar_coin': 'yy',
},
'foo_bar': 'xx',
}
formdata.store()
from wcs.admin.settings import UserFieldsFormDef

View File

@ -196,33 +196,41 @@ class CompatibilityNamesDict(dict):
return flat_keys.keys()
def __getitem__(self, key):
try:
val = super(CompatibilityNamesDict, self).__getitem__(key)
except KeyError:
# fallback to deconstructing namespaces around underscores
parts = key.split('_')
current_dict = self
while parts:
for i in range(len(parts), 0, -1):
part = '_'.join(parts[:i])
try:
if current_dict is self:
current_dict = dict.__getitem__(current_dict, part)
elif hasattr(current_dict, '__getitem__'):
current_dict = current_dict[part]
else:
current_dict = getattr(current_dict, part)
except (AttributeError, KeyError, TypeError):
# TypeError will happen if indexing is used on a string
if i == 1:
raise KeyError(key)
else:
parts = parts[i:]
break
return current_dict
def get_path(self, base, path):
def resolve(path):
key = '_'.join(path)
try:
if base is self:
return dict.__getitem__(base, key)
elif hasattr(base, '__getitem__'):
return base[key]
else:
return getattr(base, key)
except (AttributeError, KeyError, TypeError) as e:
# TypeError will happen if indexing is used on a string
raise KeyError(key) from e
return val
# longer item's names have precedence over short ones, i.e. if
# d = {'foo': {'bar': 1}, 'foo_bar': 2}
# then get_path(d, 'foor_bar') will return 2 and never 1.
for i in range(len(path), 0, -1):
try:
value = resolve(path[:i])
rest = path[i:]
if rest:
return self.get_path(value, rest)
else:
return value
except KeyError:
pass
raise KeyError
def __getitem__(self, key):
parts = key.split('_')
try:
return self.get_path(self, parts)
except KeyError as e:
raise KeyError(key) from e
def __contains__(self, key):
try: