Skip to content

Extending a Protocol leads to unsafe behavior #8005

Closed
@jingw

Description

@jingw
  • Are you reporting a bug, or opening a feature request?
    bug

  • Please insert below the code you are checking with mypy, or a mock-up repro if the source is private. We would appreciate if you try to simplify your case to a minimal repro.

from typing import Protocol

class P(Protocol):
    def foo(self) -> int: ...

class A(P):  # mypy does not flag this
    pass

class B:
    pass

test: P = A()  # mypy does not flag this
test = B()  # mypy flags this

print(A().foo() + 5)  # both error at runtime
print(B().foo() + 5)
  • What is the actual behavior/output?
    A().foo() + 5 crashes at runtime with TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
    B is correctly type checked and rejected.

  • What is the behavior/output you expect?
    According to https://mypy.readthedocs.io/en/latest/protocols.html#defining-subprotocols-and-subclassing-protocols, "Explicitly including a protocol as a base class ... forces mypy to verify that your class implementation is actually compatible with the protocol."
    I would expect extending a Protocol to be similar to implementing an interface in Java.
    In this particular example, mypy should ideally detect that A does not fill in the stub method from P, like it does for B. Alternatively, if that is not possible, perhaps extending a protocol should not be allowed.

  • What are the versions of mypy and Python you are using? Do you see the same issue after installing mypy from Git master?
    Python 3.8.0
    mypy 0.750+dev.d9dea5f3ad30bb449e4167b3e8476684ded0482e

  • What are the mypy flags you are using? (For example --strict-optional)
    mypy --strict test.py

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions