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

typed-argument-default-in-stub (PYI011) - false positive when default value intentionally used to infer the default value of a generic #12999

Open
DetachHead opened this issue Aug 20, 2024 · 1 comment
Labels
needs-triage rule Implementing or modifying a lint rule

Comments

@DetachHead
Copy link

DetachHead commented Aug 20, 2024

not sure if this is something that can be determined without type analysis (#3893), but sometimes PYI011 conflicts with pyright's reportInvalidTypeVarUse rule. for example, in the following .pyi file:

# foo.pyi

a: int

def foo[T](value: T | None = a) -> T: ... # error: PYI011
# usage.py

from foo import foo
reveal_type(foo()) # int

if we take ruff's advice and omit the default value here, it prevents type checkers from being able to infer the generic based on the default value, which is why pyright reports an error:

# foo.pyi

a: int

def foo[T](value: T | None = ...) -> T: ... # no ruff error, but now pyright reports reportInvalidTypeVarUse
# usage.py

from foo import foo
reveal_type(foo()) # Any
@Avasam
Copy link

Avasam commented Aug 20, 2024

A couple notes:

Note that assigning a default value to a generic to infer the default generic type is currently not supported in mypy and will result in type Never:

main.py:3: error: Missing return statement  [empty-body]
main.py:3: error: Incompatible default for argument "value" (default has type "int", argument has type "T | None")  [assignment]
main.py:5: note: Revealed type is "Never"

Tracked here: python/mypy#3737 (feel free to upvote, I too hit that issue and wished it worked like in pyright)

Whilst this being flagged by PYI011 is incidental, I'd recommend avoiding that form unless you're writing private stubs (using pyright only), and instead use something like:

from typing import overload

@overload
def foo() -> int: ...
@overload
def foo[T](value: T | None) -> T: ... 

Now as for PYI011 itself, it's more of a convention in typeshed to not bother with non-literal defaults. I don't think there's anything inherently wrong with your example1 (assuming it works in the type-checkers you're interested in). I personally don't think it's a false-positive, you may simply not be interested in the rule for your project.

Footnotes

  1. In your example,

    reveal_type(foo(None))
    

    would be Unknown / Any. But that has no effect on the mypy issue mentioned above or PYI011, so I'll ignore that

@MichaReiser MichaReiser added rule Implementing or modifying a lint rule needs-triage labels Aug 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs-triage rule Implementing or modifying a lint rule
Projects
None yet
Development

No branches or pull requests

3 participants