Re: [PATCH net-next v1 02/12] tools/net/ynl: Support sub-messages in nested attribute spaces
From: Donald Hunter <donald.hunter@gmail.com>
Date: 2024-01-29 11:29:46
Also in:
linux-doc
Alessandro Marcolini [off-list ref] writes:
On 1/27/24 18:18, Donald Hunter wrote:quoted
Okay, so I think the behaviour we need is to either search current scope or search the outermost scope. My suggestion would be to replace the ChainMap approach with just choosing between current and outermost scope. The unusual case is needing to search the outermost scope so using a prefix e.g. '/' for that would work. We can have 'selector: kind' continue to refer to current scope and then have 'selector: /kind' refer to the outermost scope. If we run into a case that requires something other than current or outermost then we could add e.g. '../kind' so that the scope to search is always explicitly identified.Wouldn't add different chars in front of the selctor value be confusing? IMHO the solution of using a ChainMap with levels could be an easier solution. We could just modify the __getitem__() method to output both the value and the level, and the get() method to add the chance to specify a level (in our case the level found in the spec) and error out if the specified level doesn't match with the found one. Something like this:
If we take the approach of resolving the level from the spec then I wouldn't use ChainMap. Per the Python docs [1]: "A ChainMap class is provided for quickly linking a number of mappings so they can be treated as a single unit." I think we could instead pass a list of mappings from current to outermost and then just reference the correct level that was resolved from the spec.
from collections import ChainMap
class LevelChainMap(ChainMap):
def __getitem__(self, key):
for mapping in self.maps:
try:
return mapping[key], self.maps[::-1].index(mapping)
except KeyError:
pass
return self.__missing__(key)
def get(self, key, default=None, level=None):
val, lvl = self[key] if key in self else (default, None)
if level:
if lvl != level:
raise Exception("Level mismatch")
return val, lvl
# example usage
c = LevelChainMap({'a':1}, {'inner':{'a':1}}, {'outer': {'inner':{'a':1}}})
print(c.get('a', level=2))
print(c.get('a', level=1)) #raise err
This will leave the spec as it is and will require small changes.
What do you think?The more I think about it, the more I agree that using path-like syntax in the selector is overkill. It makes sense to resolve the selector level from the spec and then directly access the mappings from the correct scope level. [1] https://docs.python.org/3/library/collections.html#collections.ChainMap