typeshed
typeshed copied to clipboard
`ChainMap` has wrong or unintuitive type after #6042
#6042/#6044 gives me new mypy complaints on my code base.
ChainMap only ever writes to the first mapping in maps. That's my understanding. For example ChainMap({}, defaults) is a typical use-case where the user gets a dict-like and cannot mutate the defaults. That's the typical stacking property of the ChainMap, you only ever mutate the top, most recent mapping.
From my understanding:
def __init__(self):
def __init__(self, __map: MutableMapping):
def __init__(self, __map: MutableMapping, *maps: ImmutableMapping):
I don't think we can have correct hints for the maps member, and new_child of course expects a mutable mapping because iirc it is exactly the next top most thing on the stack.
Originally posted by @kaste in https://github.com/python/typeshed/issues/6042#issuecomment-1186610570
(I started this as a comment on the closed issue but closed issues don't move and I got initial supportive feedback on my comment from @hauntsaninja.)
@hauntsaninja wrote
That sounds reasonable to me. I would be in favour of:
class ChainMap(MutableMapping[_KT, _VT], Generic[_KT, _VT]): maps: list[Mapping[_KT, _VT]] def __init__(self) -> None: ... def __init__(self, __map: MutableMapping[_KT, _VT], *maps: Mapping[_KT, _VT]) -> None: ...Also just to call something out:
My understanding is that the typeshed policy is to err on the side of false negatives ... Here is an example in a ChainMap subclass ...
While I'm not sure we've stated this out loud, historically, typeshed has very consistently preferred false positives for subclassers of classes over false positives for other users of classes.