Thread (6 messages) 6 messages, 4 authors, 2024-02-02

Re: [PATCH net-next v1 02/12] tools/net/ynl: Support sub-messages in nested attribute spaces

From: Alessandro Marcolini <hidden>
Date: 2024-01-27 18:51:33
Also in: linux-doc

On 1/27/24 18:18, Donald Hunter wrote:
Jakub Kicinski [off-list ref] writes:
quoted
Is it possible to check at which "level" of the chainmap the key was
found? If so we can also construct a 'chainmap of attr sets' and make
sure that the key level == attr set level. I.e. that we got a hit at
the first level which declares a key of that name.

More crude option - we could construct a list of dicts (the levels
within the chainmap) and keys they can't contain. Once we got a hit
for a sub-message key at level A, all dicts currently on top of A
are not allowed to add that key. Once we're done with the message we
scan thru the list and make sure the keys haven't appeared?

Another random thought, should we mark the keys which can "descend"
somehow? IDK, put a ~ in front?

	selector: ~kind

or some other char?
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:

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?
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help