Alessandro Marcolini <alessandromarcolini99@xxxxxxxxx> writes: > On 1/27/24 18:18, Donald Hunter wrote: >> 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