diff --git a/crates/ruff/src/rules/pyflakes/rules/assert_tuple.rs b/crates/ruff/src/rules/pyflakes/rules/assert_tuple.rs index 456c18b45f..9f76c7970d 100644 --- a/crates/ruff/src/rules/pyflakes/rules/assert_tuple.rs +++ b/crates/ruff/src/rules/pyflakes/rules/assert_tuple.rs @@ -5,6 +5,27 @@ use ruff_macros::{derive_message_formats, violation}; use crate::checkers::ast::Checker; +/// ## What it does +/// Checks for `assert` statements that use non-empty tuples as test +/// conditions. +/// +/// ## Why is this bad? +/// Non-empty tuples are always `True`, so an `assert` statement with a +/// non-empty tuple as its test condition will always pass. This is likely a +/// mistake. +/// +/// ## Example +/// ```python +/// assert (some_condition,) +/// ``` +/// +/// Use instead: +/// ```python +/// assert some_condition +/// ``` +/// +/// ## References +/// - [Python documentation](https://docs.python.org/3/reference/simple_stmts.html#the-assert-statement) #[violation] pub struct AssertTuple; diff --git a/crates/ruff/src/rules/pyflakes/rules/if_tuple.rs b/crates/ruff/src/rules/pyflakes/rules/if_tuple.rs index 3fcdcf9d21..01f9e9a784 100644 --- a/crates/ruff/src/rules/pyflakes/rules/if_tuple.rs +++ b/crates/ruff/src/rules/pyflakes/rules/if_tuple.rs @@ -5,6 +5,27 @@ use ruff_macros::{derive_message_formats, violation}; use crate::checkers::ast::Checker; +/// ## What it does +/// Checks for `if statements that use non-empty tuples as test conditions. +/// +/// ## Why is this bad? +/// Non-empty tuples are always `True`, so an `if` statement with a non-empty +/// tuple as its test condition will always pass. This is likely a mistake. +/// +/// ## Example +/// ```python +/// if (False,): +/// print("This will always run") +/// ``` +/// +/// Use instead: +/// ```python +/// if False: +/// print("This will never run") +/// ``` +/// +/// ## References +/// - [Python documentation](https://docs.python.org/3/reference/compound_stmts.html#the-if-statement) #[violation] pub struct IfTuple; diff --git a/crates/ruff/src/rules/pyflakes/rules/invalid_literal_comparisons.rs b/crates/ruff/src/rules/pyflakes/rules/invalid_literal_comparisons.rs index 59d4e790be..80cdb42882 100644 --- a/crates/ruff/src/rules/pyflakes/rules/invalid_literal_comparisons.rs +++ b/crates/ruff/src/rules/pyflakes/rules/invalid_literal_comparisons.rs @@ -27,6 +27,41 @@ impl From<&Cmpop> for IsCmpop { } } +/// ## What it does +/// Checks for `is` and `is not` comparisons against constant literals, like +/// integers and strings. +/// +/// ## Why is this bad? +/// The `is` and `is not` comparators operate on identity, in that they check +/// whether two objects are the same object. If the objects are not the same +/// object, the comparison will always be `False`. Using `is` and `is not` with +/// constant literals often works "by accident", but are not guaranteed to produce +/// the expected result. +/// +/// As of Python 3.8, using `is` and `is not` with constant literals will produce +/// a `SyntaxWarning`. +/// +/// Instead, use `==` and `!=` to compare constant literals, which will compare +/// the values of the objects instead of their identities. +/// +/// ## Example +/// ```python +/// x = 200 +/// if x is 200: +/// print("It's 200!") +/// ``` +/// +/// Use instead: +/// ```python +/// x = 200 +/// if x == 200: +/// print("It's 200!") +/// ``` +/// +/// ## References +/// - [Python documentation](https://docs.python.org/3/reference/expressions.html#is-not) +/// - [Python documentation](https://docs.python.org/3/reference/expressions.html#value-comparisons) +/// - [_Why does Python log a SyntaxWarning for ‘is’ with literals?_ by Adam Johnson](https://adamj.eu/tech/2020/01/21/why-does-python-3-8-syntaxwarning-for-is-literal/) #[violation] pub struct IsLiteral { cmpop: IsCmpop, diff --git a/crates/ruff/src/rules/pyflakes/rules/invalid_print_syntax.rs b/crates/ruff/src/rules/pyflakes/rules/invalid_print_syntax.rs index 96c9996971..651b03d737 100644 --- a/crates/ruff/src/rules/pyflakes/rules/invalid_print_syntax.rs +++ b/crates/ruff/src/rules/pyflakes/rules/invalid_print_syntax.rs @@ -5,6 +5,46 @@ use ruff_macros::{derive_message_formats, violation}; use crate::checkers::ast::Checker; +/// ## What it does +/// Checks for `print` statements that use the `>>` syntax. +/// +/// ## Why is this bad? +/// In Python 2, the `print` statement can be used with the `>>` syntax to +/// print to a file-like object. This `print >> sys.stderr` syntax is +/// deprecated in Python 3. +/// +/// Instead, use the `file` keyword argument to the `print` function, the +/// `sys.stderr.write` function, or the `logging` module. +/// +/// ## Example +/// ```python +/// from __future__ import print_function +/// import sys +/// +/// print >> sys.stderr, "Hello, world!" +/// ``` +/// +/// Use instead: +/// ```python +/// print("Hello, world!", file=sys.stderr) +/// ``` +/// +/// Or: +/// ```python +/// import sys +/// +/// sys.stderr.write("Hello, world!\n") +/// ``` +/// +/// Or: +/// ```python +/// import logging +/// +/// logging.error("Hello, world!") +/// ``` +/// +/// ## References +/// - [Python documentation](https://docs.python.org/3/library/functions.html#print) #[violation] pub struct InvalidPrintSyntax; diff --git a/crates/ruff/src/rules/pyflakes/rules/repeated_keys.rs b/crates/ruff/src/rules/pyflakes/rules/repeated_keys.rs index b36393ae45..44f2c70a5d 100644 --- a/crates/ruff/src/rules/pyflakes/rules/repeated_keys.rs +++ b/crates/ruff/src/rules/pyflakes/rules/repeated_keys.rs @@ -10,6 +10,36 @@ use ruff_python_ast::comparable::{ComparableConstant, ComparableExpr}; use crate::checkers::ast::Checker; use crate::registry::{AsRule, Rule}; +/// ## What it does +/// Checks for dictionary literals that associate multiple values with the +/// same key. +/// +/// ## Why is this bad? +/// Dictionary keys should be unique. If a key is associated with multiple values, +/// the earlier values will be overwritten. Including multiple values for the +/// same key in a dictionary literal is likely a mistake. +/// +/// ## Example +/// ```python +/// foo = { +/// "bar": 1, +/// "baz": 2, +/// "baz": 3, +/// } +/// foo["baz"] # 3 +/// ``` +/// +/// Use instead: +/// ```python +/// foo = { +/// "bar": 1, +/// "baz": 2, +/// } +/// foo["baz"] # 2 +/// ``` +/// +/// ## References +/// - [Python documentation](https://docs.python.org/3/tutorial/datastructures.html#dictionaries) #[violation] pub struct MultiValueRepeatedKeyLiteral { name: String, @@ -37,6 +67,36 @@ impl Violation for MultiValueRepeatedKeyLiteral { } } } + +/// ## What it does +/// Checks for dictionary keys that are repeated with different values. +/// +/// ## Why is this bad? +/// Dictionary keys should be unique. If a key is repeated with a different +/// value, the first values will be overwritten and the key will correspond to +/// the last value. This is likely a mistake. +/// +/// ## Example +/// ```python +/// foo = { +/// bar: 1, +/// baz: 2, +/// baz: 3, +/// } +/// foo[baz] # 3 +/// ``` +/// +/// Use instead: +/// ```python +/// foo = { +/// bar: 1, +/// baz: 2, +/// } +/// foo[baz] # 2 +/// ``` +/// +/// ## References +/// - [Python documentation](https://docs.python.org/3/tutorial/datastructures.html#dictionaries) #[violation] pub struct MultiValueRepeatedKeyVariable { name: String, diff --git a/crates/ruff/src/rules/pyflakes/rules/starred_expressions.rs b/crates/ruff/src/rules/pyflakes/rules/starred_expressions.rs index 8a3fef38dd..d4b3a875fa 100644 --- a/crates/ruff/src/rules/pyflakes/rules/starred_expressions.rs +++ b/crates/ruff/src/rules/pyflakes/rules/starred_expressions.rs @@ -4,6 +4,15 @@ use rustpython_parser::ast::Expr; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; +/// ## What it does +/// Checks for the use of too many expressions in starred assignment statements. +/// +/// ## Why is this bad? +/// In assignment statements, starred expressions can be used to unpack iterables. +/// +/// In Python 3, no more than 1 << 8 assignments are allowed before a starred +/// expression, and no more than 1 << 24 expressions are allowed after a starred +/// expression. #[violation] pub struct ExpressionsInStarAssignment; @@ -14,6 +23,22 @@ impl Violation for ExpressionsInStarAssignment { } } +/// ## What it does +/// Checks for the use of multiple starred expressions in assignment statements. +/// +/// ## Why is this bad? +/// In assignment statements, starred expressions can be used to unpack iterables. +/// Including more than one starred expression on the left-hand-side of an +/// assignment will cause a `SyntaxError`, as it is unclear which expression +/// should receive the remaining values. +/// +/// ## Example +/// ```python +/// *foo, *bar, baz = (1, 2, 3) +/// ``` +/// +/// ## References +/// - [PEP 3132](https://peps.python.org/pep-3132/) #[violation] pub struct MultipleStarredExpressions;