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

The inferred argument type is confusing in subclass of logging.FileHandler #3381

Closed
herjiict opened this issue Sep 23, 2022 · 4 comments
Closed
Labels
bug Something isn't working fixed in next version (main) A fix has been implemented and will appear in an upcoming version reference

Comments

@herjiict
Copy link

Environment data

  • Language Server version: 2022.9.30 (pyright df789b5e)
  • OS and version: Windows 11 22000.978 WSL Ubuntu 20.04
  • Python version (& distribution if applicable, e.g. Anaconda): 3.9 (Miniconda3)

Code Snippet

  • Snippet 1
import logging

class MyHandler(logging.FileHandler):
    def __init__(
        self,
        filename,
        mode="a",
        encoding=None,
        delay=False,
        errors=None,
    ) :
        super().__init__(
            filename=filename,
            mode=mode,
            encoding=encoding,
            delay=delay,
            errors=errors,
        )

reveal_type(MyHandler.__init__)
  • Snippet 2
import logging

class MyHandler(logging.FileHandler):
    def __init__(
        self,
        filename=1,
        mode="a",
        encoding=None,
        delay=False,
        errors=None,
    ):
        super().__init__(
            filename="myfile",
            mode=mode,
            encoding=encoding,
            delay=delay,
            errors=errors,
        )

reveal_type(MyHandler.__init__)

Repro Steps

Paste code snippets above in VSCode and see the revealed types.

Expected behavior

In snippet 1, since encoding and errors are inferred to be str | None (instead of Unknown | None), I expect filename inferred StrPath (instead of Unknown).

In snippet 2, filename is expected to be inferred int (instead of StrPath)

Actual behavior

  • Snippet 1
Type of "MyHandler.__init__" is "(self: MyHandler, filename: Unknown, mode: str = "a", encoding: str | None = None, delay: bool = False, errors: str | None = None) -> None"
  • Snippet 2
Type of "MyHandler.__init__" is "(self: MyHandler, filename: str | PathLike[str] = 1, mode: str = "a", encoding: str | None = None, delay: bool = False, errors: str | None = None) -> None"
@erictraut
Copy link
Contributor

Thanks for the bug report. This will be fixed in an upcoming release.

Pyright, the type checker that underlies pylance, uses different techniques to infer method parameter types when they are unannotated.

  1. If the parameter is a self or cls it is inferred to be of type Self or type[Self], respectively.
  2. If the method is overriding a base class method whose parameters are annotated and the signatures match in number, name and parameter type, the parameter types are inherited from the base method.
  3. If the parameter has a default argument value other than None (e.g. a = 0), the parameter type is inferred from the type of the default argument.
  4. If the method is an __init__ and none of the parameters are annotated, the corresponding class is treated as though it is generic, and each of the __init__ parameters is assigned its own type variable. Since instance variables are often assigned values directly from __init__ parameters, this allows pyright to improve its inference of instance variable types in code that contains no annotations. For example:
class Foo:
    def __init__(self, a, b):
        self.a = a
        self.b = b

f = Foo(1, "hi")
reveal_type(f.a) # int
reveal_type(f.b) # str

In the case of parameter filename in your first sample above, pyright was using technique 4 to infer its type, giving it an internal TypeVar type. It should use technique 2, which infers the type StrPath as you expected.

This is addressed in this commit.

@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-needed labels Sep 23, 2022
@heejaechang
Copy link
Contributor

I think we have some eval ordering issue as you can see below. filename will show Unknown until it is evaluated as argument below. I think that is when type is inferred and cached.

eval_order

@erictraut
Copy link
Contributor

@heejaechang, that is unexpected behavior. Should be investigated to see if it's a bug in the hover provider or type evaluator. I recommend opening a new bug since it's not the same issues as the one in this bug report.

@debonte
Copy link
Contributor

debonte commented Sep 29, 2022

This issue has been fixed in prerelease version 2022.9.41, which was released yesterday. You can find the changelog here: CHANGELOG.md

@debonte debonte closed this as completed Sep 29, 2022
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 reference
Projects
None yet
Development

No branches or pull requests

4 participants