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

self-referential type can't be represented by a Protocol #8486

Closed
glyph opened this issue Mar 3, 2020 · 3 comments
Closed

self-referential type can't be represented by a Protocol #8486

glyph opened this issue Mar 3, 2020 · 3 comments

Comments

@glyph
Copy link

glyph commented Mar 3, 2020

Please provide more information to help us understand the issue:

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

Bug report, I think? Although the usage here is sufficiently sophisticated that it might qualify as a feature.

  • 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.

In trying to work around this issue with datetime.date, I was trying to make a protocol that was date-"ish" and precluded passing a date. But it seemed that anywhere I wanted to accept or return a date-ish object I ran into this problem:

from typing_extensions import Protocol


class Concrete(object):
    def method(self, argument: "Concrete") -> None:
        pass


class Abstract(Protocol):
    def method(self, argument: "Abstract") -> None:
        pass


x: Abstract = Concrete()
  • What is the actual behavior/output?
Incompatible types in assignment (expression has type "Concrete", variable has type "Abstract")

Following member(s) of "Concrete" have conflicts:

Expected:

def method(self, argument: Abstract) -> None

Got:

def method(self, argument: Concrete) -> None
  • What is the behavior/output you expect?

I would expect this to pass typechecking.

  • What are the versions of mypy and Python you are using?

0.761, 3.6.8

  • Do you see the same issue after installing mypy from Git master?

Haven't tried.

  • What are the mypy flags you are using? (For example --strict-optional)
follow_imports=normal

warn_redundant_casts=True
warn_unused_ignores=True
strict_optional=True
strict_equality=True
no_implicit_optional=True
disallow_untyped_defs=True
disallow_any_generics=True
  • If mypy crashed with a traceback, please paste
    the full traceback below.

No tracebacks here.

@hauntsaninja
Copy link
Collaborator

hauntsaninja commented Mar 4, 2020

You should be able to accomplish this by using a TypeVar, eg, the following appears to work for me:

from typing import TypeVar
from typing_extensions import Protocol

T = TypeVar('T')

class Concrete(object):
    def method(self: T, argument: T) -> None:
        pass


class Abstract(Protocol):
    def method(self: T, argument: T) -> None:
        pass


x: Abstract = Concrete()

See also: https://mypy.readthedocs.io/en/stable/more_types.html#advanced-uses-of-self-types

@ilevkivskyi
Copy link
Member

The original error is totally valid since argument types are contravariant, see https://mypy.readthedocs.io/en/stable/generics.html#variance-of-generic-types

@glyph
Copy link
Author

glyph commented Mar 11, 2020

@ilevkivskyi I can't figure out how to formulate the issue that I still have, which is that I can't figure out how to make something that duck-types to a date but not a datetime; there is some level of self-referentiality where this technique breaks down, but I can't figure out exactly where without slogging through the whole date representation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants