Skip to content

Enum of a NamedTuple-derived type leads to incompatible type error #1745

Closed

Description

@AlexOnAPeak

This code:

from typing import NamedTuple
from enum import Enum

Foo = NamedTuple('Foo', [('bar', int)])

class MyEnum(Foo, Enum):
    CONSTANT = Foo(bar=1)

def f(x):
    # type: (MyEnum) -> None
    pass

f(MyEnum.CONSTANT)

leads to:

error: Argument 1 to "f" has incompatible type "test.MyEnum"; expected "MyEnum"

Activity

  1. gvanrossum commented on Jun 25, 2016

    @gvanrossum
    Member

    I know we have plenty of namedtuple-related issues. But does this code serve a real purpose? Enum has a lot of magic, so does namedtuple -- I'm not sure if we should really be required to make sense of this, and what you're trying to accomplishing with that class.

  2. AlexOnAPeak commented on Jun 28, 2016

    @AlexOnAPeak
    Author

    This is a distilled example of a real-life enum I came across in our code. Not going to get into whether or not having such an enum is a good idea, but we have it and I'm getting mypy errors trying to use it as an argument to a function. The main weirdness is that the error is of the form incompatible type: "fully.qualified.path.to.MyEnum"; expected "MyEnum" which seems fishy.

  3. gvanrossum commented on Jun 28, 2016

    @gvanrossum
    Member

    Note that without the Foo base class you can still access the bar attribute in f() -- use x.value.bar rather than x.bar.

  4. gnprice commented on Aug 9, 2016

    @gnprice
    Collaborator

    This came up again today -- a user hit an error message just as confusing (and with the same structure) as the one in @alexsydell's report, and after some debugging someone else recognized it as this issue.

    In addition to the type-checker issue that we shouldn't be reporting an error here at all, the error message is awfully perplexing and is likely an example of #1582.

  5. added this to the milestone on Aug 11, 2016
  6. elazarg commented on Sep 5, 2016

    @elazarg
    Contributor

    I believe that this is a result of the special casing of both Enum and NamedTuple. It can be special-cased too at subtypes.py:

            right = self.right
    +       if isinstance(right, TupleType) and right.fallback.type.is_enum:
    +           return is_subtype(left, right.fallback)
            if isinstance(right, Instance):
    

    I think that this special casing is justified, but I'm not sure.

  7. added a commit that references this issue on Nov 7, 2016
    bf9cb22
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

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions