Skip to content

Disallow Mapping as argument type? #3576

Closed

Description

@srittau

This came up in #3569. See also the later comments in python/typing#11 for background. Mapping is not a protocol (as opposed to most other typing ABCs). This mean code like the following will not work:

from typing import Iterator, Mapping

class MyMap:
    def __getitem__(self, key: str) -> int:
        return 0
    def __iter__(self) -> Iterator[str]:
        return iter([])
    def __len__(self) -> int:
        return 0
    def __contains__(self, key: object) -> bool:
        return False

def foo(x: Mapping[str, int]) -> None:
    pass

foo(MyMap())  # error: Argument 1 to "foo" has incompatible type "MyMap"; expected "Mapping[str, int]"

Deriving MyMap from Mapping[str, int] works, though. I suggest we don't allow new submissions to use Mapping as argument type and work towards removing existing uses. Instead they should use a custom protocol, which can also be narrower than Mapping.

Activity

  1. djb4ai commented on Mar 26, 2020

    @djb4ai
    Contributor

    @srittau I am trying to create a Protocol in PR#3877 but when I use Protocol[_KT, _VT_co] it says Invariant type variable '_KT' used in protocol where contravariant one is expected, can't understand what could be causing this.

  2. added a commit that references this issue on Jul 10, 2020
  3. jab commented on Aug 12, 2020

    @jab
    Contributor

    Rather than disallowing Mapping as an argument type because Mapping is not a protocol, is it better to instead make Mapping a protocol? That seems like it would result in better usability than the alternative of forbidding Mapping arguments. Worth writing down the pros and cons of both options before picking which one? Related protocols (SupportsGetItem, etc.) were recently added in #4325 since this issue was created. Does that change things?

    Relatedly, if we had python/mypy#2922, I guess Mapping.register(MyMap) could be added to the example in the issue description to resolve the error, but mypy does not yet support ABCMeta.register.

  4. srittau commented on Aug 12, 2020

    @srittau
    CollaboratorAuthor

    I think it's hard to make Mapping a protocol, since it's an abstract base class in collections.abc, and since it's so widely used. But maybe it would make sense to introduce a separate MappingProto (or similar) protocol and use that going forward. Although, using more specific protocols is still more useful, but harder to implement.

  5. gvanrossum commented on Aug 12, 2020

    @gvanrossum
    Member

    Indeed. We looked into this and found it would be very difficult. I strongly recommend just inheriting from Mapping over coming up with yet another duck typing protocol. FWIW mypy probably will never support .register().

  6. AlexWaygood commented on Nov 1, 2023

    @AlexWaygood
    Member

    We have _typeshed.SupportsKeysAndGetItem now, and use it quite widely. It's a very useful protocol.

    Possibly we could look into adding lints to detect bad uses of Mapping in argument annotations. The issue tracker at flake8-pyi would probably be a better place to discuss that, though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    project: policyOrganization of the typeshed project

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions