Complete pyupgrade documentation (#5096)

## Summary

Completes the documentation for the `pyupgrade` rules.

Related to #2646.

## Test Plan

`python scripts/check_docs_formatted.py`
This commit is contained in:
Tom Kuson 2023-06-15 00:43:12 +01:00 committed by GitHub
parent 71b3130ff1
commit ccbc863960
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
40 changed files with 896 additions and 46 deletions

View file

@ -13,6 +13,36 @@ use ruff_python_stdlib::identifiers::is_identifier;
use crate::checkers::ast::Checker;
use crate::registry::AsRule;
/// ## What it does
/// Checks for `NamedTuple` declarations that use functional syntax.
///
/// ## Why is this bad?
/// `NamedTuple` subclasses can be defined either through a functional syntax
/// (`Foo = NamedTuple(...)`) or a class syntax (`class Foo(NamedTuple): ...`).
///
/// The class syntax is more readable and generally preferred over the
/// functional syntax, which exists primarily for backwards compatibility
/// with `collections.namedtuple`.
///
/// ## Example
/// ```python
/// from typing import NamedTuple
///
/// Foo = NamedTuple("Foo", [("a", int), ("b", str)])
/// ```
///
/// Use instead:
/// ```python
/// from typing import NamedTuple
///
///
/// class Foo(NamedTuple):
/// a: int
/// b: str
/// ```
///
/// ## References
/// - [Python documentation: `typing.NamedTuple`](https://docs.python.org/3/library/typing.html#typing.NamedTuple)
#[violation]
pub struct ConvertNamedTupleFunctionalToClass {
name: String,

View file

@ -13,6 +13,35 @@ use ruff_python_stdlib::identifiers::is_identifier;
use crate::checkers::ast::Checker;
use crate::registry::AsRule;
/// ## What it does
/// Checks for `TypedDict` declarations that use functional syntax.
///
/// ## Why is this bad?
/// `TypedDict` subclasses can be defined either through a functional syntax
/// (`Foo = TypedDict(...)`) or a class syntax (`class Foo(TypedDict): ...`).
///
/// The class syntax is more readable and generally preferred over the
/// functional syntax.
///
/// ## Example
/// ```python
/// from typing import TypedDict
///
/// Foo = TypedDict("Foo", {"a": int, "b": str})
/// ```
///
/// Use instead:
/// ```python
/// from typing import TypedDict
///
///
/// class Foo(TypedDict):
/// a: int
/// b: str
/// ```
///
/// ## References
/// - [Python documentation: `typing.TypedDict`](https://docs.python.org/3/library/typing.html#typing.TypedDict)
#[violation]
pub struct ConvertTypedDictFunctionalToClass {
name: String,

View file

@ -7,6 +7,29 @@ use crate::checkers::ast::Checker;
use crate::importer::ImportRequest;
use crate::registry::AsRule;
/// ## What it does
/// Checks for uses of `datetime.timezone.utc`.
///
/// ## Why is this bad?
/// As of Python 3.11, `datetime.UTC` is an alias for `datetime.timezone.utc`.
/// The alias is more readable and generally preferred over the full path.
///
/// ## Example
/// ```python
/// import datetime
///
/// datetime.timezone.utc
/// ```
///
/// Use instead:
/// ```python
/// import datetime
///
/// datetime.UTC
/// ```
///
/// ## References
/// - [Python documentation: `datetime.UTC`](https://docs.python.org/3/library/datetime.html#datetime.UTC)
#[violation]
pub struct DatetimeTimezoneUTC;

View file

@ -6,6 +6,25 @@ use ruff_macros::{derive_message_formats, violation};
use crate::checkers::ast::Checker;
use crate::registry::AsRule;
/// ## What it does
/// Checks for uses of the `xml.etree.cElementTree` module.
///
/// ## Why is this bad?
/// In Python 3.3, `xml.etree.cElementTree` was deprecated in favor of
/// `xml.etree.ElementTree`.
///
/// ## Example
/// ```python
/// from xml.etree import cElementTree
/// ```
///
/// Use instead:
/// ```python
/// from xml.etree import ElementTree
/// ```
///
/// ## References
/// - [Python documentation: `xml.etree.ElementTree`](https://docs.python.org/3/library/xml.etree.elementtree.html)
#[violation]
pub struct DeprecatedCElementTree;

View file

@ -35,6 +35,23 @@ enum Deprecation {
WithoutRename(WithoutRename),
}
/// ## What it does
/// Checks for uses of deprecated imports based on the minimum supported
/// Python version.
///
/// ## Why is this bad?
/// Deprecated imports may be removed in future versions of Python, and
/// should be replaced with their new equivalents.
///
/// ## Example
/// ```python
/// from collections import Sequence
/// ```
///
/// Use instead:
/// ```python
/// from collections.abc import Sequence
/// ```
#[violation]
pub struct DeprecatedImport {
deprecation: Deprecation,

View file

@ -23,6 +23,28 @@ pub(crate) enum MockReference {
Attribute,
}
/// ## What it does
/// Checks for imports of the `mock` module that should be replaced with
/// `unittest.mock`.
///
/// ## Why is this bad?
/// Since Python 3.3, `mock` has been a part of the standard library as
/// `unittest.mock`. The `mock` package is deprecated; use `unittest.mock`
/// instead.
///
/// ## Example
/// ```python
/// import mock
/// ```
///
/// Use instead:
/// ```python
/// from unittest import mock
/// ```
///
/// ## References
/// - [Python documentation: `unittest.mock`](https://docs.python.org/3/library/unittest.mock.html)
/// - [PyPI: `mock`](https://pypi.org/project/mock/)
#[violation]
pub struct DeprecatedMockImport {
reference_type: MockReference,

View file

@ -8,6 +8,36 @@ use ruff_macros::{derive_message_formats, violation};
use crate::checkers::ast::Checker;
use crate::registry::AsRule;
/// ## What it does
/// Checks for uses of deprecated methods from the `unittest` module.
///
/// ## Why is this bad?
/// The `unittest` module has deprecated aliases for some of its methods.
/// The aliases may be removed in future versions of Python. Instead,
/// use their non-deprecated counterparts.
///
/// ## Example
/// ```python
/// from unittest import TestCase
///
///
/// class SomeTest(TestCase):
/// def test_something(self):
/// self.assertEquals(1, 1)
/// ```
///
/// Use instead:
/// ```python
/// from unittest import TestCase
///
///
/// class SomeTest(TestCase):
/// def test_something(self):
/// self.assertEqual(1, 1)
/// ```
///
/// ## References
/// - [Python documentation: Deprecated aliases](https://docs.python.org/3/library/unittest.html#deprecated-aliases)
#[violation]
pub struct DeprecatedUnittestAlias {
alias: String,

View file

@ -9,6 +9,22 @@ use ruff_python_ast::source_code::Locator;
use crate::registry::Rule;
use crate::settings::Settings;
/// ## What it does
/// Checks for extraneous parentheses.
///
/// ## Why is this bad?
/// Extraneous parentheses are redundant, and can be removed to improve
/// readability while retaining identical semantics.
///
/// ## Example
/// ```python
/// print(("Hello, world"))
/// ```
///
/// Use instead:
/// ```python
/// print("Hello, world")
/// ```
#[violation]
pub struct ExtraneousParentheses;

View file

@ -17,6 +17,25 @@ use crate::registry::AsRule;
use crate::rules::pyflakes::format::FormatSummary;
use crate::rules::pyupgrade::helpers::curly_escape;
/// ## What it does
/// Checks for `str#format` calls that can be replaced with f-strings.
///
/// ## Why is this bad?
/// f-strings are more readable and generally preferred over `str#format`
/// calls.
///
/// ## Example
/// ```python
/// "{}".format(foo)
/// ```
///
/// Use instead:
/// ```python
/// f"{foo}"
/// ```
///
/// ## References
/// - [Python documentation: f-strings](https://docs.python.org/3/reference/lexical_analysis.html#f-strings)
#[violation]
pub struct FString;

View file

@ -14,6 +14,30 @@ use crate::cst::matchers::{match_attribute, match_call_mut, match_expression};
use crate::registry::AsRule;
use crate::rules::pyflakes::format::FormatSummary;
/// ## What it does
/// Checks for unnecessary positional indices in format strings.
///
/// ## Why is this bad?
/// In Python 3.1 and later, format strings can use implicit positional
/// references. For example, `"{0}, {1}".format("Hello", "World")` can be
/// rewritten as `"{}, {}".format("Hello", "World")`.
///
/// If the positional indices appear exactly in-order, they can be omitted
/// in favor of automatic indices to improve readability.
///
/// ## Example
/// ```python
/// "{0}, {1}".format("Hello", "World") # "Hello, World"
/// ```
///
/// Use instead:
/// ```python
/// "{}, {}".format("Hello", "World") # "Hello, World"
/// ```
///
/// ## References
/// - [Python documentation: Format String Syntax](https://docs.python.org/3/library/string.html#format-string-syntax)
/// - [Python documentation: `str.format`](https://docs.python.org/3/library/stdtypes.html#str.format)
#[violation]
pub struct FormatLiterals;

View file

@ -8,6 +8,36 @@ use crate::checkers::ast::Checker;
use crate::importer::ImportRequest;
use crate::registry::AsRule;
/// ## What it does
/// Checks for uses of `functools.lru_cache` that set `maxsize=None`.
///
/// ## Why is this bad?
/// Since Python 3.9, `functools.cache` can be used as a drop-in replacement
/// for `functools.lru_cache(maxsize=None)`. When possible, prefer
/// `functools.cache` as it is more readable and idiomatic.
///
/// ## Example
/// ```python
/// import functools
///
///
/// @functools.lru_cache(maxsize=None)
/// def foo():
/// ...
/// ```
///
/// Use instead:
/// ```python
/// import functools
///
///
/// @functools.cache
/// def foo():
/// ...
/// ```
///
/// ## References
/// - [Python documentation: `@functools.cache`](https://docs.python.org/3/library/functools.html#functools.cache)
#[violation]
pub struct LRUCacheWithMaxsizeNone;

View file

@ -7,6 +7,36 @@ use ruff_macros::{derive_message_formats, violation};
use crate::checkers::ast::Checker;
use crate::registry::AsRule;
/// ## What it does
/// Checks for unnecessary parentheses on `functools.lru_cache` decorators.
///
/// ## Why is this bad?
/// Since Python 3.8, `functools.lru_cache` can be used as a decorator without
/// trailing parentheses, as long as no arguments are passed to it.
///
/// ## Example
/// ```python
/// import functools
///
///
/// @functools.lru_cache()
/// def foo():
/// ...
/// ```
///
/// Use instead:
/// ```python
/// import functools
///
///
/// @functools.lru_cache
/// def foo():
/// ...
/// ```
///
/// ## References
/// - [Python documentation: `@functools.lru_cache`](https://docs.python.org/3/library/functools.html#functools.lru_cache)
/// - [Let lru_cache be used as a decorator with no arguments](https://github.com/python/cpython/issues/80953)
#[violation]
pub struct LRUCacheWithoutParameters;

View file

@ -24,6 +24,26 @@ impl fmt::Display for LiteralType {
}
}
/// ## What it does
/// Checks for unnecessary calls to `str` and `bytes`.
///
/// ## Why is this bad?
/// The `str` and `bytes` constructors can be replaced with string and bytes
/// literals, which are more readable and idiomatic.
///
/// ## Example
/// ```python
/// str("foo")
/// ```
///
/// Use instead:
/// ```python
/// "foo"
/// ```
///
/// ## References
/// - [Python documentation: `str`](https://docs.python.org/3/library/stdtypes.html#str)
/// - [Python documentation: `bytes`](https://docs.python.org/3/library/stdtypes.html#bytes)
#[violation]
pub struct NativeLiterals {
literal_type: LiteralType,

View file

@ -6,6 +6,29 @@ use ruff_macros::{derive_message_formats, violation};
use crate::checkers::ast::Checker;
use crate::registry::AsRule;
/// ## What it does
/// Checks for uses of `io.open`.
///
/// ## Why is this bad?
/// In Python 3, `io.open` is an alias for `open`. Prefer using `open` directly,
/// as it is more idiomatic.
///
/// ## Example
/// ```python
/// import io
///
/// with io.open("file.txt") as f:
/// ...
/// ```
///
/// Use instead:
/// ```python
/// with open("file.txt") as f:
/// ...
/// ```
///
/// ## References
/// - [Python documentation: `io.open`](https://docs.python.org/3/library/io.html#io.open)
#[violation]
pub struct OpenAlias;
@ -33,7 +56,7 @@ pub(crate) fn open_alias(checker: &mut Checker, expr: &Expr, func: &Expr) {
{
let mut diagnostic = Diagnostic::new(OpenAlias, expr.range());
if checker.patch(diagnostic.kind.rule()) {
if checker.semantic().is_available("open") {
if checker.semantic().is_builtin("open") {
diagnostic.set_fix(Fix::suggested(Edit::range_replacement(
"open".to_string(),
func.range(),

View file

@ -9,6 +9,31 @@ use ruff_python_semantic::SemanticModel;
use crate::checkers::ast::Checker;
use crate::registry::AsRule;
/// ## What it does
/// Checks for uses of exceptions that alias `OSError`.
///
/// ## Why is this bad?
/// `OSError` is the builtin error type used for exceptions that relate to the
/// operating system.
///
/// In Python 3.3, a variety of other exceptions, like `WindowsError` were
/// aliased to `OSError`. These aliases remain in place for compatibility with
/// older versions of Python, but may be removed in future versions.
///
/// Prefer using `OSError` directly, as it is more idiomatic and future-proof.
///
/// ## Example
/// ```python
/// raise IOError
/// ```
///
/// Use instead:
/// ```python
/// raise OSError
/// ```
///
/// ## References
/// - [Python documentation: `OSError`](https://docs.python.org/3/library/exceptions.html#OSError)
#[violation]
pub struct OSErrorAlias {
pub name: Option<String>,

View file

@ -16,6 +16,34 @@ use crate::registry::AsRule;
use crate::rules::pyupgrade::fixes::adjust_indentation;
use crate::settings::types::PythonVersion;
/// ## What it does
/// Checks for conditional blocks gated on `sys.version_info` comparisons
/// that are outdated for the minimum supported Python version.
///
/// ## Why is this bad?
/// In Python, code can be conditionally executed based on the active
/// Python version by comparing against the `sys.version_info` tuple.
///
/// If a code block is only executed for Python versions older than the
/// minimum supported version, it should be removed.
///
/// ## Example
/// ```python
/// import sys
///
/// if sys.version_info < (3, 0):
/// print("py2")
/// else:
/// print("py3")
/// ```
///
/// Use instead:
/// ```python
/// print("py3")
/// ```
///
/// ## References
/// - [Python documentation: `sys.version_info`](https://docs.python.org/3/library/sys.html#sys.version_info)
#[violation]
pub struct OutdatedVersionBlock;

View file

@ -18,6 +18,28 @@ use crate::checkers::ast::Checker;
use crate::registry::AsRule;
use crate::rules::pyupgrade::helpers::curly_escape;
/// ## What it does
/// Checks for `printf`-style string formatting.
///
/// ## Why is this bad?
/// `printf`-style string formatting has a number of quirks, and leads to less
/// readable code than using `str.format` calls or f-strings. In general, prefer
/// the newer `str.format` and f-strings constructs over `printf`-style string
/// formatting.
///
/// ## Example
/// ```python
/// "%s, %s" % ("Hello", "World") # "Hello, World"
/// ```
///
/// Use instead:
/// ```python
/// "{}, {}".format("Hello", "World") # "Hello, World"
/// ```
///
/// ## References
/// - [Python documentation: `printf`-style String Formatting](https://docs.python.org/3/library/stdtypes.html#old-string-formatting)
/// - [Python documentation: `str.format`](https://docs.python.org/3/library/stdtypes.html#str.format)
#[violation]
pub struct PrintfStringFormatting;

View file

@ -6,6 +6,36 @@ use ruff_macros::{derive_message_formats, violation};
use crate::checkers::ast::Checker;
use crate::registry::Rule;
/// ## What it does
/// Checks for the presence of unnecessary quotes in type annotations.
///
/// ## Why is this bad?
/// In Python, type annotations can be quoted to avoid forward references.
/// However, if `from __future__ import annotations` is present, Python
/// will always evaluate type annotations in a deferred manner, making
/// the quotes unnecessary.
///
/// ## Example
/// ```python
/// from __future__ import annotations
///
///
/// def foo(bar: "Bar") -> "Bar":
/// ...
/// ```
///
/// Use instead:
/// ```python
/// from __future__ import annotations
///
///
/// def foo(bar: Bar) -> Bar:
/// ...
/// ```
///
/// ## References
/// - [PEP 563](https://peps.python.org/pep-0563/)
/// - [Python documentation: `__future__` - Future statement definitions](https://docs.python.org/3/library/__future__.html#module-__future__)
#[violation]
pub struct QuotedAnnotation;

View file

@ -13,6 +13,27 @@ use ruff_python_ast::source_code::Locator;
use crate::checkers::ast::Checker;
use crate::registry::Rule;
/// ## What it does
/// Checks for redundant `open` mode parameters.
///
/// ## Why is this bad?
/// Redundant `open` mode parameters are unnecessary and should be removed to
/// avoid confusion.
///
/// ## Example
/// ```python
/// with open("foo.txt", "r") as f:
/// ...
/// ```
///
/// Use instead:
/// ```python
/// with open("foo.txt") as f:
/// ...
/// ```
///
/// ## References
/// - [Python documentation: `open`](https://docs.python.org/3/library/functions.html#open)
#[violation]
pub struct RedundantOpenModes {
pub replacement: Option<String>,

View file

@ -10,13 +10,40 @@ use crate::autofix::edits::remove_argument;
use crate::checkers::ast::Checker;
use crate::registry::AsRule;
/// ## What it does
/// Checks for uses of `subprocess.run` that send `stdout` and `stderr` to a
/// pipe.
///
/// ## Why is this bad?
/// As of Python 3.7, `subprocess.run` has a `capture_output` keyword argument
/// that can be set to `True` to capture `stdout` and `stderr` outputs. This is
/// equivalent to setting `stdout` and `stderr` to `subprocess.PIPE`, but is
/// more explicit and readable.
///
/// ## Example
/// ```python
/// import subprocess
///
/// subprocess.run(["foo"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
/// ```
///
/// Use instead:
/// ```python
/// import subprocess
///
/// subprocess.run(["foo"], capture_output=True)
/// ```
///
/// ## References
/// - [Python 3.7 release notes](https://docs.python.org/3/whatsnew/3.7.html#subprocess)
/// - [Python documentation: `subprocess.run`](https://docs.python.org/3/library/subprocess.html#subprocess.run)
#[violation]
pub struct ReplaceStdoutStderr;
impl AlwaysAutofixableViolation for ReplaceStdoutStderr {
#[derive_message_formats]
fn message(&self) -> String {
format!("Sending stdout and stderr to pipe is deprecated, use `capture_output`")
format!("Sending `stdout` and `stderr` to `PIPE` is deprecated, use `capture_output`")
}
fn autofix_title(&self) -> String {

View file

@ -8,6 +8,33 @@ use ruff_python_ast::helpers::find_keyword;
use crate::checkers::ast::Checker;
use crate::registry::AsRule;
/// ## What it does
/// Checks for uses of `subprocess.run` that set the `universal_newlines`
/// keyword argument.
///
/// ## Why is this bad?
/// As of Python 3.7, the `universal_newlines` keyword argument has been
/// renamed to `text`, and now exists for backwards compatibility. The
/// `universal_newlines` keyword argument may be removed in a future version of
/// Python. Prefer `text`, which is more explicit and readable.
///
/// ## Example
/// ```python
/// import subprocess
///
/// subprocess.run(["foo"], universal_newlines=True)
/// ```
///
/// Use instead:
/// ```python
/// import subprocess
///
/// subprocess.run(["foo"], text=True)
/// ```
///
/// ## References
/// - [Python 3.7 release notes](https://docs.python.org/3/whatsnew/3.7.html#subprocess)
/// - [Python documentation: `subprocess.run`](https://docs.python.org/3/library/subprocess.html#subprocess.run)
#[violation]
pub struct ReplaceUniversalNewlines;

View file

@ -7,6 +7,44 @@ use crate::checkers::ast::Checker;
use crate::registry::AsRule;
use crate::rules::pyupgrade::fixes;
/// ## What it does
/// Checks for `super` calls that pass redundant arguments.
///
/// ## Why is this bad?
/// In Python 3, `super` can be invoked without any arguments when: (1) the
/// first argument is `__class__`, and (2) the second argument is equivalent to
/// the first argument of the enclosing method.
///
/// When possible, omit the arguments to `super` to make the code more concise
/// and maintainable.
///
/// ## Example
/// ```python
/// class A:
/// def foo(self):
/// pass
///
///
/// class B(A):
/// def bar(self):
/// super(B, self).foo()
/// ```
///
/// Use instead:
/// ```python
/// class A:
/// def foo(self):
/// pass
///
///
/// class B(A):
/// def bar(self):
/// super().foo()
/// ```
///
/// ## References
/// - [Python documentation: `super`](https://docs.python.org/3/library/functions.html#super)
/// - [super/MRO, Python's most misunderstood feature.](https://www.youtube.com/watch?v=X1PQ7zzltz4)
#[violation]
pub struct SuperCallWithParameters;

View file

@ -8,6 +8,27 @@ use crate::registry::AsRule;
use super::super::types::Primitive;
/// ## What it does
/// Checks for uses of `type` that take a primitive as an argument.
///
/// ## Why is this bad?
/// `type()` returns the type of a given object. A type of a primitive can
/// always be known in advance and accessed directly, which is more concise
/// and explicit than using `type()`.
///
/// ## Example
/// ```python
/// type(1)
/// ```
///
/// Use instead:
/// ```python
/// int
/// ```
///
/// ## References
/// - [Python documentation: `type()`](https://docs.python.org/3/library/functions.html#type)
/// - [Python documentation: Built-in types](https://docs.python.org/3/library/stdtypes.html)
#[violation]
pub struct TypeOfPrimitive {
primitive: Primitive,

View file

@ -1,22 +1,46 @@
use rustpython_parser::ast::{Expr, Ranged};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation};
use ruff_macros::{derive_message_formats, violation};
use crate::checkers::ast::Checker;
use crate::registry::AsRule;
/// ## What it does
/// Checks for uses of `typing.Text`.
///
/// ## Why is this bad?
/// `typing.Text` is an alias for `str`, and only exists for Python 2
/// compatibility. As of Python 3.11, `typing.Text` is deprecated. Use `str`
/// instead.
///
/// ## Example
/// ```python
/// from typing import Text
///
/// foo: Text = "bar"
/// ```
///
/// Use instead:
/// ```python
/// foo: str = "bar"
/// ```
///
/// ## References
/// - [Python documentation: `typing.Text`](https://docs.python.org/3/library/typing.html#typing.Text)
#[violation]
pub struct TypingTextStrAlias;
impl AlwaysAutofixableViolation for TypingTextStrAlias {
impl Violation for TypingTextStrAlias {
const AUTOFIX: AutofixKind = AutofixKind::Sometimes;
#[derive_message_formats]
fn message(&self) -> String {
format!("`typing.Text` is deprecated, use `str`")
}
fn autofix_title(&self) -> String {
"Replace with `str`".to_string()
fn autofix_title(&self) -> Option<String> {
Some("Replace with `str`".to_string())
}
}
@ -31,11 +55,12 @@ pub(crate) fn typing_text_str_alias(checker: &mut Checker, expr: &Expr) {
{
let mut diagnostic = Diagnostic::new(TypingTextStrAlias, expr.range());
if checker.patch(diagnostic.kind.rule()) {
#[allow(deprecated)]
diagnostic.set_fix(Fix::unspecified(Edit::range_replacement(
"str".to_string(),
expr.range(),
)));
if checker.semantic().is_builtin("str") {
diagnostic.set_fix(Fix::automatic(Edit::range_replacement(
"str".to_string(),
expr.range(),
)));
}
}
checker.diagnostics.push(diagnostic);
}

View file

@ -7,6 +7,25 @@ use ruff_macros::{derive_message_formats, violation};
use crate::checkers::ast::Checker;
use crate::registry::AsRule;
/// ## What it does
/// Checks for uses of the Unicode kind prefix (`u`) in strings.
///
/// ## Why is this bad?
/// In Python 3, all strings are Unicode by default. The Unicode kind prefix is
/// unnecessary and should be removed to avoid confusion.
///
/// ## Example
/// ```python
/// u"foo"
/// ```
///
/// Use instead:
/// ```python
/// "foo"
/// ```
///
/// ## References
/// - [Python documentation: Unicode HOWTO](https://docs.python.org/3/howto/unicode.html)
#[violation]
pub struct UnicodeKindPrefix;
@ -23,17 +42,14 @@ impl AlwaysAutofixableViolation for UnicodeKindPrefix {
/// UP025
pub(crate) fn unicode_kind_prefix(checker: &mut Checker, expr: &Expr, kind: Option<&str>) {
if let Some(const_kind) = kind {
if const_kind.to_lowercase() == "u" {
let mut diagnostic = Diagnostic::new(UnicodeKindPrefix, expr.range());
if checker.patch(diagnostic.kind.rule()) {
#[allow(deprecated)]
diagnostic.set_fix(Fix::unspecified(Edit::range_deletion(TextRange::at(
expr.start(),
TextSize::from(1),
))));
}
checker.diagnostics.push(diagnostic);
if matches!(kind, Some("u" | "U")) {
let mut diagnostic = Diagnostic::new(UnicodeKindPrefix, expr.range());
if checker.patch(diagnostic.kind.rule()) {
diagnostic.set_fix(Fix::automatic(Edit::range_deletion(TextRange::at(
expr.start(),
TextSize::from(1),
))));
}
checker.diagnostics.push(diagnostic);
}
}

View file

@ -8,6 +8,27 @@ use crate::autofix;
use crate::checkers::ast::Checker;
use crate::registry::AsRule;
/// ## What it does
/// Checks for unnecessary imports of builtins.
///
/// ## Why is this bad?
/// Builtins are always available. Importing them is unnecessary and should be
/// removed to avoid confusion.
///
/// ## Example
/// ```python
/// from builtins import str
///
/// str(1)
/// ```
///
/// Use instead:
/// ```python
/// str(1)
/// ```
///
/// ## References
/// - [Python documentation: The Python Standard Library](https://docs.python.org/3/library/index.html)
#[violation]
pub struct UnnecessaryBuiltinImport {
pub names: Vec<String>,

View file

@ -5,7 +5,25 @@ use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_whitespace::Line;
// TODO: document referencing [PEP 3120]: https://peps.python.org/pep-3120/
/// ## What it does
/// Checks for unnecessary UTF-8 encoding declarations.
///
/// ## Why is this bad?
/// [PEP 3120] makes UTF-8 the default encoding, so a UTF-8 encoding
/// declaration is unnecessary.
///
/// ## Example
/// ```python
/// # -*- coding: utf-8 -*-
/// print("Hello, world!")
/// ```
///
/// Use instead:
/// ```python
/// print("Hello, world!")
/// ```
///
/// [PEP 3120]: https://peps.python.org/pep-3120/
#[violation]
pub struct UTF8EncodingDeclaration;

View file

@ -16,6 +16,25 @@ pub(crate) enum Reason {
DefaultArgument,
}
/// ## What it does
/// Checks for unnecessary calls to `encode` as UTF-8.
///
/// ## Why is this bad?
/// UTF-8 is the default encoding in Python, so there is no need to call
/// `encode` when UTF-8 is the desired encoding. Instead, use a bytes literal.
///
/// ## Example
/// ```python
/// "foo".encode("utf-8")
/// ```
///
/// Use instead:
/// ```python
/// b"foo"
/// ```
///
/// ## References
/// - [Python documentation: `str.encode`](https://docs.python.org/3/library/stdtypes.html#str.encode)
#[violation]
pub struct UnnecessaryEncodeUTF8 {
reason: Reason,

View file

@ -8,6 +8,30 @@ use crate::autofix;
use crate::checkers::ast::Checker;
use crate::registry::AsRule;
/// ## What it does
/// Checks for unnecessary `__future__` imports.
///
/// ## Why is this bad?
/// The `__future__` module is used to enable features that are not yet
/// available in the current Python version. If a feature is already
/// available in the minimum supported Python version, importing it
/// from `__future__` is unnecessary and should be removed to avoid
/// confusion.
///
/// ## Example
/// ```python
/// from __future__ import print_function
///
/// print("Hello, world!")
/// ```
///
/// Use instead:
/// ```python
/// print("Hello, world!")
/// ```
///
/// ## References
/// - [Python documentation: `__future__` — Future statement definitions](https://docs.python.org/3/library/__future__.html)
#[violation]
pub struct UnnecessaryFutureImport {
pub names: Vec<String>,

View file

@ -7,6 +7,27 @@ use ruff_python_ast::helpers::any_over_expr;
use crate::checkers::ast::Checker;
use crate::registry::AsRule;
/// ## What it does
/// Checks for list comprehensions that are immediately unpacked.
///
/// ## Why is this bad?
/// There is no reason to use a list comprehension if the result is immediately
/// unpacked. Instead, use a generator expression, which is more efficient as
/// it avoids allocating an intermediary list.
///
/// ## Example
/// ```python
/// a, b, c = [foo(x) for x in items]
/// ```
///
/// Use instead:
/// ```python
/// a, b, c = (foo(x) for x in items)
/// ```
///
/// ## References
/// - [Python documentation: Generator expressions](https://docs.python.org/3/reference/expressions.html#generator-expressions)
/// - [Python documentation: List comprehensions](https://docs.python.org/3/tutorial/datastructures.html#list-comprehensions)
#[violation]
pub struct UnpackedListComprehension;

View file

@ -9,6 +9,33 @@ use crate::checkers::ast::Checker;
use crate::importer::ImportRequest;
use crate::registry::AsRule;
/// ## What it does
/// Checks for the use of generics that can be replaced with standard library
/// variants based on [PEP 585].
///
/// ## Why is this bad?
/// [PEP 585] enabled collections in the Python standard library (like `list`)
/// to be used as generics directly, instead of importing analogous members
/// from the `typing` module (like `typing.List`).
///
/// When available, the [PEP 585] syntax should be used instead of importing
/// members from the `typing` module, as it's more concise and readable.
/// Importing those members from `typing` is considered deprecated as of PEP
/// 585.
///
/// ## Example
/// ```python
/// from typing import List
///
/// foo: List[int] = [1, 2, 3]
/// ```
///
/// Use instead:
/// ```python
/// foo: list[int] = [1, 2, 3]
/// ```
///
/// [PEP 585]: https://peps.python.org/pep-0585/
#[violation]
pub struct NonPEP585Annotation {
from: String,

View file

@ -8,6 +8,27 @@ use ruff_python_semantic::analyze::typing::Pep604Operator;
use crate::checkers::ast::Checker;
use crate::registry::AsRule;
/// ## What it does
/// Check for type annotations that can be rewritten based on [PEP 604] syntax.
///
/// ## Why is this bad?
/// [PEP 604] introduced a new syntax for union type annotations based on the
/// `|` operator. This syntax is more concise and readable than the previous
/// `typing.Union` and `typing.Optional` syntaxes.
///
/// ## Example
/// ```python
/// from typing import Union
///
/// foo: Union[int, str] = 1
/// ```
///
/// Use instead:
/// ```python
/// foo: int | str = 1
/// ```
///
/// [PEP 604]: https://peps.python.org/pep-0604/
#[violation]
pub struct NonPEP604Annotation;

View file

@ -34,6 +34,30 @@ impl CallKind {
}
}
/// ## What it does
/// Checks for uses of `isinstance` and `issubclass` that take a tuple
/// of types for comparison.
///
/// ## Why is this bad?
/// Since Python 3.10, `isinstance` and `issubclass` can be passed a
/// `|`-separated union of types, which is more concise and consistent
/// with the union operator introduced in [PEP 604].
///
/// ## Example
/// ```python
/// isinstance(x, (int, float))
/// ```
///
/// Use instead:
/// ```python
/// isinstance(x, int | float)
/// ```
///
/// ## References
/// - [Python documentation: `isinstance`](https://docs.python.org/3/library/functions.html#isinstance)
/// - [Python documentation: `issubclass`](https://docs.python.org/3/library/functions.html#issubclass)
///
/// [PEP 604]: https://peps.python.org/pep-0604/
#[violation]
pub struct NonPEP604Isinstance {
kind: CallKind,

View file

@ -7,6 +7,26 @@ use crate::autofix;
use crate::checkers::ast::Checker;
use crate::registry::AsRule;
/// ## What it does
/// Checks for the use of `__metaclass__ = type` in class definitions.
///
/// ## Why is this bad?
/// Since Python 3, `__metaclass__ = type` is implied and can thus be omitted.
///
/// ## Example
/// ```python
/// class Foo:
/// __metaclass__ = type
/// ```
///
/// Use instead:
/// ```python
/// class Foo:
/// ...
/// ```
///
/// ## References
/// - [PEP 3115](https://www.python.org/dev/peps/pep-3115/)
#[violation]
pub struct UselessMetaclassType;

View file

@ -8,6 +8,27 @@ use crate::autofix::edits::remove_argument;
use crate::checkers::ast::Checker;
use crate::registry::AsRule;
/// ## What it does
/// Checks for classes that inherit from `object`.
///
/// ## Why is this bad?
/// Since Python 3, all classes inherit from `object` by default, so `object` can
/// be omitted from the list of base classes.
///
/// ## Example
/// ```python
/// class Foo(object):
/// ...
/// ```
///
/// Use instead:
/// ```python
/// class Foo:
/// ...
/// ```
///
/// ## References
/// - [PEP 3115](https://www.python.org/dev/peps/pep-3115/)
#[violation]
pub struct UselessObjectInheritance {
name: String,

View file

@ -11,6 +11,27 @@ use ruff_python_ast::{statement_visitor, visitor};
use crate::checkers::ast::Checker;
use crate::registry::AsRule;
/// ## What it does
/// Checks for `for` loops that can be replaced with `yield from` expressions.
///
/// ## Why is this bad?
/// If a `for` loop only contains a `yield` statement, it can be replaced with a
/// `yield from` expression, which is more concise and idiomatic.
///
/// ## Example
/// ```python
/// for x in foo:
/// yield x
/// ```
///
/// Use instead:
/// ```python
/// yield from foo
/// ```
///
/// ## References
/// - [Python documentation: The `yield` statement](https://docs.python.org/3/reference/simple_stmts.html#the-yield-statement)
/// - [PEP 380](https://peps.python.org/pep-0380/)
#[violation]
pub struct YieldInForLoop;

View file

@ -9,7 +9,7 @@ UP019.py:7:22: UP019 [*] `typing.Text` is deprecated, use `str`
|
= help: Replace with `str`
Suggested fix
Fix
4 4 | from typing import Text as Goodbye
5 5 |
6 6 |
@ -27,7 +27,7 @@ UP019.py:11:29: UP019 [*] `typing.Text` is deprecated, use `str`
|
= help: Replace with `str`
Suggested fix
Fix
8 8 | print(word)
9 9 |
10 10 |
@ -45,7 +45,7 @@ UP019.py:15:28: UP019 [*] `typing.Text` is deprecated, use `str`
|
= help: Replace with `str`
Suggested fix
Fix
12 12 | print(word)
13 13 |
14 14 |
@ -63,7 +63,7 @@ UP019.py:19:29: UP019 [*] `typing.Text` is deprecated, use `str`
|
= help: Replace with `str`
Suggested fix
Fix
16 16 | print(word)
17 17 |
18 18 |

View file

@ -1,7 +1,7 @@
---
source: crates/ruff/src/rules/pyupgrade/mod.rs
---
UP022.py:4:10: UP022 [*] Sending stdout and stderr to pipe is deprecated, use `capture_output`
UP022.py:4:10: UP022 [*] Sending `stdout` and `stderr` to `PIPE` is deprecated, use `capture_output`
|
2 | import subprocess
3 |
@ -22,7 +22,7 @@ UP022.py:4:10: UP022 [*] Sending stdout and stderr to pipe is deprecated, use `c
6 6 | output = subprocess.run(["foo"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
7 7 |
UP022.py:6:10: UP022 [*] Sending stdout and stderr to pipe is deprecated, use `capture_output`
UP022.py:6:10: UP022 [*] Sending `stdout` and `stderr` to `PIPE` is deprecated, use `capture_output`
|
4 | output = run(["foo"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
5 |
@ -43,7 +43,7 @@ UP022.py:6:10: UP022 [*] Sending stdout and stderr to pipe is deprecated, use `c
8 8 | output = subprocess.run(stdout=subprocess.PIPE, args=["foo"], stderr=subprocess.PIPE)
9 9 |
UP022.py:8:10: UP022 [*] Sending stdout and stderr to pipe is deprecated, use `capture_output`
UP022.py:8:10: UP022 [*] Sending `stdout` and `stderr` to `PIPE` is deprecated, use `capture_output`
|
6 | output = subprocess.run(["foo"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
7 |
@ -64,7 +64,7 @@ UP022.py:8:10: UP022 [*] Sending stdout and stderr to pipe is deprecated, use `c
10 10 | output = subprocess.run(
11 11 | ["foo"], stdout=subprocess.PIPE, check=True, stderr=subprocess.PIPE
UP022.py:10:10: UP022 [*] Sending stdout and stderr to pipe is deprecated, use `capture_output`
UP022.py:10:10: UP022 [*] Sending `stdout` and `stderr` to `PIPE` is deprecated, use `capture_output`
|
8 | output = subprocess.run(stdout=subprocess.PIPE, args=["foo"], stderr=subprocess.PIPE)
9 |
@ -88,7 +88,7 @@ UP022.py:10:10: UP022 [*] Sending stdout and stderr to pipe is deprecated, use `
13 13 |
14 14 | output = subprocess.run(
UP022.py:14:10: UP022 [*] Sending stdout and stderr to pipe is deprecated, use `capture_output`
UP022.py:14:10: UP022 [*] Sending `stdout` and `stderr` to `PIPE` is deprecated, use `capture_output`
|
12 | )
13 |
@ -112,7 +112,7 @@ UP022.py:14:10: UP022 [*] Sending stdout and stderr to pipe is deprecated, use `
17 17 |
18 18 | output = subprocess.run(
UP022.py:18:10: UP022 [*] Sending stdout and stderr to pipe is deprecated, use `capture_output`
UP022.py:18:10: UP022 [*] Sending `stdout` and `stderr` to `PIPE` is deprecated, use `capture_output`
|
16 | )
17 |
@ -144,7 +144,7 @@ UP022.py:18:10: UP022 [*] Sending stdout and stderr to pipe is deprecated, use `
24 23 | encoding="utf-8",
25 24 | close_fds=True,
UP022.py:29:14: UP022 [*] Sending stdout and stderr to pipe is deprecated, use `capture_output`
UP022.py:29:14: UP022 [*] Sending `stdout` and `stderr` to `PIPE` is deprecated, use `capture_output`
|
28 | if output:
29 | output = subprocess.run(

View file

@ -11,7 +11,7 @@ UP025.py:2:5: UP025 [*] Remove unicode literals from strings
|
= help: Remove unicode prefix
Suggested fix
Fix
1 1 | # These should change
2 |-x = u"Hello"
2 |+x = "Hello"
@ -30,7 +30,7 @@ UP025.py:4:1: UP025 [*] Remove unicode literals from strings
|
= help: Remove unicode prefix
Suggested fix
Fix
1 1 | # These should change
2 2 | x = u"Hello"
3 3 |
@ -51,7 +51,7 @@ UP025.py:6:7: UP025 [*] Remove unicode literals from strings
|
= help: Remove unicode prefix
Suggested fix
Fix
3 3 |
4 4 | u'world'
5 5 |
@ -72,7 +72,7 @@ UP025.py:8:7: UP025 [*] Remove unicode literals from strings
|
= help: Remove unicode prefix
Suggested fix
Fix
5 5 |
6 6 | print(u"Hello")
7 7 |
@ -93,7 +93,7 @@ UP025.py:12:5: UP025 [*] Remove unicode literals from strings
|
= help: Remove unicode prefix
Suggested fix
Fix
9 9 |
10 10 | import foo
11 11 |
@ -114,7 +114,7 @@ UP025.py:12:15: UP025 [*] Remove unicode literals from strings
|
= help: Remove unicode prefix
Suggested fix
Fix
9 9 |
10 10 | import foo
11 11 |
@ -135,7 +135,7 @@ UP025.py:12:27: UP025 [*] Remove unicode literals from strings
|
= help: Remove unicode prefix
Suggested fix
Fix
9 9 |
10 10 | import foo
11 11 |
@ -156,7 +156,7 @@ UP025.py:12:39: UP025 [*] Remove unicode literals from strings
|
= help: Remove unicode prefix
Suggested fix
Fix
9 9 |
10 10 | import foo
11 11 |
@ -177,7 +177,7 @@ UP025.py:16:5: UP025 [*] Remove unicode literals from strings
|
= help: Remove unicode prefix
Suggested fix
Fix
13 13 |
14 14 | # These should stay quoted they way they are
15 15 |
@ -197,7 +197,7 @@ UP025.py:17:5: UP025 [*] Remove unicode literals from strings
|
= help: Remove unicode prefix
Suggested fix
Fix
14 14 | # These should stay quoted they way they are
15 15 |
16 16 | x = u'hello'
@ -217,7 +217,7 @@ UP025.py:18:5: UP025 [*] Remove unicode literals from strings
|
= help: Remove unicode prefix
Suggested fix
Fix
15 15 |
16 16 | x = u'hello'
17 17 | x = u"""hello"""
@ -238,7 +238,7 @@ UP025.py:19:5: UP025 [*] Remove unicode literals from strings
|
= help: Remove unicode prefix
Suggested fix
Fix
16 16 | x = u'hello'
17 17 | x = u"""hello"""
18 18 | x = u'''hello'''

View file

@ -48,6 +48,7 @@ KNOWN_FORMATTING_VIOLATIONS = [
"too-few-spaces-before-inline-comment",
"trailing-comma-on-bare-tuple",
"unexpected-indentation-comment",
"unicode-kind-prefix",
"unnecessary-class-parentheses",
"useless-semicolon",
"whitespace-after-open-bracket",