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

isinstance(x, np.uint64) gives error: Second argument to "isinstance" must be a class or tuple of classes, TypeVar or generic type with type arguments not allowed #3830

Closed
ischurov opened this issue Jan 12, 2023 · 2 comments
Assignees

Comments

@ischurov
Copy link

ischurov commented Jan 12, 2023

Environment data

  • Language Server version: 2023.1.10
  • OS and version: linux x64
  • Python version (and distribution if applicable, e.g. Anaconda): Python 3.10.8 (Anaconda)
  • python.analysis.indexing: true
  • python.analysis.typeCheckingMode: basic

Code Snippet

import numpy as np

def foo(x):
    if not isinstance(x, np.uint64):
        x = np.uint64(x)
    return x

Repro Steps

Type-check the given snippet.

Expected behavior

No errors found.

Actual behavior

The following error is given regarding the expression `isinstance(x, np.uint64)`:
Second argument to "isinstance" must be a class or tuple of classes
  TypeVar or generic type with type arguments not allowed

Additional context

There is a similar fixed issue #2128. I am not sure that it is actually a bug, as np.uint64 is a type alias, but I believe there should be a way to run this `isinstance` without having type error. `mypy` finds no issues in this snippet.
@erictraut
Copy link
Contributor

The isinstance method generates a runtime exception if you attempt to use a specialized generic class:

def foo(x):
    return isinstance(x, list[int])

foo([]) # TypeError

The same is true if you use a type alias:

ListOfInts = list[int]

def foo(x):
    return isinstance(x, ListOfInts)

foo([]) # TypeError

The problem here is that the numpy type stubs are "lying" to the type checker about how the underlying classes are modeled in numpy. The stubs define uint64 as a specialized version of the generic class unsighed integer.

uint64 = unsignedinteger[_64Bit]

I would expect this to generate a runtime TypeError if used with isinstance, but it doesn't. That's because the runtime implementation doesn't use a generic class. Instead, the runtime implementation of uint64 is a proper subclass of unsignedinteger.

>> print(np.uint64.__mro__)
>> (<class 'numpy.uint64'>, <class 'numpy.unsignedinteger'>, <class 'numpy.integer'>, <class 'numpy.number'>, <class 'numpy.generic'>, <class 'object'>)

Pyright (the type checker upon which pylance is built) relies on accurate static type information from the library. In this case, the static type information provided by numpy is unfortunately not correctly modeling the runtime types, which results in this false positive error.

You could file a bug with the numpy maintainers, but I think it's unlikely they would want to make a change here.

You may need to resort to a # type: ignore or a typing.cast call to suppress the static type error.

@ischurov
Copy link
Author

ischurov commented Jan 13, 2023

@erictraut thanks for the elaborate explanation! I reported this issue to the numpy team, let's look what they say.

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