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

None alias for NoneType doesn't work on generic bound when using type of the generic #11275

Closed
DetachHead opened this issue Oct 6, 2021 · 13 comments
Labels
bug mypy got something wrong

Comments

@DetachHead
Copy link
Contributor

DetachHead commented Oct 6, 2021

from typing import TypeVar
from types import NoneType

T = TypeVar("T", bound=None)
def foo(value: type[T]) -> None: ...

U = TypeVar("U", bound=NoneType)
def bar(value: type[U]) -> None: ...

foo(NoneType) #error: Value of type variable "T" of "foo" cannot be "NoneType"
bar(NoneType) #no error

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

@DetachHead DetachHead added the bug mypy got something wrong label Oct 6, 2021
@KotlinIsland
Copy link
Contributor

from typing import TypeVar, Generic
from types import NoneType

T = TypeVar("T", bound=None)
def foo(a: T, b: type[T]) -> None: ...

U = TypeVar("U", bound=NoneType)
def bar(a: U, b: type[U]) -> None: ...

foo(None, NoneType) #Value of type variable "T" of "foo" cannot be "Optional[NoneType]"
bar(None, NoneType) #Value of type variable "U" of "bar" cannot be "Optional[NoneType]"

This is absolute whack

@KotlinIsland
Copy link
Contributor

I think this might be related to the fact that the stubs define NoneType as a subtype of the type of None

@KotlinIsland
Copy link
Contributor

KotlinIsland commented Oct 6, 2021

wait, not it's not, it's completely unrelated to None

@final
class NoneType:
    def __bool__(self) -> Literal[False]: ...

LOOOOOOL!!

@erictraut
Copy link

I wouldn't expect this to work. The types.NoneType symbol has no type relationship to builtins.None, just as types.UnionType has no type relationship to typing.Union. If you want to refer to the type of the object builtins.None, you can use the expression type(None).

@KotlinIsland
Copy link
Contributor

at runtime NoneType is type(None) but typing.Union and types.UnionType are completely different constructs.

@KotlinIsland
Copy link
Contributor

T = TypeVar("T", bound=type(None)) # error: TypeVar "bound" must be a type

@erictraut
Copy link

from typing import TypeVar

T = TypeVar("T", bound=None)

def foo(value: type[T]) -> None:
    ...

U = TypeVar("U", bound=type[None])

def bar(value: type[U]) -> None:
    ...

foo(type(None))
bar(type(None)) # Error

@KotlinIsland
Copy link
Contributor

type[None], that's a good one :)

@KotlinIsland
Copy link
Contributor

KotlinIsland commented Oct 6, 2021

What a mess lmao.

in a type context, None really means type(None). So when you say type[None] I think in the type realm it is type[type(None)].

@sobolevn
Copy link
Member

sobolevn commented Oct 6, 2021

I think that we need better docs for import types usages.
Today I got another question in our user-group about this case:

from types import FunctionType

def a(): pass

b: FunctionType = a

It also does not work. It should be using typing.Callable instead.

So, I will send a PR with some docs on why it is not support and what to do instead.

@JelleZijlstra
Copy link
Member

NoneType should never be used in types. I'd welcome PRs improving documentation for this.

The original example doesn't make much sense to me: None cannot be subclassed, so bounding on None or NoneType isn't useful.

@DetachHead
Copy link
Contributor Author

The original example doesn't make much sense to me

@JelleZijlstra it's just a minimal example. My actual use case is a class with generics bounded to a union of some class and None, where the generics need to be reified at runtime. The only way I could figure out how to do it was like this

T = TypeVar("T", bound=Foo | NoneType)

class Bar(Generic[T]):
    t: type[T]

bar = Bar(NoneType)

While trying to do this was when I found out that NoneType doesn't work how I thought it does. I agree with you and @KotlinIsland that it's extremely misleading

@KotlinIsland
Copy link
Contributor

KotlinIsland commented Oct 7, 2021

Pretty sure this would fix things: python/typeshed#6125

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

Successfully merging a pull request may close this issue.

5 participants