Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Protocol with attribute hinted as another protocol can not be satisfied #12990

Closed
altendky opened this issue Jun 16, 2022 · 3 comments
Closed
Labels
bug mypy got something wrong topic-protocols

Comments

@altendky
Copy link

Bug Report

I seem to be unable to satisfy a Protocol with an attribute that is hinted as another Protocol. The inner element does satisfy the inner protocol as shown by the call to g(). The mypy docs do describe recursive protocols as being supported which while a different thing than this seems to suggest that expecting protocols in general to be usable as hints in other protocols is reasonable.

To Reproduce

https://mypy-play.net/?mypy=latest&python=3.10&gist=62ec93fabc3a77038d6b35840a01863e

from dataclasses import dataclass
from typing import Protocol

class PInner(Protocol):
    x: int

class POuter(Protocol):
    inner: PInner

def f(x: POuter) -> None:
    pass

def g(x: PInner) -> None:
    pass

@dataclass
class Inner:
    x: int

@dataclass
class Outer:
    inner: Inner

inner = Inner(x=3)
outer = Outer(inner=inner)

g(x=outer.inner)

f(x=outer)

Expected Behavior

I expect the code to pass mypy.

Actual Behavior

main.py:29: error: Argument "x" to "f" has incompatible type "Outer"; expected "POuter"
main.py:29: note: Following member(s) of "Outer" have conflicts:
main.py:29: note:     inner: expected "PInner", got "Inner"
Found 1 error in 1 file (checked 1 source file)

Your Environment

  • Mypy version used: 0.961
  • Mypy command-line flags: mypy-play.net default
  • Mypy configuration options from mypy.ini (and other config files): mypy-play.net default
  • Python version used: 3.10
  • Operating system and version: mypy-play.net default
@altendky altendky added the bug mypy got something wrong label Jun 16, 2022
@pranavrajpal
Copy link
Contributor

I think the error is correct. inner in POuter is a mutable attribute, which means that f is allowed to replace x.inner with an object of a different class that still implements the same protocol. Changing POuter to use a readonly property for inner fixes the error.

@altendky
Copy link
Author

It took me a few attempts before I understood your explanation, but it makes sense now and does address both the example and my real case. The real case had three layers of protocols actually so I had to apply the read-only property pattern twice.

Thanks for your time and the explanation.

@altendky
Copy link
Author

For what it's worth, fixing this in my code really made my day. :] Thanks again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong topic-protocols
Projects
None yet
Development

No branches or pull requests

3 participants