mirror of
https://github.com/astral-sh/ruff.git
synced 2025-11-18 19:41:34 +00:00
[ty] Understand legacy and PEP 695 ParamSpec (#21139)
## Summary This PR adds support for understanding the legacy definition and PEP 695 definition for `ParamSpec`. This is still very initial and doesn't really implement any of the semantics. Part of https://github.com/astral-sh/ty/issues/157 ## Test Plan Add mdtest cases. ## Ecosystem analysis Most of the diagnostics in `starlette` are due to the fact that ty now understands `ParamSpec` is not a `Todo` type, so the assignability check fails. The code looks something like: ```py class _MiddlewareFactory(Protocol[P]): def __call__(self, app: ASGIApp, /, *args: P.args, **kwargs: P.kwargs) -> ASGIApp: ... # pragma: no cover class Middleware: def __init__( self, cls: _MiddlewareFactory[P], *args: P.args, **kwargs: P.kwargs, ) -> None: self.cls = cls self.args = args self.kwargs = kwargs # ty complains that `ServerErrorMiddleware` is not assignable to `_MiddlewareFactory[P]` Middleware(ServerErrorMiddleware, handler=error_handler, debug=debug) ``` There are multiple diagnostics where there's an attribute access on the `Wrapped` object of `functools` which Pyright also raises: ```py from functools import wraps def my_decorator(f): @wraps(f) def wrapper(*args, **kwds): return f(*args, **kwds) # Pyright: Cannot access attribute "__signature__" for class "_Wrapped[..., Unknown, ..., Unknown]" Attribute "__signature__" is unknown [reportAttributeAccessIssue] # ty: Object of type `_Wrapped[Unknown, Unknown, Unknown, Unknown]` has no attribute `__signature__` [unresolved-attribute] wrapper.__signature__ return wrapper ``` There are additional diagnostics that is due to the assignability checks failing because ty now infers the `ParamSpec` instead of using the `Todo` type which would always succeed. This results in a few `no-matching-overload` diagnostics because the assignability checks fail. There are a few diagnostics related to https://github.com/astral-sh/ty/issues/491 where there's a variable which is either a bound method or a variable that's annotated with `Callable` that doesn't contain the instance as the first parameter. Another set of (valid) diagnostics are where the code hasn't provided all the type variables. ty is now raising diagnostics for these because we include `ParamSpec` type variable in the signature. For example, `staticmethod[Any]` which contains two type variables.
This commit is contained in:
parent
132d10fb6f
commit
cb2e277482
16 changed files with 684 additions and 146 deletions
163
crates/ty/docs/rules.md
generated
163
crates/ty/docs/rules.md
generated
|
|
@ -39,7 +39,7 @@ def test(): -> "int":
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20call-non-callable" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L117" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L118" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -63,7 +63,7 @@ Calling a non-callable object will raise a `TypeError` at runtime.
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-argument-forms" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L161" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L162" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -95,7 +95,7 @@ f(int) # error
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-declarations" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L187" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L188" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -126,7 +126,7 @@ a = 1
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-metaclass" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L212" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L213" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -158,7 +158,7 @@ class C(A, B): ...
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20cyclic-class-definition" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L238" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L239" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -190,7 +190,7 @@ class B(A): ...
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20duplicate-base" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L303" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L304" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -217,7 +217,7 @@ class B(A, A): ...
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.12">0.0.1-alpha.12</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20duplicate-kw-only" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L324" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L325" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -329,7 +329,7 @@ def test(): -> "Literal[5]":
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20inconsistent-mro" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L528" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L529" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -359,7 +359,7 @@ class C(A, B): ...
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20index-out-of-bounds" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L552" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L553" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -385,7 +385,7 @@ t[3] # IndexError: tuple index out of range
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.12">0.0.1-alpha.12</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20instance-layout-conflict" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L356" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L357" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -474,7 +474,7 @@ an atypical memory layout.
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-argument-type" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L606" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L607" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -501,7 +501,7 @@ func("foo") # error: [invalid-argument-type]
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-assignment" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L646" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L647" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -529,7 +529,7 @@ a: int = ''
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-attribute-access" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1757" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1782" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -563,7 +563,7 @@ C.instance_var = 3 # error: Cannot assign to instance variable
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.19">0.0.1-alpha.19</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-await" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L668" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L669" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -599,7 +599,7 @@ asyncio.run(main())
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-base" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L698" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L699" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -623,7 +623,7 @@ class A(42): ... # error: [invalid-base]
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-context-manager" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L749" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L750" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -650,7 +650,7 @@ with 1:
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-declaration" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L770" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L771" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -679,7 +679,7 @@ a: str
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-exception-caught" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L793" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L794" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -723,7 +723,7 @@ except ZeroDivisionError:
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-generic-class" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L829" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L830" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -756,7 +756,7 @@ class C[U](Generic[T]): ...
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.17">0.0.1-alpha.17</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-key" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L573" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L574" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -795,7 +795,7 @@ carol = Person(name="Carol", age=25) # typo!
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-legacy-type-variable" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L855" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L856" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -830,7 +830,7 @@ def f(t: TypeVar("U")): ...
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-metaclass" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L904" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L929" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -864,7 +864,7 @@ class B(metaclass=f): ...
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.19">0.0.1-alpha.19</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-named-tuple" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L502" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L503" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -896,7 +896,7 @@ TypeError: can only inherit from a NamedTuple type and Generic
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-overload" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L931" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L956" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -946,7 +946,7 @@ def foo(x: int) -> int: ...
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-parameter-default" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1030" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1055" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -966,13 +966,44 @@ weakens a type checker's ability to accurately reason about your code.
|
|||
def f(a: int = ''): ...
|
||||
```
|
||||
|
||||
## `invalid-paramspec`
|
||||
|
||||
<small>
|
||||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-paramspec" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L884" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
**What it does**
|
||||
|
||||
Checks for the creation of invalid `ParamSpec`s
|
||||
|
||||
**Why is this bad?**
|
||||
|
||||
There are several requirements that you must follow when creating a `ParamSpec`.
|
||||
|
||||
**Examples**
|
||||
|
||||
```python
|
||||
from typing import ParamSpec
|
||||
|
||||
P1 = ParamSpec("P1") # okay
|
||||
P2 = ParamSpec("S2") # error: ParamSpec name must match the variable it's assigned to
|
||||
```
|
||||
|
||||
**References**
|
||||
|
||||
- [Typing spec: ParamSpec](https://typing.python.org/en/latest/spec/generics.html#paramspec)
|
||||
|
||||
## `invalid-protocol`
|
||||
|
||||
<small>
|
||||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-protocol" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L438" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L439" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -1006,7 +1037,7 @@ TypeError: Protocols can only inherit from other protocols, got <class 'int'>
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-raise" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1050" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1075" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -1055,7 +1086,7 @@ def g():
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-return-type" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L627" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L628" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -1080,7 +1111,7 @@ def func() -> int:
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-super-argument" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1093" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1118" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -1138,7 +1169,7 @@ TODO #14889
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.6">0.0.1-alpha.6</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-alias-type" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L883" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L908" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -1165,7 +1196,7 @@ NewAlias = TypeAliasType(get_name(), int) # error: TypeAliasType name mus
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-checking-constant" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1132" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1157" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -1195,7 +1226,7 @@ TYPE_CHECKING = ''
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-form" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1156" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1181" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -1225,7 +1256,7 @@ b: Annotated[int] # `Annotated` expects at least two arguments
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.11">0.0.1-alpha.11</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-guard-call" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1208" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1233" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -1259,7 +1290,7 @@ f(10) # Error
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.11">0.0.1-alpha.11</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-guard-definition" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1180" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1205" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -1293,7 +1324,7 @@ class C:
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-variable-constraints" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1236" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1261" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -1328,7 +1359,7 @@ T = TypeVar('T', bound=str) # valid bound TypeVar
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20missing-argument" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1265" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1290" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -1353,7 +1384,7 @@ func() # TypeError: func() missing 1 required positional argument: 'x'
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.20">0.0.1-alpha.20</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20missing-typed-dict-key" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1858" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1883" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -1386,7 +1417,7 @@ alice["age"] # KeyError
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20no-matching-overload" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1284" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1309" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -1415,7 +1446,7 @@ func("string") # error: [no-matching-overload]
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20non-subscriptable" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1307" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1332" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -1439,7 +1470,7 @@ Subscripting an object that does not support it will raise a `TypeError` at runt
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20not-iterable" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1325" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1350" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -1465,7 +1496,7 @@ for i in 34: # TypeError: 'int' object is not iterable
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20parameter-already-assigned" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1376" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1401" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -1492,7 +1523,7 @@ f(1, x=2) # Error raised here
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.22">0.0.1-alpha.22</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20positional-only-parameter-as-kwarg" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1611" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1636" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -1550,7 +1581,7 @@ def test(): -> "int":
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20static-assert-error" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1733" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1758" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -1580,7 +1611,7 @@ static_assert(int(2.0 * 3.0) == 6) # error: does not have a statically known tr
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20subclass-of-final-class" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1467" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1492" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -1609,7 +1640,7 @@ class B(A): ... # Error raised here
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20too-many-positional-arguments" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1512" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1537" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -1636,7 +1667,7 @@ f("foo") # Error raised here
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20type-assertion-failure" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1490" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1515" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -1664,7 +1695,7 @@ def _(x: int):
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unavailable-implicit-super-arguments" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1533" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1558" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -1710,7 +1741,7 @@ class A:
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unknown-argument" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1590" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1615" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -1737,7 +1768,7 @@ f(x=1, y=2) # Error raised here
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-attribute" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1632" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1657" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -1765,7 +1796,7 @@ A().foo # AttributeError: 'A' object has no attribute 'foo'
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-import" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1654" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1679" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -1790,7 +1821,7 @@ import foo # ModuleNotFoundError: No module named 'foo'
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-reference" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1673" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1698" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -1815,7 +1846,7 @@ print(x) # NameError: name 'x' is not defined
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-bool-conversion" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1345" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1370" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -1852,7 +1883,7 @@ b1 < b2 < b1 # exception raised here
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-operator" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1692" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1717" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -1880,7 +1911,7 @@ A() + A() # TypeError: unsupported operand type(s) for +: 'A' and 'A'
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20zero-stepsize-in-slice" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1714" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1739" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -1905,7 +1936,7 @@ l[1:10:0] # ValueError: slice step cannot be zero
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.20">0.0.1-alpha.20</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20ambiguous-protocol-member" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L467" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L468" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -1946,7 +1977,7 @@ class SubProto(BaseProto, Protocol):
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.16">0.0.1-alpha.16</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20deprecated" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L282" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L283" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -2034,7 +2065,7 @@ a = 20 / 0 # type: ignore
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.22">0.0.1-alpha.22</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-missing-attribute" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1397" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1422" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -2062,7 +2093,7 @@ A.c # AttributeError: type object 'A' has no attribute 'c'
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.22">0.0.1-alpha.22</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-missing-implicit-call" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L135" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L136" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -2094,7 +2125,7 @@ A()[0] # TypeError: 'A' object is not subscriptable
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.22">0.0.1-alpha.22</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-missing-import" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1419" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1444" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -2126,7 +2157,7 @@ from module import a # ImportError: cannot import name 'a' from 'module'
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20redundant-cast" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1785" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1810" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -2153,7 +2184,7 @@ cast(int, f()) # Redundant
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20undefined-reveal" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1572" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1597" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -2177,7 +2208,7 @@ reveal_type(1) # NameError: name 'reveal_type' is not defined
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.15">0.0.1-alpha.15</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-global" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1806" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1831" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -2235,7 +2266,7 @@ def g():
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.7">0.0.1-alpha.7</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-base" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L716" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L717" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -2274,7 +2305,7 @@ class D(C): ... # error: [unsupported-base]
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.22">0.0.1-alpha.22</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20useless-overload-body" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L974" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L999" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -2337,7 +2368,7 @@ def foo(x: int | str) -> int | str:
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'ignore'."><code>ignore</code></a> ·
|
||||
Preview (since <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a>) ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20division-by-zero" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L264" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L265" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
@ -2361,7 +2392,7 @@ Dividing by zero raises a `ZeroDivisionError` at runtime.
|
|||
Default level: <a href="../rules.md#rule-levels" title="This lint has a default level of 'ignore'."><code>ignore</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unresolved-reference" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1445" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1470" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -276,10 +276,20 @@ mod tests {
|
|||
"#,
|
||||
);
|
||||
|
||||
// TODO: Goto type definition currently doesn't work for type param specs
|
||||
// because the inference doesn't support them yet.
|
||||
// This snapshot should show a single target pointing to `T`
|
||||
assert_snapshot!(test.goto_type_definition(), @"No type definitions found");
|
||||
assert_snapshot!(test.goto_type_definition(), @r"
|
||||
info[goto-type-definition]: Type definition
|
||||
--> main.py:2:14
|
||||
|
|
||||
2 | type Alias[**P = [int, str]] = Callable[P, int]
|
||||
| ^
|
||||
|
|
||||
info: Source
|
||||
--> main.py:2:41
|
||||
|
|
||||
2 | type Alias[**P = [int, str]] = Callable[P, int]
|
||||
| ^
|
||||
|
|
||||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -1633,11 +1633,12 @@ def ab(a: int, *, c: int):
|
|||
"#,
|
||||
);
|
||||
|
||||
// TODO: This should be `P@Alias (<variance>)`
|
||||
assert_snapshot!(test.hover(), @r"
|
||||
@Todo
|
||||
typing.ParamSpec
|
||||
---------------------------------------------
|
||||
```python
|
||||
@Todo
|
||||
typing.ParamSpec
|
||||
```
|
||||
---------------------------------------------
|
||||
info[hover]: Hovered content is
|
||||
|
|
|
|||
|
|
@ -307,8 +307,9 @@ Using a `ParamSpec` in a `Callable` annotation:
|
|||
from typing_extensions import Callable
|
||||
|
||||
def _[**P1](c: Callable[P1, int]):
|
||||
reveal_type(P1.args) # revealed: @Todo(ParamSpec)
|
||||
reveal_type(P1.kwargs) # revealed: @Todo(ParamSpec)
|
||||
# TODO: Should reveal `ParamSpecArgs` and `ParamSpecKwargs`
|
||||
reveal_type(P1.args) # revealed: @Todo(ParamSpecArgs / ParamSpecKwargs)
|
||||
reveal_type(P1.kwargs) # revealed: @Todo(ParamSpecArgs / ParamSpecKwargs)
|
||||
|
||||
# TODO: Signature should be (**P1) -> int
|
||||
reveal_type(c) # revealed: (...) -> int
|
||||
|
|
|
|||
|
|
@ -21,8 +21,9 @@ def f(*args: Unpack[Ts]) -> tuple[Unpack[Ts]]:
|
|||
|
||||
def g() -> TypeGuard[int]: ...
|
||||
def i(callback: Callable[Concatenate[int, P], R_co], *args: P.args, **kwargs: P.kwargs) -> R_co:
|
||||
reveal_type(args) # revealed: tuple[@Todo(Support for `typing.ParamSpec`), ...]
|
||||
reveal_type(kwargs) # revealed: dict[str, @Todo(Support for `typing.ParamSpec`)]
|
||||
# TODO: Should reveal a type representing `P.args` and `P.kwargs`
|
||||
reveal_type(args) # revealed: tuple[@Todo(ParamSpecArgs / ParamSpecKwargs), ...]
|
||||
reveal_type(kwargs) # revealed: dict[str, @Todo(ParamSpecArgs / ParamSpecKwargs)]
|
||||
return callback(42, *args, **kwargs)
|
||||
|
||||
class Foo:
|
||||
|
|
|
|||
|
|
@ -26,9 +26,12 @@ reveal_type(generic_context(SingleTypevar))
|
|||
# revealed: tuple[T@MultipleTypevars, S@MultipleTypevars]
|
||||
reveal_type(generic_context(MultipleTypevars))
|
||||
|
||||
# TODO: support `ParamSpec`/`TypeVarTuple` properly (these should not reveal `None`)
|
||||
reveal_type(generic_context(SingleParamSpec)) # revealed: None
|
||||
reveal_type(generic_context(TypeVarAndParamSpec)) # revealed: None
|
||||
# revealed: tuple[P@SingleParamSpec]
|
||||
reveal_type(generic_context(SingleParamSpec))
|
||||
# revealed: tuple[P@TypeVarAndParamSpec, T@TypeVarAndParamSpec]
|
||||
reveal_type(generic_context(TypeVarAndParamSpec))
|
||||
|
||||
# TODO: support `TypeVarTuple` properly (these should not reveal `None`)
|
||||
reveal_type(generic_context(SingleTypeVarTuple)) # revealed: None
|
||||
reveal_type(generic_context(TypeVarAndTypeVarTuple)) # revealed: None
|
||||
```
|
||||
|
|
|
|||
159
crates/ty_python_semantic/resources/mdtest/paramspec.md
Normal file
159
crates/ty_python_semantic/resources/mdtest/paramspec.md
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
# `ParamSpec`
|
||||
|
||||
## Definition
|
||||
|
||||
### Valid
|
||||
|
||||
```py
|
||||
from typing import ParamSpec
|
||||
|
||||
P = ParamSpec("P")
|
||||
reveal_type(type(P)) # revealed: <class 'ParamSpec'>
|
||||
reveal_type(P) # revealed: typing.ParamSpec
|
||||
reveal_type(P.__name__) # revealed: Literal["P"]
|
||||
```
|
||||
|
||||
The paramspec name can also be provided as a keyword argument:
|
||||
|
||||
```py
|
||||
from typing import ParamSpec
|
||||
|
||||
P = ParamSpec(name="P")
|
||||
reveal_type(P.__name__) # revealed: Literal["P"]
|
||||
```
|
||||
|
||||
### Must be directly assigned to a variable
|
||||
|
||||
```py
|
||||
from typing import ParamSpec
|
||||
|
||||
P = ParamSpec("P")
|
||||
# error: [invalid-paramspec]
|
||||
P1: ParamSpec = ParamSpec("P1")
|
||||
|
||||
# error: [invalid-paramspec]
|
||||
tuple_with_typevar = ("foo", ParamSpec("W"))
|
||||
reveal_type(tuple_with_typevar[1]) # revealed: ParamSpec
|
||||
```
|
||||
|
||||
```py
|
||||
from typing_extensions import ParamSpec
|
||||
|
||||
T = ParamSpec("T")
|
||||
# error: [invalid-paramspec]
|
||||
P1: ParamSpec = ParamSpec("P1")
|
||||
|
||||
# error: [invalid-paramspec]
|
||||
tuple_with_typevar = ("foo", ParamSpec("P2"))
|
||||
reveal_type(tuple_with_typevar[1]) # revealed: ParamSpec
|
||||
```
|
||||
|
||||
### `ParamSpec` parameter must match variable name
|
||||
|
||||
```py
|
||||
from typing import ParamSpec
|
||||
|
||||
P1 = ParamSpec("P1")
|
||||
|
||||
# error: [invalid-paramspec]
|
||||
P2 = ParamSpec("P3")
|
||||
```
|
||||
|
||||
### Accepts only a single `name` argument
|
||||
|
||||
> The runtime should accept bounds and covariant and contravariant arguments in the declaration just
|
||||
> as typing.TypeVar does, but for now we will defer the standardization of the semantics of those
|
||||
> options to a later PEP.
|
||||
|
||||
```py
|
||||
from typing import ParamSpec
|
||||
|
||||
# error: [invalid-paramspec]
|
||||
P1 = ParamSpec("P1", bound=int)
|
||||
# error: [invalid-paramspec]
|
||||
P2 = ParamSpec("P2", int, str)
|
||||
# error: [invalid-paramspec]
|
||||
P3 = ParamSpec("P3", covariant=True)
|
||||
# error: [invalid-paramspec]
|
||||
P4 = ParamSpec("P4", contravariant=True)
|
||||
```
|
||||
|
||||
### Defaults
|
||||
|
||||
```toml
|
||||
[environment]
|
||||
python-version = "3.13"
|
||||
```
|
||||
|
||||
The default value for a `ParamSpec` can be either a list of types, `...`, or another `ParamSpec`.
|
||||
|
||||
```py
|
||||
from typing import ParamSpec
|
||||
|
||||
P1 = ParamSpec("P1", default=[int, str])
|
||||
P2 = ParamSpec("P2", default=...)
|
||||
P3 = ParamSpec("P3", default=P2)
|
||||
```
|
||||
|
||||
Other values are invalid.
|
||||
|
||||
```py
|
||||
# error: [invalid-paramspec]
|
||||
P4 = ParamSpec("P4", default=int)
|
||||
```
|
||||
|
||||
### PEP 695
|
||||
|
||||
```toml
|
||||
[environment]
|
||||
python-version = "3.12"
|
||||
```
|
||||
|
||||
#### Valid
|
||||
|
||||
```py
|
||||
def foo1[**P]() -> None:
|
||||
reveal_type(P) # revealed: typing.ParamSpec
|
||||
|
||||
def foo2[**P = ...]() -> None:
|
||||
reveal_type(P) # revealed: typing.ParamSpec
|
||||
|
||||
def foo3[**P = [int, str]]() -> None:
|
||||
reveal_type(P) # revealed: typing.ParamSpec
|
||||
|
||||
def foo4[**P, **Q = P]():
|
||||
reveal_type(P) # revealed: typing.ParamSpec
|
||||
reveal_type(Q) # revealed: typing.ParamSpec
|
||||
```
|
||||
|
||||
#### Invalid
|
||||
|
||||
ParamSpec, when defined using the new syntax, does not allow defining bounds or constraints.
|
||||
|
||||
This results in a lot of syntax errors mainly because the AST doesn't accept them in this position.
|
||||
The parser could do a better job in recovering from these errors.
|
||||
|
||||
<!-- blacken-docs:off -->
|
||||
|
||||
```py
|
||||
# error: [invalid-syntax]
|
||||
# error: [invalid-syntax]
|
||||
# error: [invalid-syntax]
|
||||
# error: [invalid-syntax]
|
||||
# error: [invalid-syntax]
|
||||
# error: [invalid-syntax]
|
||||
def foo[**P: int]() -> None:
|
||||
# error: [invalid-syntax]
|
||||
# error: [invalid-syntax]
|
||||
pass
|
||||
```
|
||||
|
||||
<!-- blacken-docs:on -->
|
||||
|
||||
#### Invalid default
|
||||
|
||||
```py
|
||||
# error: [invalid-paramspec]
|
||||
def foo[**P = int]() -> None:
|
||||
pass
|
||||
```
|
||||
|
|
@ -1171,9 +1171,7 @@ class EggsLegacy(Generic[T, P]): ...
|
|||
static_assert(not is_assignable_to(Spam, Callable[..., Any]))
|
||||
static_assert(not is_assignable_to(SpamLegacy, Callable[..., Any]))
|
||||
static_assert(not is_assignable_to(Eggs, Callable[..., Any]))
|
||||
|
||||
# TODO: should pass
|
||||
static_assert(not is_assignable_to(EggsLegacy, Callable[..., Any])) # error: [static-assert-error]
|
||||
static_assert(not is_assignable_to(EggsLegacy, Callable[..., Any]))
|
||||
```
|
||||
|
||||
### Classes with `__call__` as attribute
|
||||
|
|
|
|||
|
|
@ -4358,6 +4358,13 @@ impl<'db> Type<'db> {
|
|||
.into()
|
||||
}
|
||||
|
||||
Type::KnownInstance(KnownInstanceType::TypeVar(typevar))
|
||||
if typevar.kind(db).is_paramspec()
|
||||
&& matches!(name.as_str(), "args" | "kwargs") =>
|
||||
{
|
||||
Place::bound(todo_type!("ParamSpecArgs / ParamSpecKwargs")).into()
|
||||
}
|
||||
|
||||
Type::NominalInstance(..)
|
||||
| Type::ProtocolInstance(..)
|
||||
| Type::BooleanLiteral(..)
|
||||
|
|
@ -7024,7 +7031,7 @@ impl<'db> Type<'db> {
|
|||
Type::TypeVar(bound_typevar) => {
|
||||
if matches!(
|
||||
bound_typevar.typevar(db).kind(db),
|
||||
TypeVarKind::Legacy | TypeVarKind::TypingSelf
|
||||
TypeVarKind::Legacy | TypeVarKind::TypingSelf | TypeVarKind::ParamSpec
|
||||
) && binding_context.is_none_or(|binding_context| {
|
||||
bound_typevar.binding_context(db) == BindingContext::Definition(binding_context)
|
||||
}) {
|
||||
|
|
@ -7743,6 +7750,9 @@ impl<'db> KnownInstanceType<'db> {
|
|||
fn class(self, db: &'db dyn Db) -> KnownClass {
|
||||
match self {
|
||||
Self::SubscriptedProtocol(_) | Self::SubscriptedGeneric(_) => KnownClass::SpecialForm,
|
||||
Self::TypeVar(typevar_instance) if typevar_instance.kind(db).is_paramspec() => {
|
||||
KnownClass::ParamSpec
|
||||
}
|
||||
Self::TypeVar(_) => KnownClass::TypeVar,
|
||||
Self::TypeAliasType(TypeAliasType::PEP695(alias)) if alias.is_specialized(db) => {
|
||||
KnownClass::GenericAlias
|
||||
|
|
@ -7808,7 +7818,13 @@ impl<'db> KnownInstanceType<'db> {
|
|||
// This is a legacy `TypeVar` _outside_ of any generic class or function, so we render
|
||||
// it as an instance of `typing.TypeVar`. Inside of a generic class or function, we'll
|
||||
// have a `Type::TypeVar(_)`, which is rendered as the typevar's name.
|
||||
KnownInstanceType::TypeVar(_) => f.write_str("typing.TypeVar"),
|
||||
KnownInstanceType::TypeVar(typevar_instance) => {
|
||||
if typevar_instance.kind(self.db).is_paramspec() {
|
||||
f.write_str("typing.ParamSpec")
|
||||
} else {
|
||||
f.write_str("typing.TypeVar")
|
||||
}
|
||||
}
|
||||
KnownInstanceType::Deprecated(_) => f.write_str("warnings.deprecated"),
|
||||
KnownInstanceType::Field(field) => {
|
||||
f.write_str("dataclasses.Field")?;
|
||||
|
|
@ -7864,9 +7880,6 @@ pub enum DynamicType<'db> {
|
|||
///
|
||||
/// This variant should be created with the `todo_type!` macro.
|
||||
Todo(TodoType),
|
||||
/// A special Todo-variant for PEP-695 `ParamSpec` types. A temporary variant to detect and special-
|
||||
/// case the handling of these types in `Callable` annotations.
|
||||
TodoPEP695ParamSpec,
|
||||
/// A special Todo-variant for type aliases declared using `typing.TypeAlias`.
|
||||
/// A temporary variant to detect and special-case the handling of these aliases in autocomplete suggestions.
|
||||
TodoTypeAlias,
|
||||
|
|
@ -7894,13 +7907,6 @@ impl std::fmt::Display for DynamicType<'_> {
|
|||
// `DynamicType::Todo`'s display should be explicit that is not a valid display of
|
||||
// any other type
|
||||
DynamicType::Todo(todo) => write!(f, "@Todo{todo}"),
|
||||
DynamicType::TodoPEP695ParamSpec => {
|
||||
if cfg!(debug_assertions) {
|
||||
f.write_str("@Todo(ParamSpec)")
|
||||
} else {
|
||||
f.write_str("@Todo")
|
||||
}
|
||||
}
|
||||
DynamicType::TodoUnpack => {
|
||||
if cfg!(debug_assertions) {
|
||||
f.write_str("@Todo(typing.Unpack)")
|
||||
|
|
@ -8239,12 +8245,20 @@ pub enum TypeVarKind {
|
|||
Pep695,
|
||||
/// `typing.Self`
|
||||
TypingSelf,
|
||||
/// `P = ParamSpec("P")`
|
||||
ParamSpec,
|
||||
/// `def foo[**P]() -> None: ...`
|
||||
Pep695ParamSpec,
|
||||
}
|
||||
|
||||
impl TypeVarKind {
|
||||
const fn is_self(self) -> bool {
|
||||
matches!(self, Self::TypingSelf)
|
||||
}
|
||||
|
||||
const fn is_paramspec(self) -> bool {
|
||||
matches!(self, Self::ParamSpec | Self::Pep695ParamSpec)
|
||||
}
|
||||
}
|
||||
|
||||
/// The identity of a type variable.
|
||||
|
|
@ -8597,6 +8611,15 @@ impl<'db> TypeVarInstance<'db> {
|
|||
let expr = &call_expr.arguments.find_keyword("default")?.value;
|
||||
Some(definition_expression_type(db, definition, expr))
|
||||
}
|
||||
// PEP 695 ParamSpec
|
||||
DefinitionKind::ParamSpec(paramspec) => {
|
||||
let paramspec_node = paramspec.node(&module);
|
||||
Some(definition_expression_type(
|
||||
db,
|
||||
definition,
|
||||
paramspec_node.default.as_ref()?,
|
||||
))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,10 +49,7 @@ impl<'db> ClassBase<'db> {
|
|||
ClassBase::Dynamic(DynamicType::Any) => "Any",
|
||||
ClassBase::Dynamic(DynamicType::Unknown) => "Unknown",
|
||||
ClassBase::Dynamic(
|
||||
DynamicType::Todo(_)
|
||||
| DynamicType::TodoPEP695ParamSpec
|
||||
| DynamicType::TodoTypeAlias
|
||||
| DynamicType::TodoUnpack,
|
||||
DynamicType::Todo(_) | DynamicType::TodoTypeAlias | DynamicType::TodoUnpack,
|
||||
) => "@Todo",
|
||||
ClassBase::Dynamic(DynamicType::Divergent(_)) => "Divergent",
|
||||
ClassBase::Protocol => "Protocol",
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ pub(crate) fn register_lints(registry: &mut LintRegistryBuilder) {
|
|||
registry.register_lint(&INVALID_EXCEPTION_CAUGHT);
|
||||
registry.register_lint(&INVALID_GENERIC_CLASS);
|
||||
registry.register_lint(&INVALID_LEGACY_TYPE_VARIABLE);
|
||||
registry.register_lint(&INVALID_PARAMSPEC);
|
||||
registry.register_lint(&INVALID_TYPE_ALIAS_TYPE);
|
||||
registry.register_lint(&INVALID_METACLASS);
|
||||
registry.register_lint(&INVALID_OVERLOAD);
|
||||
|
|
@ -880,6 +881,30 @@ declare_lint! {
|
|||
}
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// ## What it does
|
||||
/// Checks for the creation of invalid `ParamSpec`s
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// There are several requirements that you must follow when creating a `ParamSpec`.
|
||||
///
|
||||
/// ## Examples
|
||||
/// ```python
|
||||
/// from typing import ParamSpec
|
||||
///
|
||||
/// P1 = ParamSpec("P1") # okay
|
||||
/// P2 = ParamSpec("S2") # error: ParamSpec name must match the variable it's assigned to
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// - [Typing spec: ParamSpec](https://typing.python.org/en/latest/spec/generics.html#paramspec)
|
||||
pub(crate) static INVALID_PARAMSPEC = {
|
||||
summary: "detects invalid ParamSpec usage",
|
||||
status: LintStatus::stable("0.0.1-alpha.1"),
|
||||
default_level: Level::Error,
|
||||
}
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// ## What it does
|
||||
/// Checks for the creation of invalid `TypeAliasType`s
|
||||
|
|
|
|||
|
|
@ -59,11 +59,12 @@ use crate::types::diagnostic::{
|
|||
DIVISION_BY_ZERO, DUPLICATE_KW_ONLY, INCONSISTENT_MRO, INVALID_ARGUMENT_TYPE,
|
||||
INVALID_ASSIGNMENT, INVALID_ATTRIBUTE_ACCESS, INVALID_BASE, INVALID_DECLARATION,
|
||||
INVALID_GENERIC_CLASS, INVALID_KEY, INVALID_LEGACY_TYPE_VARIABLE, INVALID_METACLASS,
|
||||
INVALID_NAMED_TUPLE, INVALID_OVERLOAD, INVALID_PARAMETER_DEFAULT, INVALID_PROTOCOL,
|
||||
INVALID_TYPE_FORM, INVALID_TYPE_GUARD_CALL, INVALID_TYPE_VARIABLE_CONSTRAINTS,
|
||||
IncompatibleBases, NON_SUBSCRIPTABLE, POSSIBLY_MISSING_IMPLICIT_CALL, POSSIBLY_MISSING_IMPORT,
|
||||
SUBCLASS_OF_FINAL_CLASS, UNDEFINED_REVEAL, UNRESOLVED_ATTRIBUTE, UNRESOLVED_GLOBAL,
|
||||
UNRESOLVED_IMPORT, UNRESOLVED_REFERENCE, UNSUPPORTED_OPERATOR, USELESS_OVERLOAD_BODY,
|
||||
INVALID_NAMED_TUPLE, INVALID_OVERLOAD, INVALID_PARAMETER_DEFAULT, INVALID_PARAMSPEC,
|
||||
INVALID_PROTOCOL, INVALID_TYPE_FORM, INVALID_TYPE_GUARD_CALL,
|
||||
INVALID_TYPE_VARIABLE_CONSTRAINTS, IncompatibleBases, NON_SUBSCRIPTABLE,
|
||||
POSSIBLY_MISSING_IMPLICIT_CALL, POSSIBLY_MISSING_IMPORT, SUBCLASS_OF_FINAL_CLASS,
|
||||
UNDEFINED_REVEAL, UNRESOLVED_ATTRIBUTE, UNRESOLVED_GLOBAL, UNRESOLVED_IMPORT,
|
||||
UNRESOLVED_REFERENCE, UNSUPPORTED_OPERATOR, USELESS_OVERLOAD_BODY,
|
||||
hint_if_stdlib_attribute_exists_on_other_versions,
|
||||
hint_if_stdlib_submodule_exists_on_other_versions, report_attempted_protocol_instantiation,
|
||||
report_bad_dunder_set_call, report_cannot_pop_required_field_on_typed_dict,
|
||||
|
|
@ -1296,6 +1297,9 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
DefinitionKind::TypeVar(typevar) => {
|
||||
self.infer_typevar_deferred(typevar.node(self.module()));
|
||||
}
|
||||
DefinitionKind::ParamSpec(paramspec) => {
|
||||
self.infer_paramspec_deferred(paramspec.node(self.module()));
|
||||
}
|
||||
DefinitionKind::Assignment(assignment) => {
|
||||
self.infer_assignment_deferred(assignment.value(self.module()));
|
||||
}
|
||||
|
|
@ -3182,18 +3186,120 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
let ast::TypeParamParamSpec {
|
||||
range: _,
|
||||
node_index: _,
|
||||
name: _,
|
||||
name,
|
||||
default,
|
||||
} = node;
|
||||
self.infer_optional_expression(default.as_deref(), TypeContext::default());
|
||||
let pep_695_todo = Type::Dynamic(DynamicType::TodoPEP695ParamSpec);
|
||||
if default.is_some() {
|
||||
self.deferred.insert(definition);
|
||||
}
|
||||
let identity = TypeVarIdentity::new(
|
||||
self.db(),
|
||||
&name.id,
|
||||
Some(definition),
|
||||
TypeVarKind::Pep695ParamSpec,
|
||||
);
|
||||
let ty = Type::KnownInstance(KnownInstanceType::TypeVar(TypeVarInstance::new(
|
||||
self.db(),
|
||||
identity,
|
||||
None, // ParamSpec, when declared using PEP 695 syntax, has no bounds or constraints
|
||||
None, // explicit_variance
|
||||
default.as_deref().map(|_| TypeVarDefaultEvaluation::Lazy),
|
||||
)));
|
||||
self.add_declaration_with_binding(
|
||||
node.into(),
|
||||
definition,
|
||||
&DeclaredAndInferredType::are_the_same_type(pep_695_todo),
|
||||
&DeclaredAndInferredType::are_the_same_type(ty),
|
||||
);
|
||||
}
|
||||
|
||||
fn infer_paramspec_deferred(&mut self, node: &ast::TypeParamParamSpec) {
|
||||
let ast::TypeParamParamSpec {
|
||||
range: _,
|
||||
node_index: _,
|
||||
name: _,
|
||||
default: Some(default),
|
||||
} = node
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let previous_deferred_state =
|
||||
std::mem::replace(&mut self.deferred_state, DeferredExpressionState::Deferred);
|
||||
let default_ty = self.infer_paramspec_default(default);
|
||||
self.store_expression_type(default, default_ty);
|
||||
self.deferred_state = previous_deferred_state;
|
||||
}
|
||||
|
||||
fn infer_paramspec_default(&mut self, default: &ast::Expr) -> Type<'db> {
|
||||
// This is the same logic as `TypeInferenceBuilder::infer_callable_parameter_types` except
|
||||
// for the subscript branch which is required for `Concatenate` but that cannot be
|
||||
// specified in this context.
|
||||
match default {
|
||||
ast::Expr::EllipsisLiteral(_) => {
|
||||
CallableType::single(self.db(), Signature::new(Parameters::gradual_form(), None))
|
||||
}
|
||||
ast::Expr::List(ast::ExprList { elts, .. }) => {
|
||||
let mut parameter_types = Vec::with_capacity(elts.len());
|
||||
|
||||
// Whether to infer `Todo` for the parameters
|
||||
let mut return_todo = false;
|
||||
|
||||
for param in elts {
|
||||
let param_type = self.infer_type_expression(param);
|
||||
// This is similar to what we currently do for inferring tuple type expression.
|
||||
// We currently infer `Todo` for the parameters to avoid invalid diagnostics
|
||||
// when trying to check for assignability or any other relation. For example,
|
||||
// `*tuple[int, str]`, `Unpack[]`, etc. are not yet supported.
|
||||
return_todo |= param_type.is_todo()
|
||||
&& matches!(param, ast::Expr::Starred(_) | ast::Expr::Subscript(_));
|
||||
parameter_types.push(param_type);
|
||||
}
|
||||
|
||||
let parameters = if return_todo {
|
||||
// TODO: `Unpack`
|
||||
Parameters::todo()
|
||||
} else {
|
||||
Parameters::new(parameter_types.iter().map(|param_type| {
|
||||
Parameter::positional_only(None).with_annotated_type(*param_type)
|
||||
}))
|
||||
};
|
||||
|
||||
CallableType::single(self.db(), Signature::new(parameters, None))
|
||||
}
|
||||
ast::Expr::Name(name) => {
|
||||
let name_ty = self.infer_name_load(name);
|
||||
let is_paramspec = match name_ty {
|
||||
Type::KnownInstance(known_instance) => {
|
||||
known_instance.class(self.db()) == KnownClass::ParamSpec
|
||||
}
|
||||
Type::NominalInstance(nominal) => {
|
||||
nominal.has_known_class(self.db(), KnownClass::ParamSpec)
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
if is_paramspec {
|
||||
name_ty
|
||||
} else {
|
||||
if let Some(builder) = self.context.report_lint(&INVALID_PARAMSPEC, default) {
|
||||
builder.into_diagnostic(
|
||||
"The default value to `ParamSpec` must be either a list of types, \
|
||||
`ParamSpec`, or `...`",
|
||||
);
|
||||
}
|
||||
Type::unknown()
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if let Some(builder) = self.context.report_lint(&INVALID_PARAMSPEC, default) {
|
||||
builder.into_diagnostic(
|
||||
"The default value to `ParamSpec` must be either a list of types, \
|
||||
`ParamSpec`, or `...`",
|
||||
);
|
||||
}
|
||||
Type::unknown()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn infer_typevartuple_definition(
|
||||
&mut self,
|
||||
node: &ast::TypeParamTypeVarTuple,
|
||||
|
|
@ -4324,17 +4430,21 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
TypeContext::default(),
|
||||
);
|
||||
|
||||
let typevar_class = callable_type
|
||||
let ty = match callable_type
|
||||
.as_class_literal()
|
||||
.and_then(|cls| cls.known(self.db()))
|
||||
.filter(|cls| {
|
||||
matches!(cls, KnownClass::TypeVar | KnownClass::ExtensionsTypeVar)
|
||||
});
|
||||
|
||||
let ty = if let Some(typevar_class) = typevar_class {
|
||||
self.infer_legacy_typevar(target, call_expr, definition, typevar_class)
|
||||
} else {
|
||||
self.infer_call_expression_impl(call_expr, callable_type, tcx)
|
||||
{
|
||||
Some(
|
||||
typevar_class @ (KnownClass::TypeVar | KnownClass::ExtensionsTypeVar),
|
||||
) => {
|
||||
self.infer_legacy_typevar(target, call_expr, definition, typevar_class)
|
||||
}
|
||||
Some(KnownClass::ParamSpec) => {
|
||||
self.infer_paramspec(target, call_expr, definition)
|
||||
}
|
||||
Some(_) | None => {
|
||||
self.infer_call_expression_impl(call_expr, callable_type, tcx)
|
||||
}
|
||||
};
|
||||
|
||||
self.store_expression_type(value, ty);
|
||||
|
|
@ -4371,6 +4481,160 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
target_ty
|
||||
}
|
||||
|
||||
fn infer_paramspec(
|
||||
&mut self,
|
||||
target: &ast::Expr,
|
||||
call_expr: &ast::ExprCall,
|
||||
definition: Definition<'db>,
|
||||
) -> Type<'db> {
|
||||
fn error<'db>(
|
||||
context: &InferContext<'db, '_>,
|
||||
message: impl std::fmt::Display,
|
||||
node: impl Ranged,
|
||||
) -> Type<'db> {
|
||||
if let Some(builder) = context.report_lint(&INVALID_PARAMSPEC, node) {
|
||||
builder.into_diagnostic(message);
|
||||
}
|
||||
// If the call doesn't create a valid paramspec, we'll emit diagnostics and fall back to
|
||||
// just creating a regular instance of `typing.ParamSpec`.
|
||||
KnownClass::ParamSpec.to_instance(context.db())
|
||||
}
|
||||
|
||||
let db = self.db();
|
||||
let arguments = &call_expr.arguments;
|
||||
let assume_all_features = self.in_stub();
|
||||
let python_version = Program::get(db).python_version(db);
|
||||
let have_features_from =
|
||||
|version: PythonVersion| assume_all_features || python_version >= version;
|
||||
|
||||
let mut default = None;
|
||||
let mut name_param_ty = None;
|
||||
|
||||
if arguments.args.len() > 1 {
|
||||
return error(
|
||||
&self.context,
|
||||
"`ParamSpec` can only have one positional argument",
|
||||
call_expr,
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(starred) = arguments.args.iter().find(|arg| arg.is_starred_expr()) {
|
||||
return error(
|
||||
&self.context,
|
||||
"Starred arguments are not supported in `ParamSpec` creation",
|
||||
starred,
|
||||
);
|
||||
}
|
||||
|
||||
for kwarg in &arguments.keywords {
|
||||
let Some(identifier) = kwarg.arg.as_ref() else {
|
||||
return error(
|
||||
&self.context,
|
||||
"Starred arguments are not supported in `ParamSpec` creation",
|
||||
kwarg,
|
||||
);
|
||||
};
|
||||
match identifier.id().as_str() {
|
||||
"name" => {
|
||||
// Duplicate keyword argument is a syntax error, so we don't have to check if
|
||||
// `name_param_ty.is_some()` here.
|
||||
if !arguments.args.is_empty() {
|
||||
return error(
|
||||
&self.context,
|
||||
"The `name` parameter of `ParamSpec` can only be provided once",
|
||||
kwarg,
|
||||
);
|
||||
}
|
||||
name_param_ty =
|
||||
Some(self.infer_expression(&kwarg.value, TypeContext::default()));
|
||||
}
|
||||
"bound" | "covariant" | "contravariant" | "infer_variance" => {
|
||||
return error(
|
||||
&self.context,
|
||||
"The variance and bound arguments for `ParamSpec` do not have defined semantics yet",
|
||||
call_expr,
|
||||
);
|
||||
}
|
||||
"default" => {
|
||||
if !have_features_from(PythonVersion::PY313) {
|
||||
// We don't return here; this error is informational since this will error
|
||||
// at runtime, but the user's intent is plain, we may as well respect it.
|
||||
error(
|
||||
&self.context,
|
||||
"The `default` parameter of `typing.ParamSpec` was added in Python 3.13",
|
||||
kwarg,
|
||||
);
|
||||
}
|
||||
default = Some(TypeVarDefaultEvaluation::Lazy);
|
||||
}
|
||||
name => {
|
||||
// We don't return here; this error is informational since this will error
|
||||
// at runtime, but it will likely cause fewer cascading errors if we just
|
||||
// ignore the unknown keyword and still understand as much of the typevar as we
|
||||
// can.
|
||||
error(
|
||||
&self.context,
|
||||
format_args!("Unknown keyword argument `{name}` in `ParamSpec` creation"),
|
||||
kwarg,
|
||||
);
|
||||
self.infer_expression(&kwarg.value, TypeContext::default());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let Some(name_param_ty) = name_param_ty.or_else(|| {
|
||||
arguments
|
||||
.find_positional(0)
|
||||
.map(|arg| self.infer_expression(arg, TypeContext::default()))
|
||||
}) else {
|
||||
return error(
|
||||
&self.context,
|
||||
"The `name` parameter of `ParamSpec` is required.",
|
||||
call_expr,
|
||||
);
|
||||
};
|
||||
|
||||
let Some(name_param) = name_param_ty.as_string_literal().map(|name| name.value(db)) else {
|
||||
return error(
|
||||
&self.context,
|
||||
"The first argument to `ParamSpec` must be a string literal",
|
||||
call_expr,
|
||||
);
|
||||
};
|
||||
|
||||
let ast::Expr::Name(ast::ExprName {
|
||||
id: target_name, ..
|
||||
}) = target
|
||||
else {
|
||||
return error(
|
||||
&self.context,
|
||||
"A `ParamSpec` definition must be a simple variable assignment",
|
||||
target,
|
||||
);
|
||||
};
|
||||
|
||||
if name_param != target_name {
|
||||
return error(
|
||||
&self.context,
|
||||
format_args!(
|
||||
"The name of a `ParamSpec` (`{name_param}`) must match \
|
||||
the name of the variable it is assigned to (`{target_name}`)"
|
||||
),
|
||||
target,
|
||||
);
|
||||
}
|
||||
|
||||
if default.is_some() {
|
||||
self.deferred.insert(definition);
|
||||
}
|
||||
|
||||
let identity =
|
||||
TypeVarIdentity::new(db, target_name, Some(definition), TypeVarKind::ParamSpec);
|
||||
Type::KnownInstance(KnownInstanceType::TypeVar(TypeVarInstance::new(
|
||||
db, identity, None, None, default,
|
||||
)))
|
||||
}
|
||||
|
||||
fn infer_legacy_typevar(
|
||||
&mut self,
|
||||
target: &ast::Expr,
|
||||
|
|
@ -4617,8 +4881,11 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
}
|
||||
|
||||
fn infer_assignment_deferred(&mut self, value: &ast::Expr) {
|
||||
// Infer deferred bounds/constraints/defaults of a legacy TypeVar.
|
||||
let ast::Expr::Call(ast::ExprCall { arguments, .. }) = value else {
|
||||
// Infer deferred bounds/constraints/defaults of a legacy TypeVar / ParamSpec.
|
||||
let ast::Expr::Call(ast::ExprCall {
|
||||
func, arguments, ..
|
||||
}) = value
|
||||
else {
|
||||
return;
|
||||
};
|
||||
for arg in arguments.args.iter().skip(1) {
|
||||
|
|
@ -4628,7 +4895,14 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
self.infer_type_expression(&bound.value);
|
||||
}
|
||||
if let Some(default) = arguments.find_keyword("default") {
|
||||
self.infer_type_expression(&default.value);
|
||||
let func_ty = self.get_or_infer_expression(func, TypeContext::default());
|
||||
if func_ty.as_class_literal().is_some_and(|class_literal| {
|
||||
class_literal.is_known(self.db(), KnownClass::ParamSpec)
|
||||
}) {
|
||||
self.infer_paramspec_default(&default.value);
|
||||
} else {
|
||||
self.infer_type_expression(&default.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -7047,22 +7321,33 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
.to_class_type(self.db())
|
||||
.is_none_or(|enum_class| !class.is_subclass_of(self.db(), enum_class))
|
||||
{
|
||||
if matches!(
|
||||
class.known(self.db()),
|
||||
Some(KnownClass::TypeVar | KnownClass::ExtensionsTypeVar)
|
||||
) {
|
||||
// Inference of correctly-placed `TypeVar` definitions is done in
|
||||
// `TypeInferenceBuilder::infer_legacy_typevar`, and doesn't use the full
|
||||
// call-binding machinery. If we reach here, it means that someone is trying to
|
||||
// instantiate a `typing.TypeVar` in an invalid context.
|
||||
if let Some(builder) = self
|
||||
.context
|
||||
.report_lint(&INVALID_LEGACY_TYPE_VARIABLE, call_expression)
|
||||
{
|
||||
builder.into_diagnostic(
|
||||
"A `TypeVar` definition must be a simple variable assignment",
|
||||
);
|
||||
// Inference of correctly-placed `TypeVar` and `ParamSpec` definitions is done in
|
||||
// `TypeInferenceBuilder::infer_legacy_typevar` and
|
||||
// `TypeInferenceBuilder::infer_paramspec`, and doesn't use the full
|
||||
// call-binding machinery. If we reach here, it means that someone is trying to
|
||||
// instantiate a `typing.TypeVar` and `typing.ParamSpec` in an invalid context.
|
||||
match class.known(self.db()) {
|
||||
Some(KnownClass::TypeVar | KnownClass::ExtensionsTypeVar) => {
|
||||
if let Some(builder) = self
|
||||
.context
|
||||
.report_lint(&INVALID_LEGACY_TYPE_VARIABLE, call_expression)
|
||||
{
|
||||
builder.into_diagnostic(
|
||||
"A `TypeVar` definition must be a simple variable assignment",
|
||||
);
|
||||
}
|
||||
}
|
||||
Some(KnownClass::ParamSpec) => {
|
||||
if let Some(builder) = self
|
||||
.context
|
||||
.report_lint(&INVALID_PARAMSPEC, call_expression)
|
||||
{
|
||||
builder.into_diagnostic(
|
||||
"A `ParamSpec` definition must be a simple variable assignment",
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let db = self.db();
|
||||
|
|
@ -8270,10 +8555,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
|
||||
(
|
||||
todo @ Type::Dynamic(
|
||||
DynamicType::Todo(_)
|
||||
| DynamicType::TodoPEP695ParamSpec
|
||||
| DynamicType::TodoUnpack
|
||||
| DynamicType::TodoTypeAlias,
|
||||
DynamicType::Todo(_) | DynamicType::TodoUnpack | DynamicType::TodoTypeAlias,
|
||||
),
|
||||
_,
|
||||
_,
|
||||
|
|
@ -8281,10 +8563,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
| (
|
||||
_,
|
||||
todo @ Type::Dynamic(
|
||||
DynamicType::Todo(_)
|
||||
| DynamicType::TodoPEP695ParamSpec
|
||||
| DynamicType::TodoUnpack
|
||||
| DynamicType::TodoTypeAlias,
|
||||
DynamicType::Todo(_) | DynamicType::TodoUnpack | DynamicType::TodoTypeAlias,
|
||||
),
|
||||
_,
|
||||
) => Some(todo),
|
||||
|
|
|
|||
|
|
@ -1524,7 +1524,9 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
self.db(),
|
||||
self.infer_name_load(name),
|
||||
&|ty| match ty {
|
||||
Type::Dynamic(DynamicType::TodoPEP695ParamSpec) => true,
|
||||
Type::KnownInstance(known_instance) => {
|
||||
known_instance.class(self.db()) == KnownClass::ParamSpec
|
||||
}
|
||||
Type::NominalInstance(nominal) => {
|
||||
nominal.has_known_class(self.db(), KnownClass::ParamSpec)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -262,9 +262,6 @@ fn dynamic_elements_ordering(left: DynamicType, right: DynamicType) -> Ordering
|
|||
#[cfg(not(debug_assertions))]
|
||||
(DynamicType::Todo(TodoType), DynamicType::Todo(TodoType)) => Ordering::Equal,
|
||||
|
||||
(DynamicType::TodoPEP695ParamSpec, _) => Ordering::Less,
|
||||
(_, DynamicType::TodoPEP695ParamSpec) => Ordering::Greater,
|
||||
|
||||
(DynamicType::TodoUnpack, _) => Ordering::Less,
|
||||
(_, DynamicType::TodoUnpack) => Ordering::Greater,
|
||||
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ Settings: Settings {
|
|||
"invalid-named-tuple": Error (Default),
|
||||
"invalid-overload": Error (Default),
|
||||
"invalid-parameter-default": Error (Default),
|
||||
"invalid-paramspec": Error (Default),
|
||||
"invalid-protocol": Error (Default),
|
||||
"invalid-raise": Error (Default),
|
||||
"invalid-return-type": Error (Default),
|
||||
|
|
|
|||
10
ty.schema.json
generated
10
ty.schema.json
generated
|
|
@ -643,6 +643,16 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"invalid-paramspec": {
|
||||
"title": "detects invalid ParamSpec usage",
|
||||
"description": "## What it does\nChecks for the creation of invalid `ParamSpec`s\n\n## Why is this bad?\nThere are several requirements that you must follow when creating a `ParamSpec`.\n\n## Examples\n```python\nfrom typing import ParamSpec\n\nP1 = ParamSpec(\"P1\") # okay\nP2 = ParamSpec(\"S2\") # error: ParamSpec name must match the variable it's assigned to\n```\n\n## References\n- [Typing spec: ParamSpec](https://typing.python.org/en/latest/spec/generics.html#paramspec)",
|
||||
"default": "error",
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/definitions/Level"
|
||||
}
|
||||
]
|
||||
},
|
||||
"invalid-protocol": {
|
||||
"title": "detects invalid protocol class definitions",
|
||||
"description": "## What it does\nChecks for protocol classes that will raise `TypeError` at runtime.\n\n## Why is this bad?\nAn invalidly defined protocol class may lead to the type checker inferring\nunexpected things. It may also lead to `TypeError`s at runtime.\n\n## Examples\nA `Protocol` class cannot inherit from a non-`Protocol` class;\nthis raises a `TypeError` at runtime:\n\n```pycon\n>>> from typing import Protocol\n>>> class Foo(int, Protocol): ...\n...\nTraceback (most recent call last):\n File \"<python-input-1>\", line 1, in <module>\n class Foo(int, Protocol): ...\nTypeError: Protocols can only inherit from other protocols, got <class 'int'>\n```",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue