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 does not recognize typing.Final #1574

Closed
covuworie opened this issue Jul 20, 2021 · 5 comments
Closed

Pylance does not recognize typing.Final #1574

covuworie opened this issue Jul 20, 2021 · 5 comments
Labels
bug Something isn't working fixed in next version (main) A fix has been implemented and will appear in an upcoming version

Comments

@covuworie
Copy link

covuworie commented Jul 20, 2021

Environment data

Pylance v2021.7.4

  • Language Server version: 2021.7.4 (pyright 209f9621)
  • OS and version: Linux Debian (Python Docker official image slim-buster)
  • Python version: 3.8.2

Expected behaviour

No error as in the following case when Final is omitted:

from dataclasses import dataclass

@dataclass
class MyDataclass:
    name: str = field()

MyDataclass(name="bar")

and second case

from dataclasses import dataclass

@dataclass
class MyDataclass:
    name: str = field()

    @classmethod
    def from_name(cls, name: str) -> MyDataclass:
        instance = cls(name)
        return instance

Actual behaviour

Error:
No parameter named "name" PylancereportGeneralTypeIssues
(constant) name: str

occurs due to the presence of Final as in the following case:

from dataclasses import dataclass
from typing import Final

@dataclass
class MyDataclass:
    name: Final[str] = field()

MyDataclass(name="bar")

and second case

from dataclasses import dataclass
from typing import Final

@dataclass
class MyDataclass:
    name: Final[str] = field()

    @classmethod
    def from_name(cls, name: str) -> MyDataclass:
        instance = cls(name)
        return instance

Error:
Expected 0 positional arguments Pylance(reportGeneralTypeIssues)

These are clearly false-positives and not expected behavior.

Code Snippet / Additional information

Contents of pyrightconfig.json file:

{
    "ignore": [],
    "pythonPlatform": "Linux",
    "pythonVersion": "3.8",
    "typeCheckingMode": "basic",
    "useLibraryCodeForTypes": true,
    "venv": "/opt/venv/bin/python"
}
@erictraut
Copy link
Contributor

erictraut commented Jul 20, 2021

Thanks for the bug report.

It wasn't immediately clear to me whether this was a bug based on the Python documentation. It took a bit of digging and experimentation to convince myself that the current behavior in Pylance is indeed incorrect.

PEP 591 (which introduced Final) says:

Type checkers should infer a final attribute that is initialized in a class body as being a class variable. Variables should not be annotated with both ClassVar and Final.

And PEP 557, which introduced dataclass, says:

If a field is a ClassVar, it is excluded from consideration as a field and is ignored by the Data Class mechanisms.

Consistent with these two statements, Pylance assumed that your use of Final indicated that name was implicitly a ClassVar and should not be considered a dataclass field.

However, after some experimentation, I've confirmed that there is apparently an implied exception to the PEP 591 rule for dataclasses. This exception isn't spelled out in any PEP, and I suspect that it was simply an oversight when dataclass was implemented. In any event, it's too late to change the behavior now without introducing a backward compatibility problem, so we're stuck with the inconsistency.

I've updated the dataclass logic in Pylance to add this exception so the behavior is consistent with the runtime support for dataclass.

@erictraut erictraut added bug Something isn't working fixed in next version (main) A fix has been implemented and will appear in an upcoming version and removed triage labels Jul 20, 2021
@covuworie
Copy link
Author

Hi Eric, thanks for the super quick response, fix and explanation. Very much appreciated. How often are releases of pylance?

There is another issue I want to bring to your attention but I cannot reproduce it in isolation and unfortunately I cannot share my code with you as it's intellectual property. Another error occurs when using the @final decorator from the typing module. The error reads as follows:

Expected class type but received "_F@final"PylancereportGeneralTypeIssues)

I removed use of this decorator from my code as I don't really need it. This seems like a bug to me but I cannot be sure. The code producing this issue looks a little similar to the below (but this only has the issue described above that you have now fixed):

from dataclasses import dataclass
from typing import Final

def from_name(klass: MyDataclass) -> Dict[str, MyDataclass]:
    my_data: Dict[str, MyDataclass] = {"name": MyDataclass(klass.name)}
    return my_data

@final
@dataclass
class MyDataclass:
    name: Final[str] = field()
    age: Final[Optional[int]] = field()

The error shows on the MyDataclass in both Dict type annotations (whether it is a return type, a variable and the same issue happens in a function parameter annotation). Maybe from the error message you have an idea of what is going on even though I cannot reproduce it for you?

@erictraut
Copy link
Contributor

erictraut commented Jul 21, 2021

We typically release a new version once a week on or about Wednesday.

The error message above seems to reference a type variable _F that is used in the scope of a function or class called final. I don't see any TypeVars used in your sample, so there's probably something missing to repro the issue. If you're able to find a repro with a minimal sample, please feel free to open another issue.

@covuworie
Copy link
Author

There are no uses of TypeVar anywhere in my entire codebase. The closest thing I see is use of InitVar in two places in the codebase. I tried to reproduce with that but still no luck.

I will wait for the new release of pylance and try again with that. If I can reproduce then I will submit a new issue. Thanks very much for your help. You can go ahead and close this issue when you are ready.

@jakebailey
Copy link
Member

This issue has been fixed in version 2021.7.5, which we've just released. You can find the changelog here: https://github.com/microsoft/pylance-release/blob/main/CHANGELOG.md#202175-22-july-2021

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working fixed in next version (main) A fix has been implemented and will appear in an upcoming version
Projects
None yet
Development

No branches or pull requests

3 participants