diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d84a1c6bf6..3b17534533 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,6 +5,7 @@ exclude: | .github/workflows/release.yml| crates/ty_vendored/vendor/.*| crates/ty_project/resources/.*| + crates/ty/docs/rules.md| crates/ruff_benchmark/resources/.*| crates/ruff_linter/resources/.*| crates/ruff_linter/src/rules/.*/snapshots/.*| diff --git a/Cargo.lock b/Cargo.lock index 45855fee99..d325171eec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2726,6 +2726,7 @@ dependencies = [ "tracing-indicatif", "tracing-subscriber", "ty_project", + "url", ] [[package]] diff --git a/crates/ruff_dev/Cargo.toml b/crates/ruff_dev/Cargo.toml index c007005860..e6194130f4 100644 --- a/crates/ruff_dev/Cargo.toml +++ b/crates/ruff_dev/Cargo.toml @@ -44,6 +44,7 @@ toml = { workspace = true, features = ["parse"] } tracing = { workspace = true } tracing-indicatif = { workspace = true } tracing-subscriber = { workspace = true, features = ["env-filter"] } +url = { workspace = true } [dev-dependencies] indoc = { workspace = true } diff --git a/crates/ruff_dev/src/generate_all.rs b/crates/ruff_dev/src/generate_all.rs index d4fd30a869..9a2963bb60 100644 --- a/crates/ruff_dev/src/generate_all.rs +++ b/crates/ruff_dev/src/generate_all.rs @@ -2,7 +2,9 @@ use anyhow::Result; -use crate::{generate_cli_help, generate_docs, generate_json_schema, generate_ty_schema}; +use crate::{ + generate_cli_help, generate_docs, generate_json_schema, generate_ty_rules, generate_ty_schema, +}; pub(crate) const REGENERATE_ALL_COMMAND: &str = "cargo dev generate-all"; @@ -38,5 +40,6 @@ pub(crate) fn main(args: &Args) -> Result<()> { generate_docs::main(&generate_docs::Args { dry_run: args.mode.is_dry_run(), })?; + generate_ty_rules::main(&generate_ty_rules::Args { mode: args.mode })?; Ok(()) } diff --git a/crates/ruff_dev/src/generate_ty_rules.rs b/crates/ruff_dev/src/generate_ty_rules.rs new file mode 100644 index 0000000000..6586afc738 --- /dev/null +++ b/crates/ruff_dev/src/generate_ty_rules.rs @@ -0,0 +1,144 @@ +//! Generates the rules table for ty +#![allow(clippy::print_stdout, clippy::print_stderr)] + +use std::borrow::Cow; +use std::fmt::Write as _; +use std::fs; +use std::path::PathBuf; + +use anyhow::{bail, Result}; +use itertools::Itertools as _; +use pretty_assertions::StrComparison; + +use crate::generate_all::{Mode, REGENERATE_ALL_COMMAND}; +use crate::ROOT_DIR; + +#[derive(clap::Args)] +pub(crate) struct Args { + /// Write the generated table to stdout (rather than to `ty.schema.json`). + #[arg(long, default_value_t, value_enum)] + pub(crate) mode: Mode, +} + +pub(crate) fn main(args: &Args) -> Result<()> { + let markdown = generate_markdown(); + let filename = "crates/ty/docs/rules.md"; + let schema_path = PathBuf::from(ROOT_DIR).join(filename); + + match args.mode { + Mode::DryRun => { + println!("{markdown}"); + } + Mode::Check => { + let current = fs::read_to_string(schema_path)?; + if current == markdown { + println!("Up-to-date: {filename}"); + } else { + let comparison = StrComparison::new(¤t, &markdown); + bail!("{filename} changed, please run `{REGENERATE_ALL_COMMAND}`:\n{comparison}"); + } + } + Mode::Write => { + let current = fs::read_to_string(&schema_path)?; + if current == markdown { + println!("Up-to-date: {filename}"); + } else { + println!("Updating: {filename}"); + fs::write(schema_path, markdown.as_bytes())?; + } + } + } + + Ok(()) +} + +fn generate_markdown() -> String { + let registry = &*ty_project::DEFAULT_LINT_REGISTRY; + + let mut output = String::new(); + + let _ = writeln!(&mut output, "# Rules\n"); + + let mut lints: Vec<_> = registry.lints().iter().collect(); + lints.sort_by(|a, b| { + a.default_level() + .cmp(&b.default_level()) + .reverse() + .then_with(|| a.name().cmp(&b.name())) + }); + + for lint in lints { + let _ = writeln!(&mut output, "## `{rule_name}`\n", rule_name = lint.name()); + + // Increase the header-level by one + let documentation = lint + .documentation_lines() + .map(|line| { + if line.starts_with('#') { + Cow::Owned(format!("#{line}")) + } else { + Cow::Borrowed(line) + } + }) + .join("\n"); + + let _ = writeln!( + &mut output, + r#"**Default level**: {level} + +
+{summary} + +{documentation} + +### Links +* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20{encoded_name}) +* [View source](https://github.com/astral-sh/ruff/blob/main/{file}#L{line}) +
+"#, + level = lint.default_level(), + // GitHub doesn't support markdown in `summary` headers + summary = replace_inline_code(lint.summary()), + encoded_name = url::form_urlencoded::byte_serialize(lint.name().as_str().as_bytes()) + .collect::(), + file = url::form_urlencoded::byte_serialize(lint.file().replace('\\', "/").as_bytes()) + .collect::(), + line = lint.line(), + ); + } + + output +} + +/// Replaces inline code blocks (`code`) with `code` +fn replace_inline_code(input: &str) -> String { + let mut output = String::new(); + let mut parts = input.split('`'); + + while let Some(before) = parts.next() { + if let Some(between) = parts.next() { + output.push_str(before); + output.push_str(""); + output.push_str(between); + output.push_str(""); + } else { + output.push_str(before); + } + } + + output +} + +#[cfg(test)] +mod tests { + use anyhow::Result; + + use crate::generate_all::Mode; + + use super::{main, Args}; + + #[test] + fn ty_rules_up_to_date() -> Result<()> { + main(&Args { mode: Mode::Check }) + } +} diff --git a/crates/ruff_dev/src/main.rs b/crates/ruff_dev/src/main.rs index f562d1d0ea..cfbbd039fe 100644 --- a/crates/ruff_dev/src/main.rs +++ b/crates/ruff_dev/src/main.rs @@ -15,6 +15,7 @@ mod generate_docs; mod generate_json_schema; mod generate_options; mod generate_rules_table; +mod generate_ty_rules; mod generate_ty_schema; mod print_ast; mod print_cst; @@ -44,6 +45,7 @@ enum Command { GenerateTySchema(generate_ty_schema::Args), /// Generate a Markdown-compatible table of supported lint rules. GenerateRulesTable, + GenerateTyRules(generate_ty_rules::Args), /// Generate a Markdown-compatible listing of configuration options. GenerateOptions, /// Generate CLI help. @@ -88,6 +90,7 @@ fn main() -> Result { Command::GenerateJSONSchema(args) => generate_json_schema::main(&args)?, Command::GenerateTySchema(args) => generate_ty_schema::main(&args)?, Command::GenerateRulesTable => println!("{}", generate_rules_table::generate()), + Command::GenerateTyRules(args) => generate_ty_rules::main(&args)?, Command::GenerateOptions => println!("{}", generate_options::generate()), Command::GenerateCliHelp(args) => generate_cli_help::main(&args)?, Command::GenerateDocs(args) => generate_docs::main(&args)?, diff --git a/crates/ty/docs/rules.md b/crates/ty/docs/rules.md new file mode 100644 index 0000000000..7dba79499c --- /dev/null +++ b/crates/ty/docs/rules.md @@ -0,0 +1,1554 @@ +# Rules + +## `byte-string-type-annotation` + +**Default level**: error + +
+detects byte strings in type annotation positions + +### What it does +Checks for byte-strings in type annotation positions. + +### Why is this bad? +Static analysis tools like ty can't analyse type annotations that use byte-string notation. + +### Examples +```python +def test(): -> b"int": + ... +``` + +Use instead: +```python +def test(): -> "int": + ... +``` + +### Links +* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20byte-string-type-annotation) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fstring_annotation.rs#L36) +
+ +## `call-non-callable` + +**Default level**: error + +
+detects calls to non-callable objects + +### What it does +Checks for calls to non-callable objects. + +### Why is this bad? +Calling a non-callable object will raise a `TypeError` at runtime. + +### Examples +```python +4() # TypeError: 'int' object is not callable +``` + +### Links +* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20call-non-callable) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L84) +
+ +## `conflicting-argument-forms` + +**Default level**: error + +
+detects when an argument is used as both a value and a type form in a call + +### What it does +Checks whether an argument is used as both a value and a type form in a call + +### Links +* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-argument-forms) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L115) +
+ +## `conflicting-declarations` + +**Default level**: error + +
+detects conflicting declarations + +### What it does +Checks whether a variable has been declared as two conflicting types. + +### Why is this bad +A variable with two conflicting declarations likely indicates a mistake. +Moreover, it could lead to incorrect or ill-defined type inference for +other code that relies on these variables. + +### Links +* [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) +
+ +## `conflicting-metaclass` + +**Default level**: error + +
+detects conflicting metaclasses + +TODO #14889 + +### Links +* [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) +
+ +## `cyclic-class-definition` + +**Default level**: error + +
+detects cyclic class definitions + +### What it does +Checks for class definitions with a cyclic inheritance chain. + +### Why is it bad? +TODO #14889 + +### Links +* [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) +
+ +## `division-by-zero` + +**Default level**: error + +
+detects division by zero + +### What it does +It detects division by zero. + +### Why is this bad? +Dividing by zero raises a `ZeroDivisionError` at runtime. + +### Examples +```python +5 / 0 +``` + +### Links +* [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) +
+ +## `duplicate-base` + +**Default level**: error + +
+detects class definitions with duplicate bases + +### What it does +Checks for class definitions with duplicate bases. + +### Why is this bad? +Class definitions with duplicate bases raise a `TypeError` at runtime. + +### Links +* [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) +
+ +## `escape-character-in-forward-annotation` + +**Default level**: error + +
+detects forward type annotations with escape characters + +TODO #14889 + +### Links +* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20escape-character-in-forward-annotation) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fstring_annotation.rs#L120) +
+ +## `fstring-type-annotation` + +**Default level**: error + +
+detects F-strings in type annotation positions + +### What it does +Checks for f-strings in type annotation positions. + +### Why is this bad? +Static analysis tools like ty can't analyse type annotations that use f-string notation. + +### Examples +```python +def test(): -> f"int": + ... +``` + +Use instead: +```python +def test(): -> "int": + ... +``` + +### Links +* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20fstring-type-annotation) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fstring_annotation.rs#L11) +
+ +## `implicit-concatenated-string-type-annotation` + +**Default level**: error + +
+detects implicit concatenated strings in type annotations + +### What it does +Checks for implicit concatenated strings in type annotation positions. + +### Why is this bad? +Static analysis tools like ty can't analyse type annotations that use implicit concatenated strings. + +### Examples +```python +def test(): -> "Literal[" "5" "]": + ... +``` + +Use instead: +```python +def test(): -> "Literal[5]": + ... +``` + +### Links +* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20implicit-concatenated-string-type-annotation) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fstring_annotation.rs#L86) +
+ +## `incompatible-slots` + +**Default level**: error + +
+detects class definitions whose MRO has conflicting __slots__ + +### What it does +Checks for classes whose bases define incompatible `__slots__`. + +### Why is this bad? +Inheriting from bases with incompatible `__slots__`s +will lead to a `TypeError` at runtime. + +Classes with no or empty `__slots__` are always compatible: + +```python +class A: ... +class B: + __slots__ = () +class C: + __slots__ = ("a", "b") + +## fine +class D(A, B, C): ... +``` + +Multiple inheritance from more than one different class +defining non-empty `__slots__` is not allowed: + +```python +class A: + __slots__ = ("a", "b") + +class B: + __slots__ = ("a", "b") # Even if the values are the same + +## TypeError: multiple bases have instance lay-out conflict +class C(A, B): ... +``` + +### Known problems +Dynamic (not tuple or string literal) `__slots__` are not checked. +Additionally, classes inheriting from built-in classes with implicit layouts +like `str` or `int` are also not checked. + +```pycon +>>> hasattr(int, "__slots__") +False +>>> hasattr(str, "__slots__") +False +>>> class A(int, str): ... +Traceback (most recent call last): + File "", line 1, in + class A(int, str): ... +TypeError: multiple bases have instance lay-out conflict +``` + +### Links +* [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) +
+ +## `inconsistent-mro` + +**Default level**: error + +
+detects class definitions with an inconsistent MRO + +### What it does +Checks for classes with an inconsistent method resolution order (MRO). + +### Why is this bad? +Classes with an inconsistent MRO will raise a `TypeError` at runtime. + +### Links +* [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) +
+ +## `index-out-of-bounds` + +**Default level**: error + +
+detects index out of bounds errors + +### What it does +Checks for attempts to use an out of bounds index to get an item from +a container. + +### Why is this bad? +Using an out of bounds index will raise an `IndexError` at runtime. + +### Links +* [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) +
+ +## `invalid-argument-type` + +**Default level**: error + +
+detects call arguments whose type is not assignable to the corresponding typed parameter + +### What it does +Detects call arguments whose type is not assignable to the corresponding typed parameter. + +### Why is this bad? +Passing an argument of a type the function (or callable object) does not accept violates +the expectations of the function author and may cause unexpected runtime errors within the +body of the function. + +### Examples +```python +def func(x: int): ... +func("foo") # error: [invalid-argument-type] +``` + +### Links +* [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) +
+ +## `invalid-assignment` + +**Default level**: error + +
+detects invalid assignments + +TODO #14889 + +### Links +* [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) +
+ +## `invalid-attribute-access` + +**Default level**: error + +
+Invalid attribute access + +### What it does +Makes sure that instance attribute accesses are valid. + +### Examples +```python +class C: + var: ClassVar[int] = 1 + +C.var = 3 # okay +C().var = 3 # error: Cannot assign to class variable +``` + +### Links +* [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) +
+ +## `invalid-base` + +**Default level**: error + +
+detects class definitions with an invalid base + +TODO #14889 + +### Links +* [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) +
+ +## `invalid-context-manager` + +**Default level**: error + +
+detects expressions used in with statements that don't implement the context manager protocol + +TODO #14889 + +### Links +* [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) +
+ +## `invalid-declaration` + +**Default level**: error + +
+detects invalid declarations + +TODO #14889 + +### Links +* [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) +
+ +## `invalid-exception-caught` + +**Default level**: error + +
+detects exception handlers that catch classes that do not inherit from BaseException + +### What it does +Checks for exception handlers that catch non-exception classes. + +### Why is this bad? +Catching classes that do not inherit from `BaseException` will raise a TypeError at runtime. + +### Example +```python +try: + 1 / 0 +except 1: + ... +``` + +Use instead: +```python +try: + 1 / 0 +except ZeroDivisionError: + ... +``` + +### References +- [Python documentation: except clause](https://docs.python.org/3/reference/compound_stmts.html#except-clause) +- [Python documentation: Built-in Exceptions](https://docs.python.org/3/library/exceptions.html#built-in-exceptions) + +### Ruff rule + This rule corresponds to Ruff's [`except-with-non-exception-classes` (`B030`)](https://docs.astral.sh/ruff/rules/except-with-non-exception-classes) + +### Links +* [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) +
+ +## `invalid-generic-class` + +**Default level**: error + +
+detects invalid generic classes + +### What it does +Checks for the creation of invalid generic classes + +### Why is this bad? +There are several requirements that you must follow when defining a generic class. + +### Examples +```python +from typing import Generic, TypeVar + +T = TypeVar("T") # okay + +## error: class uses both PEP-695 syntax and legacy syntax +class C[U](Generic[T]): ... +``` + +### References +- [Typing spec: Generics](https://typing.python.org/en/latest/spec/generics.html#introduction) + +### Links +* [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) +
+ +## `invalid-legacy-type-variable` + +**Default level**: error + +
+detects invalid legacy type variables + +### What it does +Checks for the creation of invalid legacy `TypeVar`s + +### Why is this bad? +There are several requirements that you must follow when creating a legacy `TypeVar`. + +### Examples +```python +from typing import TypeVar + +T = TypeVar("T") # okay +Q = TypeVar("S") # error: TypeVar name must match the variable it's assigned to +T = TypeVar("T") # error: TypeVars should not be redefined + +## error: TypeVar must be immediately assigned to a variable +def f(t: TypeVar("U")): ... +``` + +### References +- [Typing spec: Generics](https://typing.python.org/en/latest/spec/generics.html#introduction) + +### Links +* [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) +
+ +## `invalid-metaclass` + +**Default level**: error + +
+detects invalid metaclass= arguments + +### What it does +Checks for arguments to `metaclass=` that are invalid. + +### Why is this bad? +Python allows arbitrary expressions to be used as the argument to `metaclass=`. +These expressions, however, need to be callable and accept the same arguments +as `type.__new__`. + +### Example + +```python +def f(): ... + +## TypeError: f() takes 0 positional arguments but 3 were given +class B(metaclass=f): ... +``` + +### References +- [Python documentation: Metaclasses](https://docs.python.org/3/reference/datamodel.html#metaclasses) + +### Links +* [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) +
+ +## `invalid-overload` + +**Default level**: error + +
+detects invalid @overload usages + +### What it does +Checks for various invalid `@overload` usages. + +### Why is this bad? +The `@overload` decorator is used to define functions and methods that accepts different +combinations of arguments and return different types based on the arguments passed. This is +mainly beneficial for type checkers. But, if the `@overload` usage is invalid, the type +checker may not be able to provide correct type information. + +### Example + +Defining only one overload: + +```py +from typing import overload + +@overload +def foo(x: int) -> int: ... +def foo(x: int | None) -> int | None: + return x +``` + +Or, not providing an implementation for the overloaded definition: + +```py +from typing import overload + +@overload +def foo() -> None: ... +@overload +def foo(x: int) -> int: ... +``` + +### References +- [Python documentation: `@overload`](https://docs.python.org/3/library/typing.html#typing.overload) + +### Links +* [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) +
+ +## `invalid-parameter-default` + +**Default level**: error + +
+detects default values that can't be assigned to the parameter's annotated type + +### What it does +Checks for default values that can't be assigned to the parameter's annotated type. + +### Why is this bad? +TODO #14889 + +### Links +* [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) +
+ +## `invalid-protocol` + +**Default level**: error + +
+detects invalid protocol class definitions + +### What it does +Checks for invalidly defined protocol classes. + +### Why is this bad? +An invalidly defined protocol class may lead to the type checker inferring +unexpected things. It may also lead to `TypeError`s at runtime. + +### Examples +A `Protocol` class cannot inherit from a non-`Protocol` class; +this raises a `TypeError` at runtime: + +```pycon +>>> from typing import Protocol +>>> class Foo(int, Protocol): ... +... +Traceback (most recent call last): + File "", line 1, in + class Foo(int, Protocol): ... +TypeError: Protocols can only inherit from other protocols, got +``` + +### Links +* [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) +
+ +## `invalid-raise` + +**Default level**: error + +
+detects raise statements that raise invalid exceptions or use invalid causes + +Checks for `raise` statements that raise non-exceptions or use invalid +causes for their raised exceptions. + +### Why is this bad? +Only subclasses or instances of `BaseException` can be raised. +For an exception's cause, the same rules apply, except that `None` is also +permitted. Violating these rules results in a `TypeError` at runtime. + +### Examples +```python +def f(): + try: + something() + except NameError: + raise "oops!" from f + +def g(): + raise NotImplemented from 42 +``` + +Use instead: +```python +def f(): + try: + something() + except NameError as e: + raise RuntimeError("oops!") from e + +def g(): + raise NotImplementedError from None +``` + +### References +- [Python documentation: The `raise` statement](https://docs.python.org/3/reference/simple_stmts.html#raise) +- [Python documentation: Built-in Exceptions](https://docs.python.org/3/library/exceptions.html#built-in-exceptions) + +### Links +* [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) +
+ +## `invalid-return-type` + +**Default level**: error + +
+detects returned values that can't be assigned to the function's annotated return type + +### What it does +Detects returned values that can't be assigned to the function's annotated return type. + +### Why is this bad? +Returning an object of a type incompatible with the annotated return type may cause confusion to the user calling the function. + +### Examples +```python +def func() -> int: + return "a" # error: [invalid-return-type] +``` + +### Links +* [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) +
+ +## `invalid-super-argument` + +**Default level**: error + +
+detects invalid arguments for super() + +### What it does +Detects `super()` calls where: +- the first argument is not a valid class literal, or +- the second argument is not an instance or subclass of the first argument. + +### Why is this bad? +`super(type, obj)` expects: +- the first argument to be a class, +- and the second argument to satisfy one of the following: + - `isinstance(obj, type)` is `True` + - `issubclass(obj, type)` is `True` + +Violating this relationship will raise a `TypeError` at runtime. + +### Examples +```python +class A: + ... +class B(A): + ... + +super(A, B()) # it's okay! `A` satisfies `isinstance(B(), A)` + +super(A(), B()) # error: `A()` is not a class + +super(B, A()) # error: `A()` does not satisfy `isinstance(A(), B)` +super(B, A) # error: `A` does not satisfy `issubclass(A, B)` +``` + +### References +- [Python documentation: super()](https://docs.python.org/3/library/functions.html#super) + +### Links +* [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) +
+ +## `invalid-syntax-in-forward-annotation` + +**Default level**: error + +
+detects invalid syntax in forward annotations + +TODO #14889 + +### Links +* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-syntax-in-forward-annotation) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fstring_annotation.rs#L111) +
+ +## `invalid-type-checking-constant` + +**Default level**: error + +
+detects invalid TYPE_CHECKING constant assignments + +### What it does +Checks for a value other than `False` assigned to the `TYPE_CHECKING` variable, or an +annotation not assignable from `bool`. + +### Why is this bad? +The name `TYPE_CHECKING` is reserved for a flag that can be used to provide conditional +code seen only by the type checker, and not at runtime. Normally this flag is imported from +`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 +be `True`. If annotated, it must be annotated as a type that can accept `bool` values. + +### Links +* [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) +
+ +## `invalid-type-form` + +**Default level**: error + +
+detects invalid type forms + +### What it does +Checks for invalid type expressions. + +### Why is this bad? +TODO #14889 + +### Links +* [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) +
+ +## `invalid-type-variable-constraints` + +**Default level**: error + +
+detects invalid type variable constraints + +TODO #14889 + +### Links +* [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) +
+ +## `missing-argument` + +**Default level**: error + +
+detects missing required arguments in a call + +### What it does +Checks for missing required arguments in a call. + +### Why is this bad? +Failing to provide a required argument will raise a `TypeError` at runtime. + +### Examples +```python +def func(x: int): ... +func() # TypeError: func() missing 1 required positional argument: 'x' +``` + +### Links +* [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) +
+ +## `no-matching-overload` + +**Default level**: error + +
+detects calls that do not match any overload + +### What it does +Checks for calls to an overloaded function that do not match any of the overloads. + +### Why is this bad? +Failing to provide the correct arguments to one of the overloads will raise a `TypeError` +at runtime. + +### Examples +```python +@overload +def func(x: int): ... +@overload +def func(x: bool): ... +func("string") # error: [no-matching-overload] +``` + +### Links +* [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) +
+ +## `non-subscriptable` + +**Default level**: error + +
+detects subscripting objects that do not support subscripting + +### What it does +Checks for subscripting objects that do not support subscripting. + +### Why is this bad? +Subscripting an object that does not support it will raise a `TypeError` at runtime. + +### Examples +```python +4[1] # TypeError: 'int' object is not subscriptable +``` + +### Links +* [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) +
+ +## `not-iterable` + +**Default level**: error + +
+detects iteration over an object that is not iterable + +### What it does +Checks for objects that are not iterable but are used in a context that requires them to be. + +### Why is this bad? +Iterating over an object that is not iterable will raise a `TypeError` at runtime. + +### Examples + +```python +for i in 34: # TypeError: 'int' object is not iterable + pass +``` + +### Links +* [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) +
+ +## `parameter-already-assigned` + +**Default level**: error + +
+detects multiple arguments for the same parameter + +### What it does +Checks for calls which provide more than one argument for a single parameter. + +### Why is this bad? +Providing multiple values for a single parameter will raise a `TypeError` at runtime. + +### Examples + +```python +def f(x: int) -> int: ... + +f(1, x=2) # Error raised here +``` + +### Links +* [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) +
+ +## `raw-string-type-annotation` + +**Default level**: error + +
+detects raw strings in type annotation positions + +### What it does +Checks for raw-strings in type annotation positions. + +### Why is this bad? +Static analysis tools like ty can't analyse type annotations that use raw-string notation. + +### Examples +```python +def test(): -> r"int": + ... +``` + +Use instead: +```python +def test(): -> "int": + ... +``` + +### Links +* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20raw-string-type-annotation) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fstring_annotation.rs#L61) +
+ +## `static-assert-error` + +**Default level**: error + +
+Failed static assertion + +### What it does +Makes sure that the argument of `static_assert` is statically known to be true. + +### Examples +```python +from ty_extensions import static_assert + +static_assert(1 + 1 == 3) # error: evaluates to `False` + +static_assert(int(2.0 * 3.0) == 6) # error: does not have a statically known truthiness +``` + +### Links +* [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) +
+ +## `subclass-of-final-class` + +**Default level**: error + +
+detects subclasses of final classes + +### What it does +Checks for classes that subclass final classes. + +### Why is this bad? +Decorating a class with `@final` declares to the type checker that it should not be subclassed. + +### Example + +```python +from typing import final + +@final +class A: ... +class B(A): ... # Error raised here +``` + +### Links +* [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) +
+ +## `too-many-positional-arguments` + +**Default level**: error + +
+detects calls passing too many positional arguments + +### What it does +Checks for calls that pass more positional arguments than the callable can accept. + +### Why is this bad? +Passing too many positional arguments will raise `TypeError` at runtime. + +### Example + +```python +def f(): ... + +f("foo") # Error raised here +``` + +### Links +* [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) +
+ +## `type-assertion-failure` + +**Default level**: error + +
+detects failed type assertions + +### What it does +Checks for `assert_type()` and `assert_never()` calls where the actual type +is not the same as the asserted type. + +### Why is this bad? +`assert_type()` allows confirming the inferred type of a certain value. + +### Example + +```python +def _(x: int): + assert_type(x, int) # fine + assert_type(x, str) # error: Actual type does not match asserted type +``` + +### Links +* [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) +
+ +## `unavailable-implicit-super-arguments` + +**Default level**: error + +
+detects invalid super() calls where implicit arguments are unavailable. + +### What it does +Detects invalid `super()` calls where implicit arguments like the enclosing class or first method argument are unavailable. + +### Why is this bad? +When `super()` is used without arguments, Python tries to find two things: +the nearest enclosing class and the first argument of the immediately enclosing function (typically self or cls). +If either of these is missing, the call will fail at runtime with a `RuntimeError`. + +### Examples +```python +super() # error: no enclosing class or function found + +def func(): + super() # error: no enclosing class or first argument exists + +class A: + f = super() # error: no enclosing function to provide the first argument + + def method(self): + def nested(): + super() # error: first argument does not exist in this nested function + + lambda: super() # error: first argument does not exist in this lambda + + (super() for _ in range(10)) # error: argument is not available in generator expression + + super() # okay! both enclosing class and first argument are available +``` + +### References +- [Python documentation: super()](https://docs.python.org/3/library/functions.html#super) + +### Links +* [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) +
+ +## `unknown-argument` + +**Default level**: error + +
+detects unknown keyword arguments in calls + +### What it does +Checks for keyword arguments in calls that don't match any parameter of the callable. + +### Why is this bad? +Providing an unknown keyword argument will raise `TypeError` at runtime. + +### Example + +```python +def f(x: int) -> int: ... + +f(x=1, y=2) # Error raised here +``` + +### Links +* [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) +
+ +## `unresolved-attribute` + +**Default level**: error + +
+detects references to unresolved attributes + +### What it does +Checks for unresolved attributes. + +### 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. + +### Links +* [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) +
+ +## `unresolved-import` + +**Default level**: error + +
+detects unresolved imports + +### What it does +Checks for import statements for which the module cannot be resolved. + +### Why is this bad? +Importing a module that cannot be resolved will raise an `ImportError` +at runtime. + +### Links +* [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) +
+ +## `unsupported-bool-conversion` + +**Default level**: error + +
+detects boolean conversion where the object incorrectly implements __bool__ + +### What it does +Checks for bool conversions where the object doesn't correctly implement `__bool__`. + +### Why is this bad? +If an exception is raised when you attempt to evaluate the truthiness of an object, +using the object in a boolean context will fail at runtime. + +### Examples + +```python +class NotBoolable: + __bool__ = None + +b1 = NotBoolable() +b2 = NotBoolable() + +if b1: # exception raised here + pass + +b1 and b2 # exception raised here +not b1 # exception raised here +b1 < b2 < b1 # exception raised here +``` + +### Links +* [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) +
+ +## `unsupported-operator` + +**Default level**: error + +
+detects binary, unary, or comparison expressions where the operands don't support the operator + +### What it does +Checks for binary expressions, comparisons, and unary expressions where +the operands don't support the operator. + +### Why is this bad? +Attempting to use an unsupported operator will raise a `TypeError` at +runtime. + +### Links +* [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) +
+ +## `zero-stepsize-in-slice` + +**Default level**: error + +
+detects a slice step size of zero + +### What it does +Checks for step size 0 in slices. + +### Why is this bad? +A slice with a step size of zero will raise a `ValueError` at runtime. + +### Examples +```python +l = list(range(10)) +l[1:10:0] # ValueError: slice step cannot be zero +``` + +### Links +* [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) +
+ +## `call-possibly-unbound-method` + +**Default level**: warn + +
+detects calls to possibly unbound methods + +### What it does +Checks for calls to possibly unbound methods. + +### Why is this bad? +Calling an unbound method will raise an `AttributeError` at runtime. + +### Links +* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20call-possibly-unbound-method) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L102) +
+ +## `invalid-ignore-comment` + +**Default level**: warn + +
+detects ignore comments that use invalid syntax + +### What it does +Checks for `type: ignore` and `ty: ignore` comments that are syntactically incorrect. + +### Why is this bad? +A syntactically incorrect ignore comment is probably a mistake and is useless. + +### Examples +```py +a = 20 / 0 # type: ignoree +``` + +Use instead: + +```py +a = 20 / 0 # type: ignore +``` + +### Links +* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-ignore-comment) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Fsuppression.rs#L65) +
+ +## `possibly-unbound-attribute` + +**Default level**: warn + +
+detects references to possibly unbound attributes + +### What it does +Checks for possibly unbound attributes. + +### Why is this bad? +Attempting to access an unbound attribute will raise an `AttributeError` at runtime. + +### Links +* [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) +
+ +## `possibly-unbound-import` + +**Default level**: warn + +
+detects possibly unbound imports + +### What it does +Checks for imports of symbols that may be unbound. + +### Why is this bad? +Importing an unbound module or name will raise a `ModuleNotFoundError` +or `ImportError` at runtime. + +### Links +* [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) +
+ +## `possibly-unresolved-reference` + +**Default level**: warn + +
+detects references to possibly undefined names + +### What it does +Checks for references to names that are possibly not defined. + +### Why is this bad? +Using an undefined variable will raise a `NameError` at runtime. + +### Example + +```python +for i in range(0): + x = i + +print(x) # NameError: name 'x' is not defined +``` + +### Links +* [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) +
+ +## `redundant-cast` + +**Default level**: warn + +
+detects redundant cast calls + +### What it does +Detects redundant `cast` calls where the value already has the target type. + +### Why is this bad? +These casts have no effect and can be removed. + +### Example +```python +def f() -> int: + return 10 + +cast(int, f()) # Redundant +``` + +### Links +* [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) +
+ +## `undefined-reveal` + +**Default level**: warn + +
+detects usages of reveal_type without importing it + +### What it does +Checks for calls to `reveal_type` without importing it. + +### Why is this bad? +Using `reveal_type` without importing it will raise a `NameError` at runtime. + +### Examples +TODO #14889 + +### Links +* [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) +
+ +## `unknown-rule` + +**Default level**: warn + +
+detects ty: ignore comments that reference unknown rules + +### What it does +Checks for `ty: ignore[code]` where `code` isn't a known lint rule. + +### Why is this bad? +A `ty: ignore[code]` directive with a `code` that doesn't match +any known rule will not suppress any type errors, and is probably a mistake. + +### Examples +```py +a = 20 / 0 # ty: ignore[division-by-zer] +``` + +Use instead: + +```py +a = 20 / 0 # ty: ignore[division-by-zero] +``` + +### Links +* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unknown-rule) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Fsuppression.rs#L40) +
+ +## `unresolved-reference` + +**Default level**: warn + +
+detects references to names that are not defined + +### What it does +Checks for references to names that are not defined. + +### Why is this bad? +Using an undefined variable will raise a `NameError` at runtime. + +### Example + +```python +print(x) # NameError: name 'x' is not defined +``` + +### Links +* [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) +
+ +## `unused-ignore-comment` + +**Default level**: warn + +
+detects unused type: ignore comments + +### What it does +Checks for `type: ignore` or `ty: ignore` directives that are no longer applicable. + +### Why is this bad? +A `type: ignore` directive that no longer matches any diagnostic violations is likely +included by mistake, and should be removed to avoid confusion. + +### Examples +```py +a = 20 / 2 # ty: ignore[division-by-zero] +``` + +Use instead: + +```py +a = 20 / 2 +``` + +### Links +* [Related issues](https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unused-ignore-comment) +* [View source](https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Fsuppression.rs#L15) +
+ diff --git a/crates/ty_python_semantic/src/types/diagnostic.rs b/crates/ty_python_semantic/src/types/diagnostic.rs index 25dd0c69ba..17a1cadd51 100644 --- a/crates/ty_python_semantic/src/types/diagnostic.rs +++ b/crates/ty_python_semantic/src/types/diagnostic.rs @@ -646,7 +646,7 @@ declare_lint! { /// 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. 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"), default_level: Level::Error, } diff --git a/ty.schema.json b/ty.schema.json index a070b862cc..8750c208ed 100644 --- a/ty.schema.json +++ b/ty.schema.json @@ -551,7 +551,7 @@ ] }, "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.", "default": "error", "oneOf": [