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

Unsupported type Type[...] error when instantiating NamedTuple from class variable #4300

Closed
joshstaiger opened this issue Nov 30, 2017 · 23 comments
Labels
bug mypy got something wrong priority-0-high

Comments

@joshstaiger
Copy link

Run mypy 0.550 on the following code

from typing import NamedTuple, Type, cast

class A(NamedTuple): ...

A1: Type[A] = A  # no error
A2: Type[A] = A  # error: Unsupported type Type["A"]
A2()

def j(cls: Type[A]) -> None:  # error: Unsupported type Type["A"]
    cls()

class B(): ... # no error

B1: Type[B] = B
B1()

I see error: Unsupported type Type["A"] on the lines for A2 and def j, but not in other places, as indicated.

I'm probably hitting an edge case for NamedTuple here.

@gvanrossum gvanrossum added the bug mypy got something wrong label Dec 1, 2017
@gvanrossum
Copy link
Member

The really odd thing is that removing the A2() call makes the error go away. I have a feeling that the error is really for that call but is given the line number for the definition of A2 instead of the call line.

@ilevkivskyi
Copy link
Member

FWIW I have seen a very similar problem when working on self types in generic classes. Hopefully, my fix will also fix this one.

@mitar
Copy link

mitar commented Dec 24, 2017

One more example:

import typing

T = typing.TypeVar('T')
L = typing.TypeVar('L', bound='List')

class List(typing.List[T]):
    def __init__(self, iterable: typing.Iterable = ()) -> None:
        super().__init__(iterable)

    def copy(self: L) -> L:
        return type(self)(self)

@mitar
Copy link

mitar commented Dec 24, 2017

But this works:

import typing

L = typing.TypeVar('L', bound='List')

class List(typing.List):
    def __init__(self, iterable: typing.Iterable = ()) -> None:
        super().__init__(iterable)

    def copy(self: L) -> L:
        return type(self)(self)

So if I do not use T in class List(typing.List[T]):.

@ilevkivskyi
Copy link
Member

It looks like instantiating (calling) Type[X] sometimes has problems if X is:

  • a tuple type
  • a generic type
  • type variable with a bound to the above

Maybe there are some more details.

@mitar
Copy link

mitar commented Dec 24, 2017

And Type[X] is called somewhere internally?

@mitar
Copy link

mitar commented Dec 25, 2017

Is there any way to silence this error?

@ilevkivskyi
Copy link
Member

Is there any way to silence this error?

Hm... this is the problematic part. It looks like it is impossible to silence the error if the Type[...] comes from type(self) or similar. I am therefore setting priority to high (anyway I wanted to work on this around New Year).

@mitar
Copy link

mitar commented Dec 25, 2017

The issue is also that this is not available: #626

@elliott-beach
Copy link
Contributor

elliott-beach commented Jan 4, 2018

There's a test (by @gvanrossum) describing that you can't take the type of a Tuple from when Type[C] was implemented:

[case testTypeUsingTypeCErrorUnsupportedType]
from typing import Type, Tuple
def foo(arg: Type[Tuple[int]]): # E: Unsupported type Type["Tuple[int]"]
arg()
[builtins fixtures/tuple.pyi]
[out]

Since the above is basically taking Type[tuple], it seems like that is behavior is intended, or at least already known. testTypeUsingTypeCErrorUnsupportedType covers the same thing.

The behavior is basically caused by there being no case for TupleType in analyze_type_callee_callee, which builds the new type object:

def analyze_type_type_callee(self, item: Type, context: Context) -> Type:
.

The error with generics is related to the same function and also seems like a deliberate choice by @gvanrossum (https://github.com/python/mypy/blob/master/mypy/checkexpr.p#L672-L673).

@gvanrossum
Copy link
Member

Note the difference between tuple and Tuple. PEP 484 forbids Type[Tuple[...]] but allows (implicitly) Type[tuple]. Since NamedTuple is closest to Tuple[...] (it has a fixed set of fields) it stands to reason that it's disallowed as well.

IMO the only real issue is that

A1: Type[A]

doesn't give an error unless you try to call A1(), and that it then puts the error on the definition of A1 rather than at the call site. Something's definitely fishy there.

@JukkaL
Copy link
Collaborator

JukkaL commented Jan 5, 2018

Type[A] if A is a named tuple seems well-defined, unlike Type[Tuple[...]], since there is a specific type object A (and similarly for subclasses of A). There is no type object that is specific to Tuple[int, str], for example (it's just tuple which is shared between all tuple types).

@gvanrossum
Copy link
Member

gvanrossum commented Jan 5, 2018 via email

@elliott-beach
Copy link
Contributor

Because namedtuple is a normal subclass of tuple, I think you could say the behavior should be that Type[A] where A is a subclass of tuple should work.

Oddly (to me), this behavior does work when simply subclassing tuple, e.g.,

class MyTuple(tuple):
    pass
A: Type[MyTuple] = MyTuple
A((1,2))  # no error

This happens because MyTuple is an Instance whereas a namedtuple type is a TupleType.
So the special type of NamedTuple is the only case that is handled incorrectly.

@gvanrossum
Copy link
Member

There's nothing "normal" about NamedTuple. :-(

Note that when you subclass tuple, it ends up being a variable-length tuple that's homogeneously typed (all items have the same type). Both NamedTuple and Tuple are fixed-length tuples with heterogeneous types (each item has its own type). That's the reason they are special.

@elliott-beach
Copy link
Contributor

Sorry, thanks for explaining that.

@ilevkivskyi ilevkivskyi self-assigned this Feb 21, 2018
@ilevkivskyi
Copy link
Member

One minor comment to future self: the formatting for this error is also wrong it looks like

__main__.py: error: Unsupported type Type["L"]

instead of

__main__.py: error: Unsupported type "Type[L]"

@OJFord
Copy link

OJFord commented Apr 19, 2018

It also doesn't feature a line number, so though I see:

file.py: error: Unsupported type Type["None"]

I'm having a hard time tracking down the cause... this particular file doesn't even import Type.

edit: In case it's of use to someone else, in my case the cause was an assignment like thing = type(other). type(other) was certainly not None (nor type(None)).

@gvanrossum
Copy link
Member

We should at the very least add the line number to the error. This is already a high priority issue.

@ilevkivskyi
Copy link
Member

All the original examples now pass correctly, the only remaining problem is that now reasonably invalid (from mypy's point of view) things like type((1, 2))() cause an error that has wrong formatting and don't have a line number:

test.py: error: Unsupported type Type["Tuple[int, int]"]

@ilevkivskyi
Copy link
Member

A similar example just came in #7086.

@ilevkivskyi ilevkivskyi removed their assignment Dec 9, 2019
lovasoa added a commit to heckad/marshmallow_dataclass that referenced this issue Apr 21, 2020
@lovasoa
Copy link

lovasoa commented Apr 21, 2020

Hello ! Any news on this ?
This seems to be a blocker for lovasoa/marshmallow_dataclass#77

@JukkaL
Copy link
Collaborator

JukkaL commented Jun 25, 2020

This seems to work now using the latest git master.

@JukkaL JukkaL closed this as completed Jun 25, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong priority-0-high
Projects
None yet
Development

No branches or pull requests

8 participants