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

Error when importing Enum from different file #3546

Closed
twoertwein opened this issue Jun 6, 2022 · 2 comments
Closed

Error when importing Enum from different file #3546

twoertwein opened this issue Jun 6, 2022 · 2 comments
Labels
as designed Not a bug, working as intended

Comments

@twoertwein
Copy link

Describe the bug
Pyright does not report errors, when declaring the enum within the same file where it is being used. When importing the same enum from a different file, pyright reports an error.

To Reproduce

bar.py

from enum import Enum
from typing import Literal

# similar to https://github.com/python/typeshed/pull/7127/files
class _NoDefault(Enum):
    no_default = "NO_DEFAULT"

no_default = _NoDefault.no_default  # Sentinel indicating the default value.
NoDefault = Literal[_NoDefault.no_default]

def test(x: NoDefault = no_default):
    ...

pyright reports no errors for bar.py

foo.py

import bar

reveal_type(bar.NoDefault)
reveal_type(bar.no_default)

def test(x: bar.NoDefault = bar.no_default):
    ...

pyright reports:
3:13 - information: Type of "bar.NoDefault" is "Type[Literal[_NoDefault.no_default]]"
4:13 - information: Type of "bar.no_default" is "_NoDefault"
6:29 - error: Expression of type "_NoDefault" cannot be assigned to parameter of type "NoDefault"

Expected behavior
It seems that pyright has troubles inferring bar.no_default, it should be bar._NoDefault.no_default and not bar._NoDefault.

@twoertwein
Copy link
Author

Changing the lines in bar to.py

NoDefault = Literal[_NoDefault.no_default]
no_default: NoDefault = _NoDefault.no_default  # Sentinel indicating the default value.

avoids this issue.

@erictraut
Copy link
Collaborator

Yes, this behavior is intended. The variable no_default has no type annotation, so its type is inferred. In this case, it has an inferred type of _NoDefault. Locally, its type is narrowed to the type Literal[_NoDefault.no_default] because of the assignment. When you import that variable from another module, the local type narrowing is not applied, so its type is simply NoDefault. If your intent is for no_default to have the type Literal[_NoDefault.no_default], you should annotate it as such.

Even better, if your intent is for this variable to be constant, you should annotate it as Final. When inferring the type of a Final variable, pyright retains the literal type.

no_default: Final = _NoDefault.no_default

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
as designed Not a bug, working as intended
Projects
None yet
Development

No branches or pull requests

2 participants