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

Pylance infers Literal[] type where it is not intended #4633

Closed
tthommes opened this issue Jul 20, 2023 · 7 comments
Closed

Pylance infers Literal[] type where it is not intended #4633

tthommes opened this issue Jul 20, 2023 · 7 comments
Assignees
Labels
needs repro Issue has not been reproduced yet

Comments

@tthommes
Copy link

tthommes commented Jul 20, 2023

When I try to pass an Enum-value e.g.

class MyEnum(Enum):
  A = 0x1
  B = 0x2

to a function parameter type-hinted as Integral e.g.

from numbers import Integral
def myfunc(a: Integral):
  pass

myfunc(MyEnum.A.value)

pylance infers Literal[] for the Enum-value and complains about incompatibility.

Originally posted by @tthommes in #697 (comment)

There has been a bug, fixed three years ago, that seems to be the same issue. When I back-port my Pylance-Version to that one, the here described issue is gone. So I suppose the bug was somehow "resurrected".

@github-actions github-actions bot added the needs repro Issue has not been reproduced yet label Jul 20, 2023
@erictraut
Copy link
Contributor

erictraut commented Jul 20, 2023

This behavior is correct from a type checking perspective. An int value is not type compatible with the class Integral.

x: Integral = 0 # Type error

Not surprisingly, mypy generates the same error in this case.

The abstract numeric types defined in numbers have never been integrated into the static type system for Python. There has been much discussion about how this might be done, but no serious proposals have been put forth by the typing community.

The recommended workaround is to avoid the use of abstract numeric types and use the standard builtin types like int.

(Note: This has nothing to do with the other bug that was referenced above. They're completely unrelated. It also has nothing to do with type inference or literals, as the title implies.)

@erictraut
Copy link
Contributor

Another workaround, if you really want to use Integral, is to define your own custom type that derives from both int and Integral and use that in your enum definition.

class MyInt(int, Integral):
    pass


class MyEnum(Enum):
    A = MyInt(0x1)
    B = MyInt(0x2)

@tthommes
Copy link
Author

thanks for the quick response. The first and recommended workaround works fine.
With the second workaround I however get "Cannot instanciate abstract class MyInt" which is probably due to the shortness of the type-definition...

@erictraut
Copy link
Contributor

Are you receiving the "Cannot instanciate abstract class" error from the Python interpreter or VS Code? It runs fine for me. Here's the full sample:

from enum import Enum
from numbers import Integral

class MyInt(int, Integral):
    pass

class MyEnum(Enum):
    A = MyInt(0x1)
    B = MyInt(0x2)

def myfunc(a: Integral):
    pass

myfunc(MyEnum.A.value)

which however is probably not an issue of Pylance but rather the numbers module?

The types in the numbers module predate static typing in Python. The definitions for these types have never been updated to work with the static type system. They should probably be changed from abstract (nominal) classes to protocols (structural types). Because they're defined as nominal, they must appear within the class hierarchy of a given class for a type checker to consider them "type compatible". Since int doesn't have Integral in its class hierarchy, a static type checker will necessarily see the two as incompatible by the rules of the Python static type system.

@tthommes
Copy link
Author

tthommes commented Jul 20, 2023

Thanks for the good explanation. The abstract class error is reported by Pylance in VS Code:

Cannot instantiate abstract class "MyInt"
  "Number.__hash__" is abstract Pylance(reportGeneralTypeIssues)

@erictraut
Copy link
Contributor

The abstract class error is reported by Pylance in VS Code

Looks like you're using strict-mode type checking with the latest production version of Pylance. If you use the latest prerelease version of Pylance, this issue doesn't occur. That's because the prerelease version of Pylance contains a newer version of the typeshed stubs, and a small change was made recently in these stubs to include __hash__ in the definition of the int class.

@rchiodo
Copy link
Contributor

rchiodo commented Jul 20, 2023

Closing as this is fixed in prerelease version 2023.7.31.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs repro Issue has not been reproduced yet
Projects
None yet
Development

No branches or pull requests

4 participants