[ty] Document nearly all lints (#17981)

This commit is contained in:
InSync 2025-05-10 00:06:56 +07:00 committed by GitHub
parent 861ef2504e
commit 249a852a6e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 558 additions and 116 deletions

View file

@ -61,7 +61,23 @@ Calling a non-callable object will raise a `TypeError` at runtime.
<summary>detects when an argument is used as both a value and a type form in a call</summary> <summary>detects when an argument is used as both a value and a type form in a call</summary>
### What it does ### What it does
Checks whether an argument is used as both a value and a type form in a call Checks whether an argument is used as both a value and a type form in a call.
### Why is this bad?
Such calls have confusing semantics and often indicate a logic error.
### Examples
```python
from typing import reveal_type
from ty_extensions import is_fully_static
if flag:
f = repr # Expects a value
else:
f = is_fully_static # Expects a type form
f(int) # error
```
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-argument-forms) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-argument-forms)
@ -83,9 +99,19 @@ A variable with two conflicting declarations likely indicates a mistake.
Moreover, it could lead to incorrect or ill-defined type inference for Moreover, it could lead to incorrect or ill-defined type inference for
other code that relies on these variables. other code that relies on these variables.
### Examples
```python
if b:
a: int
else:
a: str
a = 1
```
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-declarations) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-declarations)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L125) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L141)
</details> </details>
## `conflicting-metaclass` ## `conflicting-metaclass`
@ -95,11 +121,28 @@ other code that relies on these variables.
<details> <details>
<summary>detects conflicting metaclasses</summary> <summary>detects conflicting metaclasses</summary>
TODO #14889 ### What it does
Checks for class definitions where the metaclass of the class
being created would not be a subclass of the metaclasses of
all the class's bases.
### Why is it bad?
Such a class definition raises a `TypeError` at runtime.
### Examples
```python
class M1(type): ...
class M2(type): ...
class A(metaclass=M1): ...
class B(metaclass=M2): ...
## TypeError: metaclass conflict
class C(A, B): ...
```
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-metaclass) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-metaclass)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L140) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L166)
</details> </details>
## `cyclic-class-definition` ## `cyclic-class-definition`
@ -110,14 +153,27 @@ TODO #14889
<summary>detects cyclic class definitions</summary> <summary>detects cyclic class definitions</summary>
### What it does ### What it does
Checks for class definitions with a cyclic inheritance chain. Checks for class definitions in stub files that inherit
(directly or indirectly) from themselves.
### Why is it bad? ### Why is it bad?
TODO #14889 Although forward references are natively supported in stub files,
inheritance cycles are still disallowed, as it is impossible to
resolve a consistent [method resolution order] for a class that
inherits from itself.
### Examples
```python
## foo.pyi
class A(B): ...
class B(A): ...
```
[method resolution order]: https://docs.python.org/3/glossary.html#term-method-resolution-order
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20cyclic-class-definition) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20cyclic-class-definition)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L149) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L192)
</details> </details>
## `division-by-zero` ## `division-by-zero`
@ -140,7 +196,7 @@ Dividing by zero raises a `ZeroDivisionError` at runtime.
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20division-by-zero) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20division-by-zero)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L162) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L218)
</details> </details>
## `duplicate-base` ## `duplicate-base`
@ -154,11 +210,19 @@ Dividing by zero raises a `ZeroDivisionError` at runtime.
Checks for class definitions with duplicate bases. Checks for class definitions with duplicate bases.
### Why is this bad? ### Why is this bad?
Class definitions with duplicate bases raise a `TypeError` at runtime. Class definitions with duplicate bases raise `TypeError` at runtime.
### Examples
```python
class A: ...
## TypeError: duplicate base class
class B(A, A): ...
```
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20duplicate-base) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20duplicate-base)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L180) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L236)
</details> </details>
## `escape-character-in-forward-annotation` ## `escape-character-in-forward-annotation`
@ -295,7 +359,7 @@ TypeError: multiple bases have instance lay-out conflict
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20incompatible-slots) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20incompatible-slots)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L193) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L257)
</details> </details>
## `inconsistent-mro` ## `inconsistent-mro`
@ -306,14 +370,25 @@ TypeError: multiple bases have instance lay-out conflict
<summary>detects class definitions with an inconsistent MRO</summary> <summary>detects class definitions with an inconsistent MRO</summary>
### What it does ### What it does
Checks for classes with an inconsistent method resolution order (MRO). Checks for classes with an inconsistent [method resolution order] (MRO).
### Why is this bad? ### Why is this bad?
Classes with an inconsistent MRO will raise a `TypeError` at runtime. Classes with an inconsistent MRO will raise a `TypeError` at runtime.
### Examples
```python
class A: ...
class B(A): ...
## TypeError: Cannot create a consistent method resolution order
class C(A, B): ...
```
[method resolution order]: https://docs.python.org/3/glossary.html#term-method-resolution-order
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20inconsistent-mro) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20inconsistent-mro)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L279) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L343)
</details> </details>
## `index-out-of-bounds` ## `index-out-of-bounds`
@ -330,9 +405,15 @@ a container.
### Why is this bad? ### Why is this bad?
Using an out of bounds index will raise an `IndexError` at runtime. Using an out of bounds index will raise an `IndexError` at runtime.
### Examples
```python
t = (0, 1, 2)
t[3] # IndexError: tuple index out of range
```
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20index-out-of-bounds) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20index-out-of-bounds)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L292) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L367)
</details> </details>
## `invalid-argument-type` ## `invalid-argument-type`
@ -358,7 +439,7 @@ func("foo") # error: [invalid-argument-type]
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-argument-type) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-argument-type)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L306) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L387)
</details> </details>
## `invalid-assignment` ## `invalid-assignment`
@ -368,11 +449,24 @@ func("foo") # error: [invalid-argument-type]
<details> <details>
<summary>detects invalid assignments</summary> <summary>detects invalid assignments</summary>
TODO #14889 ### What it does
Checks for assignments where the type of the value
is not [assignable to] the type of the assignee.
### Why is this bad?
Such assignments break the rules of the type system and
weaken a type checker's ability to accurately reason about your code.
### Examples
```python
a: int = ''
```
[assignable to]: https://typing.python.org/en/latest/spec/glossary.html#term-assignable
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-assignment) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-assignment)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L346) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L427)
</details> </details>
## `invalid-attribute-access` ## `invalid-attribute-access`
@ -383,20 +477,29 @@ TODO #14889
<summary>Invalid attribute access</summary> <summary>Invalid attribute access</summary>
### What it does ### What it does
Makes sure that instance attribute accesses are valid. Checks for assignments to class variables from instances
and assignments to instance variables from its class.
### Why is this bad?
Incorrect assignments break the rules of the type system and
weaken a type checker's ability to accurately reason about your code.
### Examples ### Examples
```python ```python
class C: class C:
var: ClassVar[int] = 1 class_var: ClassVar[int] = 1
instance_var: int
C.var = 3 # okay C.class_var = 3 # okay
C().var = 3 # error: Cannot assign to class variable C().class_var = 3 # error: Cannot assign to class variable
C().instance_var = 3 # okay
C.instance_var = 3 # error: Cannot assign to instance variable
``` ```
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-attribute-access) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-attribute-access)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1099) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1311)
</details> </details>
## `invalid-base` ## `invalid-base`
@ -404,13 +507,13 @@ C().var = 3 # error: Cannot assign to class variable
**Default level**: error **Default level**: error
<details> <details>
<summary>detects class definitions with an invalid base</summary> <summary>detects invalid bases in class definitions</summary>
TODO #14889 TODO #14889
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-base) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-base)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L355) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L449)
</details> </details>
## `invalid-context-manager` ## `invalid-context-manager`
@ -420,11 +523,23 @@ TODO #14889
<details> <details>
<summary>detects expressions used in with statements that don't implement the context manager protocol</summary> <summary>detects expressions used in with statements that don't implement the context manager protocol</summary>
TODO #14889 ### What it does
Checks for expressions used in `with` statements
that do not implement the context manager protocol.
### Why is this bad?
Such a statement will raise `TypeError` at runtime.
### Examples
```python
## TypeError: 'int' object does not support the context manager protocol
with 1:
print(2)
```
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-context-manager) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-context-manager)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L364) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L458)
</details> </details>
## `invalid-declaration` ## `invalid-declaration`
@ -434,11 +549,25 @@ TODO #14889
<details> <details>
<summary>detects invalid declarations</summary> <summary>detects invalid declarations</summary>
TODO #14889 ### What it does
Checks for declarations where the inferred type of an existing symbol
is not [assignable to] its post-hoc declared type.
### Why is this bad?
Such declarations break the rules of the type system and
weaken a type checker's ability to accurately reason about your code.
### Examples
```python
a = 1
a: str
```
[assignable to]: https://typing.python.org/en/latest/spec/glossary.html#term-assignable
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-declaration) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-declaration)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L373) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L479)
</details> </details>
## `invalid-exception-caught` ## `invalid-exception-caught`
@ -479,7 +608,7 @@ except ZeroDivisionError:
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-exception-caught) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-exception-caught)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L382) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L502)
</details> </details>
## `invalid-generic-class` ## `invalid-generic-class`
@ -510,7 +639,7 @@ class C[U](Generic[T]): ...
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-generic-class) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-generic-class)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L418) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L538)
</details> </details>
## `invalid-legacy-type-variable` ## `invalid-legacy-type-variable`
@ -543,7 +672,7 @@ def f(t: TypeVar("U")): ...
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-legacy-type-variable) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-legacy-type-variable)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L444) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L564)
</details> </details>
## `invalid-metaclass` ## `invalid-metaclass`
@ -575,7 +704,7 @@ class B(metaclass=f): ...
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-metaclass) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-metaclass)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L472) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L592)
</details> </details>
## `invalid-overload` ## `invalid-overload`
@ -623,7 +752,7 @@ def foo(x: int) -> int: ...
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-overload) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-overload)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L499) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L619)
</details> </details>
## `invalid-parameter-default` ## `invalid-parameter-default`
@ -634,14 +763,21 @@ def foo(x: int) -> int: ...
<summary>detects default values that can't be assigned to the parameter's annotated type</summary> <summary>detects default values that can't be assigned to the parameter's annotated type</summary>
### What it does ### What it does
Checks for default values that can't be assigned to the parameter's annotated type. Checks for default values that can't be
assigned to the parameter's annotated type.
### Why is this bad? ### Why is this bad?
TODO #14889 This breaks the rules of the type system and
weakens a type checker's ability to accurately reason about your code.
### Examples
```python
def f(a: int = ''): ...
```
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-parameter-default) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-parameter-default)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L542) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L662)
</details> </details>
## `invalid-protocol` ## `invalid-protocol`
@ -674,7 +810,7 @@ TypeError: Protocols can only inherit from other protocols, got <class 'int'>
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-protocol) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-protocol)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L251) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L315)
</details> </details>
## `invalid-raise` ## `invalid-raise`
@ -722,7 +858,7 @@ def g():
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-raise) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-raise)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L555) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L682)
</details> </details>
## `invalid-return-type` ## `invalid-return-type`
@ -746,7 +882,7 @@ def func() -> int:
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-return-type) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-return-type)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L327) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L408)
</details> </details>
## `invalid-super-argument` ## `invalid-super-argument`
@ -790,7 +926,7 @@ super(B, A) # error: `A` does not satisfy `issubclass(A, B)`
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-super-argument) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-super-argument)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L598) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L725)
</details> </details>
## `invalid-syntax-in-forward-annotation` ## `invalid-syntax-in-forward-annotation`
@ -825,9 +961,15 @@ code seen only by the type checker, and not at runtime. Normally this flag is im
must be assigned the value `False` at runtime; the type checker will consider its value to must be assigned the value `False` at runtime; the type checker will consider its value to
be `True`. If annotated, it must be annotated as a type that can accept `bool` values. be `True`. If annotated, it must be annotated as a type that can accept `bool` values.
### Examples
```python
TYPE_CHECKING: str
TYPE_CHECKING = ''
```
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-checking-constant) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-checking-constant)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L637) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L764)
</details> </details>
## `invalid-type-form` ## `invalid-type-form`
@ -838,14 +980,24 @@ be `True`. If annotated, it must be annotated as a type that can accept `bool` v
<summary>detects invalid type forms</summary> <summary>detects invalid type forms</summary>
### What it does ### What it does
Checks for invalid type expressions. Checks for expressions that are used as type expressions
but cannot validly be interpreted as such.
### Why is this bad? ### Why is this bad?
TODO #14889 Such expressions cannot be understood by ty.
In some cases, they might raise errors at runtime.
### Examples
```python
from typing import Annotated
a: type[1] # `1` is not a type
b: Annotated[int] # `Annotated` expects at least two arguments
```
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-form) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-form)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L655) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L788)
</details> </details>
## `invalid-type-variable-constraints` ## `invalid-type-variable-constraints`
@ -855,11 +1007,31 @@ TODO #14889
<details> <details>
<summary>detects invalid type variable constraints</summary> <summary>detects invalid type variable constraints</summary>
TODO #14889 ### What it does
Checks for constrained [type variables] with only one constraint.
### Why is this bad?
A constrained type variable must have at least two constraints.
### Examples
```python
from typing import TypeVar
T = TypeVar('T', str) # invalid constrained TypeVar
```
Use instead:
```python
T = TypeVar('T', str, int) # valid constrained TypeVar
## or
T = TypeVar('T', bound=str) # valid bound TypeVar
```
[type variables]: https://docs.python.org/3/library/typing.html#typing.TypeVar
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-variable-constraints) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-variable-constraints)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L668) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L811)
</details> </details>
## `missing-argument` ## `missing-argument`
@ -883,7 +1055,7 @@ func() # TypeError: func() missing 1 required positional argument: 'x'
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20missing-argument) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20missing-argument)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L677) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L840)
</details> </details>
## `no-matching-overload` ## `no-matching-overload`
@ -911,7 +1083,7 @@ func("string") # error: [no-matching-overload]
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20no-matching-overload) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20no-matching-overload)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L696) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L859)
</details> </details>
## `non-subscriptable` ## `non-subscriptable`
@ -934,7 +1106,7 @@ Subscripting an object that does not support it will raise a `TypeError` at runt
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20non-subscriptable) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20non-subscriptable)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L719) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L882)
</details> </details>
## `not-iterable` ## `not-iterable`
@ -959,7 +1131,7 @@ for i in 34: # TypeError: 'int' object is not iterable
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20not-iterable) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20not-iterable)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L737) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L900)
</details> </details>
## `parameter-already-assigned` ## `parameter-already-assigned`
@ -985,7 +1157,7 @@ f(1, x=2) # Error raised here
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20parameter-already-assigned) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20parameter-already-assigned)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L788) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L951)
</details> </details>
## `raw-string-type-annotation` ## `raw-string-type-annotation`
@ -1028,6 +1200,11 @@ def test(): -> "int":
### What it does ### What it does
Makes sure that the argument of `static_assert` is statically known to be true. Makes sure that the argument of `static_assert` is statically known to be true.
### Why is this bad?
A `static_assert` call represents an explicit request from the user
for the type checker to emit an error if the argument cannot be verified
to evaluate to `True` in a boolean context.
### Examples ### Examples
```python ```python
from ty_extensions import static_assert from ty_extensions import static_assert
@ -1039,7 +1216,7 @@ static_assert(int(2.0 * 3.0) == 6) # error: does not have a statically known tr
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20static-assert-error) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20static-assert-error)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1080) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1287)
</details> </details>
## `subclass-of-final-class` ## `subclass-of-final-class`
@ -1067,7 +1244,7 @@ class B(A): ... # Error raised here
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20subclass-of-final-class) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20subclass-of-final-class)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L858) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1042)
</details> </details>
## `too-many-positional-arguments` ## `too-many-positional-arguments`
@ -1093,7 +1270,7 @@ f("foo") # Error raised here
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20too-many-positional-arguments) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20too-many-positional-arguments)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L903) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1087)
</details> </details>
## `type-assertion-failure` ## `type-assertion-failure`
@ -1120,7 +1297,7 @@ def _(x: int):
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20type-assertion-failure) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20type-assertion-failure)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L881) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1065)
</details> </details>
## `unavailable-implicit-super-arguments` ## `unavailable-implicit-super-arguments`
@ -1164,7 +1341,7 @@ class A:
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unavailable-implicit-super-arguments) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unavailable-implicit-super-arguments)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L924) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1108)
</details> </details>
## `unknown-argument` ## `unknown-argument`
@ -1190,7 +1367,7 @@ f(x=1, y=2) # Error raised here
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unknown-argument) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unknown-argument)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L979) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1165)
</details> </details>
## `unresolved-attribute` ## `unresolved-attribute`
@ -1204,11 +1381,20 @@ f(x=1, y=2) # Error raised here
Checks for unresolved attributes. Checks for unresolved attributes.
### Why is this bad? ### Why is this bad?
Accessing an unbound attribute will raise an `AttributeError` at runtime. An unresolved attribute is not guaranteed to exist from the type alone, so this could also indicate that the object is not of the type that the user expects. Accessing an unbound attribute will raise an `AttributeError` at runtime.
An unresolved attribute is not guaranteed to exist from the type alone,
so this could also indicate that the object is not of the type that the user expects.
### Examples
```python
class A: ...
A().foo # AttributeError: 'A' object has no attribute 'foo'
```
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-attribute) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-attribute)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1000) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1186)
</details> </details>
## `unresolved-import` ## `unresolved-import`
@ -1222,12 +1408,17 @@ Accessing an unbound attribute will raise an `AttributeError` at runtime. An unr
Checks for import statements for which the module cannot be resolved. Checks for import statements for which the module cannot be resolved.
### Why is this bad? ### Why is this bad?
Importing a module that cannot be resolved will raise an `ImportError` Importing a module that cannot be resolved will raise a `ModuleNotFoundError`
at runtime. at runtime.
### Examples
```python
import foo # ModuleNotFoundError: No module named 'foo'
```
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-import) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-import)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1013) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1208)
</details> </details>
## `unresolved-reference` ## `unresolved-reference`
@ -1251,7 +1442,7 @@ print(x) # NameError: name 'x' is not defined
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-reference) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-reference)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1027) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1227)
</details> </details>
## `unsupported-bool-conversion` ## `unsupported-bool-conversion`
@ -1287,7 +1478,7 @@ b1 < b2 < b1 # exception raised here
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-bool-conversion) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-bool-conversion)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L757) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L920)
</details> </details>
## `unsupported-operator` ## `unsupported-operator`
@ -1305,9 +1496,16 @@ the operands don't support the operator.
Attempting to use an unsupported operator will raise a `TypeError` at Attempting to use an unsupported operator will raise a `TypeError` at
runtime. runtime.
### Examples
```python
class A: ...
A() + A() # TypeError: unsupported operand type(s) for +: 'A' and 'A'
```
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-operator) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-operator)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1046) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1246)
</details> </details>
## `zero-stepsize-in-slice` ## `zero-stepsize-in-slice`
@ -1331,7 +1529,7 @@ l[1:10:0] # ValueError: slice step cannot be zero
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20zero-stepsize-in-slice) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20zero-stepsize-in-slice)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1061) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1268)
</details> </details>
## `call-possibly-unbound-method` ## `call-possibly-unbound-method`
@ -1394,9 +1592,18 @@ Checks for possibly unbound attributes.
### Why is this bad? ### Why is this bad?
Attempting to access an unbound attribute will raise an `AttributeError` at runtime. Attempting to access an unbound attribute will raise an `AttributeError` at runtime.
### Examples
```python
class A:
if b:
c = 0
A.c # AttributeError: type object 'A' has no attribute 'c'
```
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unbound-attribute) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unbound-attribute)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L809) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L972)
</details> </details>
## `possibly-unbound-import` ## `possibly-unbound-import`
@ -1413,9 +1620,21 @@ Checks for imports of symbols that may be unbound.
Importing an unbound module or name will raise a `ModuleNotFoundError` Importing an unbound module or name will raise a `ModuleNotFoundError`
or `ImportError` at runtime. or `ImportError` at runtime.
### Examples
```python
## module.py
import datetime
if datetime.date.today().weekday() != 6:
a = 1
## main.py
from module import a # ImportError: cannot import name 'a' from 'module'
```
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unbound-import) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unbound-import)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L822) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L994)
</details> </details>
## `redundant-cast` ## `redundant-cast`
@ -1441,7 +1660,7 @@ cast(int, f()) # Redundant
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20redundant-cast) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20redundant-cast)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1118) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1339)
</details> </details>
## `undefined-reveal` ## `undefined-reveal`
@ -1458,11 +1677,13 @@ Checks for calls to `reveal_type` without importing it.
Using `reveal_type` without importing it will raise a `NameError` at runtime. Using `reveal_type` without importing it will raise a `NameError` at runtime.
### Examples ### Examples
TODO #14889 ```python
reveal_type(1) # NameError: name 'reveal_type' is not defined
```
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20undefined-reveal) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20undefined-reveal)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L963) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1147)
</details> </details>
## `unknown-rule` ## `unknown-rule`
@ -1519,7 +1740,7 @@ print(x) # NameError: name 'x' is not defined
### Links ### Links
* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unresolved-reference) * [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unresolved-reference)
* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L836) * [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1020)
</details> </details>
## `unused-ignore-comment` ## `unused-ignore-comment`

View file

@ -114,7 +114,23 @@ declare_lint! {
declare_lint! { declare_lint! {
/// ## What it does /// ## What it does
/// Checks whether an argument is used as both a value and a type form in a call /// Checks whether an argument is used as both a value and a type form in a call.
///
/// ## Why is this bad?
/// Such calls have confusing semantics and often indicate a logic error.
///
/// ## Examples
/// ```python
/// from typing import reveal_type
/// from ty_extensions import is_fully_static
///
/// if flag:
/// f = repr # Expects a value
/// else:
/// f = is_fully_static # Expects a type form
///
/// f(int) # error
/// ```
pub(crate) static CONFLICTING_ARGUMENT_FORMS = { pub(crate) static CONFLICTING_ARGUMENT_FORMS = {
summary: "detects when an argument is used as both a value and a type form in a call", summary: "detects when an argument is used as both a value and a type form in a call",
status: LintStatus::preview("1.0.0"), status: LintStatus::preview("1.0.0"),
@ -130,6 +146,16 @@ declare_lint! {
/// A variable with two conflicting declarations likely indicates a mistake. /// A variable with two conflicting declarations likely indicates a mistake.
/// Moreover, it could lead to incorrect or ill-defined type inference for /// Moreover, it could lead to incorrect or ill-defined type inference for
/// other code that relies on these variables. /// other code that relies on these variables.
///
/// ## Examples
/// ```python
/// if b:
/// a: int
/// else:
/// a: str
///
/// a = 1
/// ```
pub(crate) static CONFLICTING_DECLARATIONS = { pub(crate) static CONFLICTING_DECLARATIONS = {
summary: "detects conflicting declarations", summary: "detects conflicting declarations",
status: LintStatus::preview("1.0.0"), status: LintStatus::preview("1.0.0"),
@ -138,7 +164,24 @@ declare_lint! {
} }
declare_lint! { declare_lint! {
/// TODO #14889 /// ## What it does
/// Checks for class definitions where the metaclass of the class
/// being created would not be a subclass of the metaclasses of
/// all the class's bases.
///
/// ## Why is it bad?
/// Such a class definition raises a `TypeError` at runtime.
///
/// ## Examples
/// ```python
/// class M1(type): ...
/// class M2(type): ...
/// class A(metaclass=M1): ...
/// class B(metaclass=M2): ...
///
/// # TypeError: metaclass conflict
/// class C(A, B): ...
/// ```
pub(crate) static CONFLICTING_METACLASS = { pub(crate) static CONFLICTING_METACLASS = {
summary: "detects conflicting metaclasses", summary: "detects conflicting metaclasses",
status: LintStatus::preview("1.0.0"), status: LintStatus::preview("1.0.0"),
@ -148,10 +191,23 @@ declare_lint! {
declare_lint! { declare_lint! {
/// ## What it does /// ## What it does
/// Checks for class definitions with a cyclic inheritance chain. /// Checks for class definitions in stub files that inherit
/// (directly or indirectly) from themselves.
/// ///
/// ## Why is it bad? /// ## Why is it bad?
/// TODO #14889 /// Although forward references are natively supported in stub files,
/// inheritance cycles are still disallowed, as it is impossible to
/// resolve a consistent [method resolution order] for a class that
/// inherits from itself.
///
/// ## Examples
/// ```python
/// # foo.pyi
/// class A(B): ...
/// class B(A): ...
/// ```
///
/// [method resolution order]: https://docs.python.org/3/glossary.html#term-method-resolution-order
pub(crate) static CYCLIC_CLASS_DEFINITION = { pub(crate) static CYCLIC_CLASS_DEFINITION = {
summary: "detects cyclic class definitions", summary: "detects cyclic class definitions",
status: LintStatus::preview("1.0.0"), status: LintStatus::preview("1.0.0"),
@ -182,7 +238,15 @@ declare_lint! {
/// Checks for class definitions with duplicate bases. /// Checks for class definitions with duplicate bases.
/// ///
/// ## Why is this bad? /// ## Why is this bad?
/// Class definitions with duplicate bases raise a `TypeError` at runtime. /// Class definitions with duplicate bases raise `TypeError` at runtime.
///
/// ## Examples
/// ```python
/// class A: ...
///
/// # TypeError: duplicate base class
/// class B(A, A): ...
/// ```
pub(crate) static DUPLICATE_BASE = { pub(crate) static DUPLICATE_BASE = {
summary: "detects class definitions with duplicate bases", summary: "detects class definitions with duplicate bases",
status: LintStatus::preview("1.0.0"), status: LintStatus::preview("1.0.0"),
@ -278,10 +342,21 @@ declare_lint! {
declare_lint! { declare_lint! {
/// ## What it does /// ## What it does
/// Checks for classes with an inconsistent method resolution order (MRO). /// Checks for classes with an inconsistent [method resolution order] (MRO).
/// ///
/// ## Why is this bad? /// ## Why is this bad?
/// Classes with an inconsistent MRO will raise a `TypeError` at runtime. /// Classes with an inconsistent MRO will raise a `TypeError` at runtime.
///
/// ## Examples
/// ```python
/// class A: ...
/// class B(A): ...
///
/// # TypeError: Cannot create a consistent method resolution order
/// class C(A, B): ...
/// ```
///
/// [method resolution order]: https://docs.python.org/3/glossary.html#term-method-resolution-order
pub(crate) static INCONSISTENT_MRO = { pub(crate) static INCONSISTENT_MRO = {
summary: "detects class definitions with an inconsistent MRO", summary: "detects class definitions with an inconsistent MRO",
status: LintStatus::preview("1.0.0"), status: LintStatus::preview("1.0.0"),
@ -296,6 +371,12 @@ declare_lint! {
/// ///
/// ## Why is this bad? /// ## Why is this bad?
/// Using an out of bounds index will raise an `IndexError` at runtime. /// Using an out of bounds index will raise an `IndexError` at runtime.
///
/// ## Examples
/// ```python
/// t = (0, 1, 2)
/// t[3] # IndexError: tuple index out of range
/// ```
pub(crate) static INDEX_OUT_OF_BOUNDS = { pub(crate) static INDEX_OUT_OF_BOUNDS = {
summary: "detects index out of bounds errors", summary: "detects index out of bounds errors",
status: LintStatus::preview("1.0.0"), status: LintStatus::preview("1.0.0"),
@ -344,7 +425,20 @@ declare_lint! {
} }
declare_lint! { declare_lint! {
/// TODO #14889 /// ## What it does
/// Checks for assignments where the type of the value
/// is not [assignable to] the type of the assignee.
///
/// ## Why is this bad?
/// Such assignments break the rules of the type system and
/// weaken a type checker's ability to accurately reason about your code.
///
/// ## Examples
/// ```python
/// a: int = ''
/// ```
///
/// [assignable to]: https://typing.python.org/en/latest/spec/glossary.html#term-assignable
pub(crate) static INVALID_ASSIGNMENT = { pub(crate) static INVALID_ASSIGNMENT = {
summary: "detects invalid assignments", summary: "detects invalid assignments",
status: LintStatus::preview("1.0.0"), status: LintStatus::preview("1.0.0"),
@ -355,14 +449,26 @@ declare_lint! {
declare_lint! { declare_lint! {
/// TODO #14889 /// TODO #14889
pub(crate) static INVALID_BASE = { pub(crate) static INVALID_BASE = {
summary: "detects class definitions with an invalid base", summary: "detects invalid bases in class definitions",
status: LintStatus::preview("1.0.0"), status: LintStatus::preview("1.0.0"),
default_level: Level::Error, default_level: Level::Error,
} }
} }
declare_lint! { declare_lint! {
/// TODO #14889 /// ## What it does
/// Checks for expressions used in `with` statements
/// that do not implement the context manager protocol.
///
/// ## Why is this bad?
/// Such a statement will raise `TypeError` at runtime.
///
/// ## Examples
/// ```python
/// # TypeError: 'int' object does not support the context manager protocol
/// with 1:
/// print(2)
/// ```
pub(crate) static INVALID_CONTEXT_MANAGER = { pub(crate) static INVALID_CONTEXT_MANAGER = {
summary: "detects expressions used in with statements that don't implement the context manager protocol", summary: "detects expressions used in with statements that don't implement the context manager protocol",
status: LintStatus::preview("1.0.0"), status: LintStatus::preview("1.0.0"),
@ -371,7 +477,21 @@ declare_lint! {
} }
declare_lint! { declare_lint! {
/// TODO #14889 /// ## What it does
/// Checks for declarations where the inferred type of an existing symbol
/// is not [assignable to] its post-hoc declared type.
///
/// ## Why is this bad?
/// Such declarations break the rules of the type system and
/// weaken a type checker's ability to accurately reason about your code.
///
/// ## Examples
/// ```python
/// a = 1
/// a: str
/// ```
///
/// [assignable to]: https://typing.python.org/en/latest/spec/glossary.html#term-assignable
pub(crate) static INVALID_DECLARATION = { pub(crate) static INVALID_DECLARATION = {
summary: "detects invalid declarations", summary: "detects invalid declarations",
status: LintStatus::preview("1.0.0"), status: LintStatus::preview("1.0.0"),
@ -541,10 +661,17 @@ declare_lint! {
declare_lint! { declare_lint! {
/// ## What it does /// ## What it does
/// Checks for default values that can't be assigned to the parameter's annotated type. /// Checks for default values that can't be
/// assigned to the parameter's annotated type.
/// ///
/// ## Why is this bad? /// ## Why is this bad?
/// TODO #14889 /// This breaks the rules of the type system and
/// weakens a type checker's ability to accurately reason about your code.
///
/// ## Examples
/// ```python
/// def f(a: int = ''): ...
/// ```
pub(crate) static INVALID_PARAMETER_DEFAULT = { pub(crate) static INVALID_PARAMETER_DEFAULT = {
summary: "detects default values that can't be assigned to the parameter's annotated type", summary: "detects default values that can't be assigned to the parameter's annotated type",
status: LintStatus::preview("1.0.0"), status: LintStatus::preview("1.0.0"),
@ -645,6 +772,12 @@ declare_lint! {
/// `typing` or `typing_extensions`, but it can also be defined locally. If defined locally, it /// `typing` or `typing_extensions`, but it can also be defined locally. If defined locally, it
/// must be assigned the value `False` at runtime; the type checker will consider its value to /// must be assigned the value `False` at runtime; the type checker will consider its value to
/// be `True`. If annotated, it must be annotated as a type that can accept `bool` values. /// be `True`. If annotated, it must be annotated as a type that can accept `bool` values.
///
/// ## Examples
/// ```python
/// TYPE_CHECKING: str
/// TYPE_CHECKING = ''
/// ```
pub(crate) static INVALID_TYPE_CHECKING_CONSTANT = { pub(crate) static INVALID_TYPE_CHECKING_CONSTANT = {
summary: "detects invalid `TYPE_CHECKING` constant assignments", summary: "detects invalid `TYPE_CHECKING` constant assignments",
status: LintStatus::preview("1.0.0"), status: LintStatus::preview("1.0.0"),
@ -654,10 +787,20 @@ declare_lint! {
declare_lint! { declare_lint! {
/// ## What it does /// ## What it does
/// Checks for invalid type expressions. /// Checks for expressions that are used as type expressions
/// but cannot validly be interpreted as such.
/// ///
/// ## Why is this bad? /// ## Why is this bad?
/// TODO #14889 /// Such expressions cannot be understood by ty.
/// In some cases, they might raise errors at runtime.
///
/// ## Examples
/// ```python
/// from typing import Annotated
///
/// a: type[1] # `1` is not a type
/// b: Annotated[int] # `Annotated` expects at least two arguments
/// ```
pub(crate) static INVALID_TYPE_FORM = { pub(crate) static INVALID_TYPE_FORM = {
summary: "detects invalid type forms", summary: "detects invalid type forms",
status: LintStatus::preview("1.0.0"), status: LintStatus::preview("1.0.0"),
@ -666,7 +809,27 @@ declare_lint! {
} }
declare_lint! { declare_lint! {
/// TODO #14889 /// ## What it does
/// Checks for constrained [type variables] with only one constraint.
///
/// ## Why is this bad?
/// A constrained type variable must have at least two constraints.
///
/// ## Examples
/// ```python
/// from typing import TypeVar
///
/// T = TypeVar('T', str) # invalid constrained TypeVar
/// ```
///
/// Use instead:
/// ```python
/// T = TypeVar('T', str, int) # valid constrained TypeVar
/// # or
/// T = TypeVar('T', bound=str) # valid bound TypeVar
/// ```
///
/// [type variables]: https://docs.python.org/3/library/typing.html#typing.TypeVar
pub(crate) static INVALID_TYPE_VARIABLE_CONSTRAINTS = { pub(crate) static INVALID_TYPE_VARIABLE_CONSTRAINTS = {
summary: "detects invalid type variable constraints", summary: "detects invalid type variable constraints",
status: LintStatus::preview("1.0.0"), status: LintStatus::preview("1.0.0"),
@ -812,6 +975,15 @@ declare_lint! {
/// ///
/// ## Why is this bad? /// ## Why is this bad?
/// Attempting to access an unbound attribute will raise an `AttributeError` at runtime. /// Attempting to access an unbound attribute will raise an `AttributeError` at runtime.
///
/// ## Examples
/// ```python
/// class A:
/// if b:
/// c = 0
///
/// A.c # AttributeError: type object 'A' has no attribute 'c'
/// ```
pub(crate) static POSSIBLY_UNBOUND_ATTRIBUTE = { pub(crate) static POSSIBLY_UNBOUND_ATTRIBUTE = {
summary: "detects references to possibly unbound attributes", summary: "detects references to possibly unbound attributes",
status: LintStatus::preview("1.0.0"), status: LintStatus::preview("1.0.0"),
@ -826,6 +998,18 @@ declare_lint! {
/// ## Why is this bad? /// ## Why is this bad?
/// Importing an unbound module or name will raise a `ModuleNotFoundError` /// Importing an unbound module or name will raise a `ModuleNotFoundError`
/// or `ImportError` at runtime. /// or `ImportError` at runtime.
///
/// ## Examples
/// ```python
/// # module.py
/// import datetime
///
/// if datetime.date.today().weekday() != 6:
/// a = 1
///
/// # main.py
/// from module import a # ImportError: cannot import name 'a' from 'module'
/// ```
pub(crate) static POSSIBLY_UNBOUND_IMPORT = { pub(crate) static POSSIBLY_UNBOUND_IMPORT = {
summary: "detects possibly unbound imports", summary: "detects possibly unbound imports",
status: LintStatus::preview("1.0.0"), status: LintStatus::preview("1.0.0"),
@ -968,7 +1152,9 @@ declare_lint! {
/// Using `reveal_type` without importing it will raise a `NameError` at runtime. /// Using `reveal_type` without importing it will raise a `NameError` at runtime.
/// ///
/// ## Examples /// ## Examples
/// TODO #14889 /// ```python
/// reveal_type(1) # NameError: name 'reveal_type' is not defined
/// ```
pub(crate) static UNDEFINED_REVEAL = { pub(crate) static UNDEFINED_REVEAL = {
summary: "detects usages of `reveal_type` without importing it", summary: "detects usages of `reveal_type` without importing it",
status: LintStatus::preview("1.0.0"), status: LintStatus::preview("1.0.0"),
@ -1002,7 +1188,16 @@ declare_lint! {
/// Checks for unresolved attributes. /// Checks for unresolved attributes.
/// ///
/// ## Why is this bad? /// ## Why is this bad?
/// Accessing an unbound attribute will raise an `AttributeError` at runtime. An unresolved attribute is not guaranteed to exist from the type alone, so this could also indicate that the object is not of the type that the user expects. /// Accessing an unbound attribute will raise an `AttributeError` at runtime.
/// An unresolved attribute is not guaranteed to exist from the type alone,
/// so this could also indicate that the object is not of the type that the user expects.
///
/// ## Examples
/// ```python
/// class A: ...
///
/// A().foo # AttributeError: 'A' object has no attribute 'foo'
/// ```
pub(crate) static UNRESOLVED_ATTRIBUTE = { pub(crate) static UNRESOLVED_ATTRIBUTE = {
summary: "detects references to unresolved attributes", summary: "detects references to unresolved attributes",
status: LintStatus::preview("1.0.0"), status: LintStatus::preview("1.0.0"),
@ -1015,8 +1210,13 @@ declare_lint! {
/// Checks for import statements for which the module cannot be resolved. /// Checks for import statements for which the module cannot be resolved.
/// ///
/// ## Why is this bad? /// ## Why is this bad?
/// Importing a module that cannot be resolved will raise an `ImportError` /// Importing a module that cannot be resolved will raise a `ModuleNotFoundError`
/// at runtime. /// at runtime.
///
/// ## Examples
/// ```python
/// import foo # ModuleNotFoundError: No module named 'foo'
/// ```
pub(crate) static UNRESOLVED_IMPORT = { pub(crate) static UNRESOLVED_IMPORT = {
summary: "detects unresolved imports", summary: "detects unresolved imports",
status: LintStatus::preview("1.0.0"), status: LintStatus::preview("1.0.0"),
@ -1051,6 +1251,13 @@ declare_lint! {
/// ## Why is this bad? /// ## Why is this bad?
/// Attempting to use an unsupported operator will raise a `TypeError` at /// Attempting to use an unsupported operator will raise a `TypeError` at
/// runtime. /// runtime.
///
/// ## Examples
/// ```python
/// class A: ...
///
/// A() + A() # TypeError: unsupported operand type(s) for +: 'A' and 'A'
/// ```
pub(crate) static UNSUPPORTED_OPERATOR = { pub(crate) static UNSUPPORTED_OPERATOR = {
summary: "detects binary, unary, or comparison expressions where the operands don't support the operator", summary: "detects binary, unary, or comparison expressions where the operands don't support the operator",
status: LintStatus::preview("1.0.0"), status: LintStatus::preview("1.0.0"),
@ -1081,6 +1288,11 @@ declare_lint! {
/// ## What it does /// ## What it does
/// Makes sure that the argument of `static_assert` is statically known to be true. /// Makes sure that the argument of `static_assert` is statically known to be true.
/// ///
/// ## Why is this bad?
/// A `static_assert` call represents an explicit request from the user
/// for the type checker to emit an error if the argument cannot be verified
/// to evaluate to `True` in a boolean context.
///
/// ## Examples /// ## Examples
/// ```python /// ```python
/// from ty_extensions import static_assert /// from ty_extensions import static_assert
@ -1098,15 +1310,24 @@ declare_lint! {
declare_lint! { declare_lint! {
/// ## What it does /// ## What it does
/// Makes sure that instance attribute accesses are valid. /// Checks for assignments to class variables from instances
/// and assignments to instance variables from its class.
///
/// ## Why is this bad?
/// Incorrect assignments break the rules of the type system and
/// weaken a type checker's ability to accurately reason about your code.
/// ///
/// ## Examples /// ## Examples
/// ```python /// ```python
/// class C: /// class C:
/// var: ClassVar[int] = 1 /// class_var: ClassVar[int] = 1
/// instance_var: int
/// ///
/// C.var = 3 # okay /// C.class_var = 3 # okay
/// C().var = 3 # error: Cannot assign to class variable /// C().class_var = 3 # error: Cannot assign to class variable
///
/// C().instance_var = 3 # okay
/// C.instance_var = 3 # error: Cannot assign to instance variable
/// ``` /// ```
pub(crate) static INVALID_ATTRIBUTE_ACCESS = { pub(crate) static INVALID_ATTRIBUTE_ACCESS = {
summary: "Invalid attribute access", summary: "Invalid attribute access",

View file

@ -252,7 +252,7 @@
}, },
"conflicting-argument-forms": { "conflicting-argument-forms": {
"title": "detects when an argument is used as both a value and a type form in a call", "title": "detects when an argument is used as both a value and a type form in a call",
"description": "## What it does\nChecks whether an argument is used as both a value and a type form in a call", "description": "## What it does\nChecks whether an argument is used as both a value and a type form in a call.\n\n## Why is this bad?\nSuch calls have confusing semantics and often indicate a logic error.\n\n## Examples\n```python\nfrom typing import reveal_type\nfrom ty_extensions import is_fully_static\n\nif flag:\n f = repr # Expects a value\nelse:\n f = is_fully_static # Expects a type form\n\nf(int) # error\n```",
"default": "error", "default": "error",
"oneOf": [ "oneOf": [
{ {
@ -262,7 +262,7 @@
}, },
"conflicting-declarations": { "conflicting-declarations": {
"title": "detects conflicting declarations", "title": "detects conflicting declarations",
"description": "## What it does\nChecks whether a variable has been declared as two conflicting types.\n\n## Why is this bad\nA variable with two conflicting declarations likely indicates a mistake.\nMoreover, it could lead to incorrect or ill-defined type inference for\nother code that relies on these variables.", "description": "## What it does\nChecks whether a variable has been declared as two conflicting types.\n\n## Why is this bad\nA variable with two conflicting declarations likely indicates a mistake.\nMoreover, it could lead to incorrect or ill-defined type inference for\nother code that relies on these variables.\n\n## Examples\n```python\nif b:\n a: int\nelse:\n a: str\n\na = 1\n```",
"default": "error", "default": "error",
"oneOf": [ "oneOf": [
{ {
@ -272,7 +272,7 @@
}, },
"conflicting-metaclass": { "conflicting-metaclass": {
"title": "detects conflicting metaclasses", "title": "detects conflicting metaclasses",
"description": "TODO #14889", "description": "## What it does\nChecks for class definitions where the metaclass of the class\nbeing created would not be a subclass of the metaclasses of\nall the class's bases.\n\n## Why is it bad?\nSuch a class definition raises a `TypeError` at runtime.\n\n## Examples\n```python\nclass M1(type): ...\nclass M2(type): ...\nclass A(metaclass=M1): ...\nclass B(metaclass=M2): ...\n\n# TypeError: metaclass conflict\nclass C(A, B): ...\n```",
"default": "error", "default": "error",
"oneOf": [ "oneOf": [
{ {
@ -282,7 +282,7 @@
}, },
"cyclic-class-definition": { "cyclic-class-definition": {
"title": "detects cyclic class definitions", "title": "detects cyclic class definitions",
"description": "## What it does\nChecks for class definitions with a cyclic inheritance chain.\n\n## Why is it bad?\nTODO #14889", "description": "## What it does\nChecks for class definitions in stub files that inherit\n(directly or indirectly) from themselves.\n\n## Why is it bad?\nAlthough forward references are natively supported in stub files,\ninheritance cycles are still disallowed, as it is impossible to\nresolve a consistent [method resolution order] for a class that\ninherits from itself.\n\n## Examples\n```python\n# foo.pyi\nclass A(B): ...\nclass B(A): ...\n```\n\n[method resolution order]: https://docs.python.org/3/glossary.html#term-method-resolution-order",
"default": "error", "default": "error",
"oneOf": [ "oneOf": [
{ {
@ -302,7 +302,7 @@
}, },
"duplicate-base": { "duplicate-base": {
"title": "detects class definitions with duplicate bases", "title": "detects class definitions with duplicate bases",
"description": "## What it does\nChecks for class definitions with duplicate bases.\n\n## Why is this bad?\nClass definitions with duplicate bases raise a `TypeError` at runtime.", "description": "## What it does\nChecks for class definitions with duplicate bases.\n\n## Why is this bad?\nClass definitions with duplicate bases raise `TypeError` at runtime.\n\n## Examples\n```python\nclass A: ...\n\n# TypeError: duplicate base class\nclass B(A, A): ...\n```",
"default": "error", "default": "error",
"oneOf": [ "oneOf": [
{ {
@ -352,7 +352,7 @@
}, },
"inconsistent-mro": { "inconsistent-mro": {
"title": "detects class definitions with an inconsistent MRO", "title": "detects class definitions with an inconsistent MRO",
"description": "## What it does\nChecks for classes with an inconsistent method resolution order (MRO).\n\n## Why is this bad?\nClasses with an inconsistent MRO will raise a `TypeError` at runtime.", "description": "## What it does\nChecks for classes with an inconsistent [method resolution order] (MRO).\n\n## Why is this bad?\nClasses with an inconsistent MRO will raise a `TypeError` at runtime.\n\n## Examples\n```python\nclass A: ...\nclass B(A): ...\n\n# TypeError: Cannot create a consistent method resolution order\nclass C(A, B): ...\n```\n\n[method resolution order]: https://docs.python.org/3/glossary.html#term-method-resolution-order",
"default": "error", "default": "error",
"oneOf": [ "oneOf": [
{ {
@ -362,7 +362,7 @@
}, },
"index-out-of-bounds": { "index-out-of-bounds": {
"title": "detects index out of bounds errors", "title": "detects index out of bounds errors",
"description": "## What it does\nChecks for attempts to use an out of bounds index to get an item from\na container.\n\n## Why is this bad?\nUsing an out of bounds index will raise an `IndexError` at runtime.", "description": "## What it does\nChecks for attempts to use an out of bounds index to get an item from\na container.\n\n## Why is this bad?\nUsing an out of bounds index will raise an `IndexError` at runtime.\n\n## Examples\n```python\nt = (0, 1, 2)\nt[3] # IndexError: tuple index out of range\n```",
"default": "error", "default": "error",
"oneOf": [ "oneOf": [
{ {
@ -382,7 +382,7 @@
}, },
"invalid-assignment": { "invalid-assignment": {
"title": "detects invalid assignments", "title": "detects invalid assignments",
"description": "TODO #14889", "description": "## What it does\nChecks for assignments where the type of the value\nis not [assignable to] the type of the assignee.\n\n## Why is this bad?\nSuch assignments break the rules of the type system and\nweaken a type checker's ability to accurately reason about your code.\n\n## Examples\n```python\na: int = ''\n```\n\n[assignable to]: https://typing.python.org/en/latest/spec/glossary.html#term-assignable",
"default": "error", "default": "error",
"oneOf": [ "oneOf": [
{ {
@ -392,7 +392,7 @@
}, },
"invalid-attribute-access": { "invalid-attribute-access": {
"title": "Invalid attribute access", "title": "Invalid attribute access",
"description": "## What it does\nMakes sure that instance attribute accesses are valid.\n\n## Examples\n```python\nclass C:\n var: ClassVar[int] = 1\n\nC.var = 3 # okay\nC().var = 3 # error: Cannot assign to class variable\n```", "description": "## What it does\nChecks for assignments to class variables from instances\nand assignments to instance variables from its class.\n\n## Why is this bad?\nIncorrect assignments break the rules of the type system and\nweaken a type checker's ability to accurately reason about your code.\n\n## Examples\n```python\nclass C:\n class_var: ClassVar[int] = 1\n instance_var: int\n\nC.class_var = 3 # okay\nC().class_var = 3 # error: Cannot assign to class variable\n\nC().instance_var = 3 # okay\nC.instance_var = 3 # error: Cannot assign to instance variable\n```",
"default": "error", "default": "error",
"oneOf": [ "oneOf": [
{ {
@ -401,7 +401,7 @@
] ]
}, },
"invalid-base": { "invalid-base": {
"title": "detects class definitions with an invalid base", "title": "detects invalid bases in class definitions",
"description": "TODO #14889", "description": "TODO #14889",
"default": "error", "default": "error",
"oneOf": [ "oneOf": [
@ -412,7 +412,7 @@
}, },
"invalid-context-manager": { "invalid-context-manager": {
"title": "detects expressions used in with statements that don't implement the context manager protocol", "title": "detects expressions used in with statements that don't implement the context manager protocol",
"description": "TODO #14889", "description": "## What it does\nChecks for expressions used in `with` statements\nthat do not implement the context manager protocol.\n\n## Why is this bad?\nSuch a statement will raise `TypeError` at runtime.\n\n## Examples\n```python\n# TypeError: 'int' object does not support the context manager protocol\nwith 1:\n print(2)\n```",
"default": "error", "default": "error",
"oneOf": [ "oneOf": [
{ {
@ -422,7 +422,7 @@
}, },
"invalid-declaration": { "invalid-declaration": {
"title": "detects invalid declarations", "title": "detects invalid declarations",
"description": "TODO #14889", "description": "## What it does\nChecks for declarations where the inferred type of an existing symbol\nis not [assignable to] its post-hoc declared type.\n\n## Why is this bad?\nSuch declarations break the rules of the type system and\nweaken a type checker's ability to accurately reason about your code.\n\n## Examples\n```python\na = 1\na: str\n```\n\n[assignable to]: https://typing.python.org/en/latest/spec/glossary.html#term-assignable",
"default": "error", "default": "error",
"oneOf": [ "oneOf": [
{ {
@ -492,7 +492,7 @@
}, },
"invalid-parameter-default": { "invalid-parameter-default": {
"title": "detects default values that can't be assigned to the parameter's annotated type", "title": "detects default values that can't be assigned to the parameter's annotated type",
"description": "## What it does\nChecks for default values that can't be assigned to the parameter's annotated type.\n\n## Why is this bad?\nTODO #14889", "description": "## What it does\nChecks for default values that can't be\nassigned to the parameter's annotated type.\n\n## Why is this bad?\nThis breaks the rules of the type system and\nweakens a type checker's ability to accurately reason about your code.\n\n## Examples\n```python\ndef f(a: int = ''): ...\n```",
"default": "error", "default": "error",
"oneOf": [ "oneOf": [
{ {
@ -552,7 +552,7 @@
}, },
"invalid-type-checking-constant": { "invalid-type-checking-constant": {
"title": "detects invalid `TYPE_CHECKING` constant assignments", "title": "detects invalid `TYPE_CHECKING` constant assignments",
"description": "## What it does\nChecks for a value other than `False` assigned to the `TYPE_CHECKING` variable, or an\nannotation not assignable from `bool`.\n\n## Why is this bad?\nThe name `TYPE_CHECKING` is reserved for a flag that can be used to provide conditional\ncode seen only by the type checker, and not at runtime. Normally this flag is imported from\n`typing` or `typing_extensions`, but it can also be defined locally. If defined locally, it\nmust be assigned the value `False` at runtime; the type checker will consider its value to\nbe `True`. If annotated, it must be annotated as a type that can accept `bool` values.", "description": "## What it does\nChecks for a value other than `False` assigned to the `TYPE_CHECKING` variable, or an\nannotation not assignable from `bool`.\n\n## Why is this bad?\nThe name `TYPE_CHECKING` is reserved for a flag that can be used to provide conditional\ncode seen only by the type checker, and not at runtime. Normally this flag is imported from\n`typing` or `typing_extensions`, but it can also be defined locally. If defined locally, it\nmust be assigned the value `False` at runtime; the type checker will consider its value to\nbe `True`. If annotated, it must be annotated as a type that can accept `bool` values.\n\n## Examples\n```python\nTYPE_CHECKING: str\nTYPE_CHECKING = ''\n```",
"default": "error", "default": "error",
"oneOf": [ "oneOf": [
{ {
@ -562,7 +562,7 @@
}, },
"invalid-type-form": { "invalid-type-form": {
"title": "detects invalid type forms", "title": "detects invalid type forms",
"description": "## What it does\nChecks for invalid type expressions.\n\n## Why is this bad?\nTODO #14889", "description": "## What it does\nChecks for expressions that are used as type expressions\nbut cannot validly be interpreted as such.\n\n## Why is this bad?\nSuch expressions cannot be understood by ty.\nIn some cases, they might raise errors at runtime.\n\n## Examples\n```python\nfrom typing import Annotated\n\na: type[1] # `1` is not a type\nb: Annotated[int] # `Annotated` expects at least two arguments\n```",
"default": "error", "default": "error",
"oneOf": [ "oneOf": [
{ {
@ -572,7 +572,7 @@
}, },
"invalid-type-variable-constraints": { "invalid-type-variable-constraints": {
"title": "detects invalid type variable constraints", "title": "detects invalid type variable constraints",
"description": "TODO #14889", "description": "## What it does\nChecks for constrained [type variables] with only one constraint.\n\n## Why is this bad?\nA constrained type variable must have at least two constraints.\n\n## Examples\n```python\nfrom typing import TypeVar\n\nT = TypeVar('T', str) # invalid constrained TypeVar\n```\n\nUse instead:\n```python\nT = TypeVar('T', str, int) # valid constrained TypeVar\n# or\nT = TypeVar('T', bound=str) # valid bound TypeVar\n```\n\n[type variables]: https://docs.python.org/3/library/typing.html#typing.TypeVar",
"default": "error", "default": "error",
"oneOf": [ "oneOf": [
{ {
@ -632,7 +632,7 @@
}, },
"possibly-unbound-attribute": { "possibly-unbound-attribute": {
"title": "detects references to possibly unbound attributes", "title": "detects references to possibly unbound attributes",
"description": "## What it does\nChecks for possibly unbound attributes.\n\n## Why is this bad?\nAttempting to access an unbound attribute will raise an `AttributeError` at runtime.", "description": "## What it does\nChecks for possibly unbound attributes.\n\n## Why is this bad?\nAttempting to access an unbound attribute will raise an `AttributeError` at runtime.\n\n## Examples\n```python\nclass A:\n if b:\n c = 0\n\nA.c # AttributeError: type object 'A' has no attribute 'c'\n```",
"default": "warn", "default": "warn",
"oneOf": [ "oneOf": [
{ {
@ -642,7 +642,7 @@
}, },
"possibly-unbound-import": { "possibly-unbound-import": {
"title": "detects possibly unbound imports", "title": "detects possibly unbound imports",
"description": "## What it does\nChecks for imports of symbols that may be unbound.\n\n## Why is this bad?\nImporting an unbound module or name will raise a `ModuleNotFoundError`\nor `ImportError` at runtime.", "description": "## What it does\nChecks for imports of symbols that may be unbound.\n\n## Why is this bad?\nImporting an unbound module or name will raise a `ModuleNotFoundError`\nor `ImportError` at runtime.\n\n## Examples\n```python\n# module.py\nimport datetime\n\nif datetime.date.today().weekday() != 6:\n a = 1\n\n# main.py\nfrom module import a # ImportError: cannot import name 'a' from 'module'\n```",
"default": "warn", "default": "warn",
"oneOf": [ "oneOf": [
{ {
@ -682,7 +682,7 @@
}, },
"static-assert-error": { "static-assert-error": {
"title": "Failed static assertion", "title": "Failed static assertion",
"description": "## What it does\nMakes sure that the argument of `static_assert` is statically known to be true.\n\n## Examples\n```python\nfrom ty_extensions import static_assert\n\nstatic_assert(1 + 1 == 3) # error: evaluates to `False`\n\nstatic_assert(int(2.0 * 3.0) == 6) # error: does not have a statically known truthiness\n```", "description": "## What it does\nMakes sure that the argument of `static_assert` is statically known to be true.\n\n## Why is this bad?\nA `static_assert` call represents an explicit request from the user\nfor the type checker to emit an error if the argument cannot be verified\nto evaluate to `True` in a boolean context.\n\n## Examples\n```python\nfrom ty_extensions import static_assert\n\nstatic_assert(1 + 1 == 3) # error: evaluates to `False`\n\nstatic_assert(int(2.0 * 3.0) == 6) # error: does not have a statically known truthiness\n```",
"default": "error", "default": "error",
"oneOf": [ "oneOf": [
{ {
@ -732,7 +732,7 @@
}, },
"undefined-reveal": { "undefined-reveal": {
"title": "detects usages of `reveal_type` without importing it", "title": "detects usages of `reveal_type` without importing it",
"description": "## What it does\nChecks for calls to `reveal_type` without importing it.\n\n## Why is this bad?\nUsing `reveal_type` without importing it will raise a `NameError` at runtime.\n\n## Examples\nTODO #14889", "description": "## What it does\nChecks for calls to `reveal_type` without importing it.\n\n## Why is this bad?\nUsing `reveal_type` without importing it will raise a `NameError` at runtime.\n\n## Examples\n```python\nreveal_type(1) # NameError: name 'reveal_type' is not defined\n```",
"default": "warn", "default": "warn",
"oneOf": [ "oneOf": [
{ {
@ -762,7 +762,7 @@
}, },
"unresolved-attribute": { "unresolved-attribute": {
"title": "detects references to unresolved attributes", "title": "detects references to unresolved attributes",
"description": "## What it does\nChecks for unresolved attributes.\n\n## Why is this bad?\nAccessing an unbound attribute will raise an `AttributeError` at runtime. An unresolved attribute is not guaranteed to exist from the type alone, so this could also indicate that the object is not of the type that the user expects.", "description": "## What it does\nChecks for unresolved attributes.\n\n## Why is this bad?\nAccessing an unbound attribute will raise an `AttributeError` at runtime.\nAn unresolved attribute is not guaranteed to exist from the type alone,\nso this could also indicate that the object is not of the type that the user expects.\n\n## Examples\n```python\nclass A: ...\n\nA().foo # AttributeError: 'A' object has no attribute 'foo'\n```",
"default": "error", "default": "error",
"oneOf": [ "oneOf": [
{ {
@ -772,7 +772,7 @@
}, },
"unresolved-import": { "unresolved-import": {
"title": "detects unresolved imports", "title": "detects unresolved imports",
"description": "## What it does\nChecks for import statements for which the module cannot be resolved.\n\n## Why is this bad?\nImporting a module that cannot be resolved will raise an `ImportError`\nat runtime.", "description": "## What it does\nChecks for import statements for which the module cannot be resolved.\n\n## Why is this bad?\nImporting a module that cannot be resolved will raise a `ModuleNotFoundError`\nat runtime.\n\n## Examples\n```python\nimport foo # ModuleNotFoundError: No module named 'foo'\n```",
"default": "error", "default": "error",
"oneOf": [ "oneOf": [
{ {
@ -802,7 +802,7 @@
}, },
"unsupported-operator": { "unsupported-operator": {
"title": "detects binary, unary, or comparison expressions where the operands don't support the operator", "title": "detects binary, unary, or comparison expressions where the operands don't support the operator",
"description": "## What it does\nChecks for binary expressions, comparisons, and unary expressions where\nthe operands don't support the operator.\n\n## Why is this bad?\nAttempting to use an unsupported operator will raise a `TypeError` at\nruntime.", "description": "## What it does\nChecks for binary expressions, comparisons, and unary expressions where\nthe operands don't support the operator.\n\n## Why is this bad?\nAttempting to use an unsupported operator will raise a `TypeError` at\nruntime.\n\n## Examples\n```python\nclass A: ...\n\nA() + A() # TypeError: unsupported operand type(s) for +: 'A' and 'A'\n```",
"default": "error", "default": "error",
"oneOf": [ "oneOf": [
{ {