From 8fd002c7438f2b775d25648774670faca65c1561 Mon Sep 17 00:00:00 2001 From: Zanie Date: Wed, 2 Aug 2023 18:44:11 -0500 Subject: [PATCH 1/7] Add rule to upgrade type alias annotations to keyword --- .../resources/test/fixtures/ruff/RUF017.py | 16 ++++ .../src/checkers/ast/analyze/statement.rs | 17 ++-- crates/ruff/src/codes.rs | 1 + crates/ruff/src/rules/ruff/mod.rs | 1 + crates/ruff/src/rules/ruff/rules/mod.rs | 2 + .../rules/ruff/rules/type_alias_annotation.rs | 89 +++++++++++++++++++ ..._rules__ruff__tests__RUF017_RUF017.py.snap | 37 ++++++++ ...rmat@expression__boolean_operation.py.snap | 24 +++++ ruff.schema.json | 3 +- 9 files changed, 183 insertions(+), 7 deletions(-) create mode 100644 crates/ruff/resources/test/fixtures/ruff/RUF017.py create mode 100644 crates/ruff/src/rules/ruff/rules/type_alias_annotation.rs create mode 100644 crates/ruff/src/rules/ruff/snapshots/ruff__rules__ruff__tests__RUF017_RUF017.py.snap diff --git a/crates/ruff/resources/test/fixtures/ruff/RUF017.py b/crates/ruff/resources/test/fixtures/ruff/RUF017.py new file mode 100644 index 0000000000000..99034d0ab0901 --- /dev/null +++ b/crates/ruff/resources/test/fixtures/ruff/RUF017.py @@ -0,0 +1,16 @@ +import typing +from typing import TypeAlias + +# RUF017 +x: typing.TypeAlias = int +x: TypeAlias = int + + +# RUF017 with generics (todo) +T = typing.TypeVar["T"] +x: typing.TypeAlias = list[T] + + +# OK +x: TypeAlias +x: int = 1 diff --git a/crates/ruff/src/checkers/ast/analyze/statement.rs b/crates/ruff/src/checkers/ast/analyze/statement.rs index 55e34d28cdb1d..6addff17bc54c 100644 --- a/crates/ruff/src/checkers/ast/analyze/statement.rs +++ b/crates/ruff/src/checkers/ast/analyze/statement.rs @@ -1346,12 +1346,14 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { } } } - Stmt::AnnAssign(ast::StmtAnnAssign { - target, - value, - annotation, - .. - }) => { + Stmt::AnnAssign( + assign_stmt @ ast::StmtAnnAssign { + target, + value, + annotation, + .. + }, + ) => { if let Some(value) = value { if checker.enabled(Rule::LambdaAssignment) { pycodestyle::rules::lambda_assignment( @@ -1374,6 +1376,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { stmt, ); } + if checker.enabled(Rule::TypeAliasAnnotation) { + ruff::rules::type_alias_annotation(checker, assign_stmt); + } if checker.is_stub { if let Some(value) = value { if checker.enabled(Rule::AssignmentDefaultInStub) { diff --git a/crates/ruff/src/codes.rs b/crates/ruff/src/codes.rs index 64e795cde81a3..85d00f04a9926 100644 --- a/crates/ruff/src/codes.rs +++ b/crates/ruff/src/codes.rs @@ -807,6 +807,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> { (Ruff, "014") => (RuleGroup::Nursery, rules::ruff::rules::UnreachableCode), (Ruff, "015") => (RuleGroup::Unspecified, rules::ruff::rules::UnnecessaryIterableAllocationForFirstElement), (Ruff, "016") => (RuleGroup::Unspecified, rules::ruff::rules::InvalidIndexType), + (Ruff, "017") => (RuleGroup::Unspecified, rules::ruff::rules::TypeAliasAnnotation), (Ruff, "100") => (RuleGroup::Unspecified, rules::ruff::rules::UnusedNOQA), (Ruff, "200") => (RuleGroup::Unspecified, rules::ruff::rules::InvalidPyprojectToml), diff --git a/crates/ruff/src/rules/ruff/mod.rs b/crates/ruff/src/rules/ruff/mod.rs index 42350547abd15..98b2cc5133fbf 100644 --- a/crates/ruff/src/rules/ruff/mod.rs +++ b/crates/ruff/src/rules/ruff/mod.rs @@ -36,6 +36,7 @@ mod tests { Path::new("RUF015.py") )] #[test_case(Rule::InvalidIndexType, Path::new("RUF016.py"))] + #[test_case(Rule::TypeAliasAnnotation, Path::new("RUF017.py"))] #[cfg_attr( feature = "unreachable-code", test_case(Rule::UnreachableCode, Path::new("RUF014.py")) diff --git a/crates/ruff/src/rules/ruff/rules/mod.rs b/crates/ruff/src/rules/ruff/rules/mod.rs index e4d39feefd825..2db41a251b575 100644 --- a/crates/ruff/src/rules/ruff/rules/mod.rs +++ b/crates/ruff/src/rules/ruff/rules/mod.rs @@ -10,6 +10,7 @@ pub(crate) use mutable_class_default::*; pub(crate) use mutable_dataclass_default::*; pub(crate) use pairwise_over_zipped::*; pub(crate) use static_key_dict_comprehension::*; +pub(crate) use type_alias_annotation::*; pub(crate) use unnecessary_iterable_allocation_for_first_element::*; #[cfg(feature = "unreachable-code")] pub(crate) use unreachable::*; @@ -29,6 +30,7 @@ mod mutable_class_default; mod mutable_dataclass_default; mod pairwise_over_zipped; mod static_key_dict_comprehension; +mod type_alias_annotation; mod unnecessary_iterable_allocation_for_first_element; #[cfg(feature = "unreachable-code")] pub(crate) mod unreachable; diff --git a/crates/ruff/src/rules/ruff/rules/type_alias_annotation.rs b/crates/ruff/src/rules/ruff/rules/type_alias_annotation.rs new file mode 100644 index 0000000000000..aec298fb9ea9e --- /dev/null +++ b/crates/ruff/src/rules/ruff/rules/type_alias_annotation.rs @@ -0,0 +1,89 @@ +use ruff_python_ast::{Expr, ExprName, Ranged, Stmt, StmtAnnAssign, StmtTypeAlias}; + +use crate::{registry::AsRule, settings::types::PythonVersion}; +use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation}; +use ruff_macros::{derive_message_formats, violation}; +use ruff_text_size::TextRange; + +use crate::checkers::ast::Checker; + +/// ## What it does +/// Checks for use of `TypeAlias` annotation for declaring type aliases. +/// +/// ## Why is this bad? +/// The `type` keyword was introduced in Python 3.12 by PEP-695 for defining type aliases. +/// The type keyword is easier to read and provides cleaner support for generics. +/// +/// ## Example +/// ```python +/// ListOfInt: TypeAlias = list[int] +/// ``` +/// +/// Use instead: +/// ```python +/// type ListOfInt = list[int] +/// ``` +#[violation] +pub struct TypeAliasAnnotation { + name: String, +} + +impl Violation for TypeAliasAnnotation { + const AUTOFIX: AutofixKind = AutofixKind::Always; + + #[derive_message_formats] + fn message(&self) -> String { + let TypeAliasAnnotation { name } = self; + format!("Type alias `{name}` uses `TypeAlias` annotation instead of the `type` keyword.") + } + + fn autofix_title(&self) -> Option { + Some("Use the `type` keyword instead".to_string()) + } +} + +/// RUF017 +pub(crate) fn type_alias_annotation(checker: &mut Checker, stmt: &StmtAnnAssign) { + let StmtAnnAssign { + target, + annotation, + value, + .. + } = stmt; + + // Syntax only available in 3.12+ + if checker.settings.target_version < PythonVersion::Py312 { + return; + } + + if !checker + .semantic() + .match_typing_expr(annotation, "TypeAlias") + { + return; + } + + let Expr::Name(ExprName { id: name, .. }) = target.as_ref() else { + return; + }; + + let Some(value) = value else { + return; + }; + + // todo(zanie): We should check for generic type variables used in the value and define them + // as type params instead + let mut diagnostic = Diagnostic::new(TypeAliasAnnotation { name: name.clone() }, stmt.range()); + if checker.patch(diagnostic.kind.rule()) { + diagnostic.set_fix(Fix::automatic(Edit::range_replacement( + checker.generator().stmt(&Stmt::from(StmtTypeAlias { + range: TextRange::default(), + name: target.clone(), + type_params: None, + value: value.clone(), + })), + stmt.range(), + ))); + } + checker.diagnostics.push(diagnostic); +} diff --git a/crates/ruff/src/rules/ruff/snapshots/ruff__rules__ruff__tests__RUF017_RUF017.py.snap b/crates/ruff/src/rules/ruff/snapshots/ruff__rules__ruff__tests__RUF017_RUF017.py.snap new file mode 100644 index 0000000000000..5ac88c73a5bcf --- /dev/null +++ b/crates/ruff/src/rules/ruff/snapshots/ruff__rules__ruff__tests__RUF017_RUF017.py.snap @@ -0,0 +1,37 @@ +--- +source: crates/ruff/src/rules/ruff/mod.rs +--- +RUF017.py:4:1: RUF017 [*] Type alias `x` uses `TypeAlias` annotation instead of the `type` keyword. + | +2 | from typing import TypeAlias +3 | +4 | x: typing.TypeAlias = int + | ^^^^^^^^^^^^^^^^^^^^^^^^^ RUF017 +5 | x: TypeAlias = int + | + = help: Use the `type` keyword instead + +ℹ Fix +1 1 | import typing +2 2 | from typing import TypeAlias +3 3 | +4 |-x: typing.TypeAlias = int + 4 |+type x = int +5 5 | x: TypeAlias = int + +RUF017.py:5:1: RUF017 [*] Type alias `x` uses `TypeAlias` annotation instead of the `type` keyword. + | +4 | x: typing.TypeAlias = int +5 | x: TypeAlias = int + | ^^^^^^^^^^^^^^^^^^ RUF017 + | + = help: Use the `type` keyword instead + +ℹ Fix +2 2 | from typing import TypeAlias +3 3 | +4 4 | x: typing.TypeAlias = int +5 |-x: TypeAlias = int + 5 |+type x = int + + diff --git a/crates/ruff_python_formatter/tests/snapshots/format@expression__boolean_operation.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@expression__boolean_operation.py.snap index 979f6fb80509d..246483692811f 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@expression__boolean_operation.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@expression__boolean_operation.py.snap @@ -68,6 +68,17 @@ if ( and [dddddddddddddd, eeeeeeeeee, fffffffffffffff] ): pass + +# Regression test for https://github.com/astral-sh/ruff/issues/6068 +if not ( + isinstance(aaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbb) or numpy and isinstance(ccccccccccc, dddddd) +): + pass + +if not ( + isinstance(aaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbb) and numpy or isinstance(ccccccccccc, dddddd) +): + pass ``` ## Output @@ -136,6 +147,19 @@ if ( and [dddddddddddddd, eeeeeeeeee, fffffffffffffff] ): pass + +# Regression test for https://github.com/astral-sh/ruff/issues/6068 +if not ( + isinstance(aaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbb) + or numpy and isinstance(ccccccccccc, dddddd) +): + pass + +if not ( + isinstance(aaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbb) and numpy + or isinstance(ccccccccccc, dddddd) +): + pass ``` diff --git a/ruff.schema.json b/ruff.schema.json index 96ff8fe0a8fd5..f419e9454dded 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -2453,6 +2453,7 @@ "RUF013", "RUF015", "RUF016", + "RUF017", "RUF1", "RUF10", "RUF100", @@ -2742,4 +2743,4 @@ "type": "string" } } -} \ No newline at end of file +} From 2ea5aeed224e84238df25d79b98a757c0af6dab5 Mon Sep 17 00:00:00 2001 From: Zanie Date: Thu, 3 Aug 2023 10:02:28 -0500 Subject: [PATCH 2/7] Move rule to pyupgrade, test based on Python version --- .../{ruff/RUF017.py => pyupgrade/UP100.py} | 4 +- .../src/checkers/ast/analyze/statement.rs | 4 +- crates/ruff/src/codes.rs | 2 +- crates/ruff/src/rules/pyflakes/mod.rs | 2 +- crates/ruff/src/rules/pyupgrade/mod.rs | 26 ++++++++ crates/ruff/src/rules/pyupgrade/rules/mod.rs | 2 + .../rules/use_pep695_type_alias.rs} | 18 +++--- ...n_pep695_type_alias_not_applied_py311.snap | 4 ++ ...e__tests__non_pep695_type_alias_py312.snap | 61 +++++++++++++++++++ crates/ruff/src/rules/ruff/mod.rs | 1 - crates/ruff/src/rules/ruff/rules/mod.rs | 2 - ..._rules__ruff__tests__RUF017_RUF017.py.snap | 37 ----------- ...rmat@expression__boolean_operation.py.snap | 24 -------- ruff.schema.json | 4 +- 14 files changed, 111 insertions(+), 80 deletions(-) rename crates/ruff/resources/test/fixtures/{ruff/RUF017.py => pyupgrade/UP100.py} (81%) rename crates/ruff/src/rules/{ruff/rules/type_alias_annotation.rs => pyupgrade/rules/use_pep695_type_alias.rs} (82%) create mode 100644 crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__non_pep695_type_alias_not_applied_py311.snap create mode 100644 crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__non_pep695_type_alias_py312.snap delete mode 100644 crates/ruff/src/rules/ruff/snapshots/ruff__rules__ruff__tests__RUF017_RUF017.py.snap diff --git a/crates/ruff/resources/test/fixtures/ruff/RUF017.py b/crates/ruff/resources/test/fixtures/pyupgrade/UP100.py similarity index 81% rename from crates/ruff/resources/test/fixtures/ruff/RUF017.py rename to crates/ruff/resources/test/fixtures/pyupgrade/UP100.py index 99034d0ab0901..72bc9f565f4ef 100644 --- a/crates/ruff/resources/test/fixtures/ruff/RUF017.py +++ b/crates/ruff/resources/test/fixtures/pyupgrade/UP100.py @@ -1,12 +1,12 @@ import typing from typing import TypeAlias -# RUF017 +# UP100 x: typing.TypeAlias = int x: TypeAlias = int -# RUF017 with generics (todo) +# UP100 with generics (todo) T = typing.TypeVar["T"] x: typing.TypeAlias = list[T] diff --git a/crates/ruff/src/checkers/ast/analyze/statement.rs b/crates/ruff/src/checkers/ast/analyze/statement.rs index 6addff17bc54c..bfa5cda197557 100644 --- a/crates/ruff/src/checkers/ast/analyze/statement.rs +++ b/crates/ruff/src/checkers/ast/analyze/statement.rs @@ -1376,8 +1376,8 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { stmt, ); } - if checker.enabled(Rule::TypeAliasAnnotation) { - ruff::rules::type_alias_annotation(checker, assign_stmt); + if checker.enabled(Rule::NonPEP695TypeAlias) { + pyupgrade::rules::non_pep695_type_alias(checker, assign_stmt); } if checker.is_stub { if let Some(value) = value { diff --git a/crates/ruff/src/codes.rs b/crates/ruff/src/codes.rs index 85d00f04a9926..a581e26ccf532 100644 --- a/crates/ruff/src/codes.rs +++ b/crates/ruff/src/codes.rs @@ -438,6 +438,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> { (Pyupgrade, "037") => (RuleGroup::Unspecified, rules::pyupgrade::rules::QuotedAnnotation), (Pyupgrade, "038") => (RuleGroup::Unspecified, rules::pyupgrade::rules::NonPEP604Isinstance), (Pyupgrade, "039") => (RuleGroup::Unspecified, rules::pyupgrade::rules::UnnecessaryClassParentheses), + (Pyupgrade, "100") => (RuleGroup::Unspecified, rules::pyupgrade::rules::NonPEP695TypeAlias), // pydocstyle (Pydocstyle, "100") => (RuleGroup::Unspecified, rules::pydocstyle::rules::UndocumentedPublicModule), @@ -807,7 +808,6 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> { (Ruff, "014") => (RuleGroup::Nursery, rules::ruff::rules::UnreachableCode), (Ruff, "015") => (RuleGroup::Unspecified, rules::ruff::rules::UnnecessaryIterableAllocationForFirstElement), (Ruff, "016") => (RuleGroup::Unspecified, rules::ruff::rules::InvalidIndexType), - (Ruff, "017") => (RuleGroup::Unspecified, rules::ruff::rules::TypeAliasAnnotation), (Ruff, "100") => (RuleGroup::Unspecified, rules::ruff::rules::UnusedNOQA), (Ruff, "200") => (RuleGroup::Unspecified, rules::ruff::rules::InvalidPyprojectToml), diff --git a/crates/ruff/src/rules/pyflakes/mod.rs b/crates/ruff/src/rules/pyflakes/mod.rs index 7eb0434f31ef6..b37f23c7b5462 100644 --- a/crates/ruff/src/rules/pyflakes/mod.rs +++ b/crates/ruff/src/rules/pyflakes/mod.rs @@ -3422,7 +3422,7 @@ mod tests { } #[test] - fn type_alias_annotations() { + fn use_pep695_type_aliass() { flakes( r#" from typing_extensions import TypeAlias diff --git a/crates/ruff/src/rules/pyupgrade/mod.rs b/crates/ruff/src/rules/pyupgrade/mod.rs index 0ec3c25e4b7db..0d5360bfc87b3 100644 --- a/crates/ruff/src/rules/pyupgrade/mod.rs +++ b/crates/ruff/src/rules/pyupgrade/mod.rs @@ -88,6 +88,32 @@ mod tests { Ok(()) } + #[test] + fn non_pep695_type_alias_not_applied_py311() -> Result<()> { + let diagnostics = test_path( + Path::new("pyupgrade/UP100.py"), + &settings::Settings { + target_version: PythonVersion::Py311, + ..settings::Settings::for_rule(Rule::NonPEP695TypeAlias) + }, + )?; + assert_messages!(diagnostics); + Ok(()) + } + + #[test] + fn non_pep695_type_alias_py312() -> Result<()> { + let diagnostics = test_path( + Path::new("pyupgrade/UP100.py"), + &settings::Settings { + target_version: PythonVersion::Py312, + ..settings::Settings::for_rule(Rule::NonPEP695TypeAlias) + }, + )?; + assert_messages!(diagnostics); + Ok(()) + } + #[test] fn future_annotations_keep_runtime_typing_p37() -> Result<()> { let diagnostics = test_path( diff --git a/crates/ruff/src/rules/pyupgrade/rules/mod.rs b/crates/ruff/src/rules/pyupgrade/rules/mod.rs index 16ca52a57b49b..0a924c145120d 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/mod.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/mod.rs @@ -32,6 +32,7 @@ pub(crate) use unpacked_list_comprehension::*; pub(crate) use use_pep585_annotation::*; pub(crate) use use_pep604_annotation::*; pub(crate) use use_pep604_isinstance::*; +pub(crate) use use_pep695_type_alias::*; pub(crate) use useless_metaclass_type::*; pub(crate) use useless_object_inheritance::*; pub(crate) use yield_in_for_loop::*; @@ -70,6 +71,7 @@ mod unpacked_list_comprehension; mod use_pep585_annotation; mod use_pep604_annotation; mod use_pep604_isinstance; +mod use_pep695_type_alias; mod useless_metaclass_type; mod useless_object_inheritance; mod yield_in_for_loop; diff --git a/crates/ruff/src/rules/ruff/rules/type_alias_annotation.rs b/crates/ruff/src/rules/pyupgrade/rules/use_pep695_type_alias.rs similarity index 82% rename from crates/ruff/src/rules/ruff/rules/type_alias_annotation.rs rename to crates/ruff/src/rules/pyupgrade/rules/use_pep695_type_alias.rs index aec298fb9ea9e..1aa2e3a0b5f6d 100644 --- a/crates/ruff/src/rules/ruff/rules/type_alias_annotation.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/use_pep695_type_alias.rs @@ -24,26 +24,26 @@ use crate::checkers::ast::Checker; /// type ListOfInt = list[int] /// ``` #[violation] -pub struct TypeAliasAnnotation { +pub struct NonPEP695TypeAlias { name: String, } -impl Violation for TypeAliasAnnotation { +impl Violation for NonPEP695TypeAlias { const AUTOFIX: AutofixKind = AutofixKind::Always; #[derive_message_formats] fn message(&self) -> String { - let TypeAliasAnnotation { name } = self; - format!("Type alias `{name}` uses `TypeAlias` annotation instead of the `type` keyword.") + let NonPEP695TypeAlias { name } = self; + format!("Type alias `{name}` uses `TypeAlias` annotation instead of the `type` keyword") } fn autofix_title(&self) -> Option { - Some("Use the `type` keyword instead".to_string()) + Some("Replace with the `type` keyword".to_string()) } } -/// RUF017 -pub(crate) fn type_alias_annotation(checker: &mut Checker, stmt: &StmtAnnAssign) { +/// UP100 +pub(crate) fn non_pep695_type_alias(checker: &mut Checker, stmt: &StmtAnnAssign) { let StmtAnnAssign { target, annotation, @@ -71,9 +71,9 @@ pub(crate) fn type_alias_annotation(checker: &mut Checker, stmt: &StmtAnnAssign) return; }; - // todo(zanie): We should check for generic type variables used in the value and define them + // TODO(zanie): We should check for generic type variables used in the value and define them // as type params instead - let mut diagnostic = Diagnostic::new(TypeAliasAnnotation { name: name.clone() }, stmt.range()); + let mut diagnostic = Diagnostic::new(NonPEP695TypeAlias { name: name.clone() }, stmt.range()); if checker.patch(diagnostic.kind.rule()) { diagnostic.set_fix(Fix::automatic(Edit::range_replacement( checker.generator().stmt(&Stmt::from(StmtTypeAlias { diff --git a/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__non_pep695_type_alias_not_applied_py311.snap b/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__non_pep695_type_alias_not_applied_py311.snap new file mode 100644 index 0000000000000..870ad3bf5d625 --- /dev/null +++ b/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__non_pep695_type_alias_not_applied_py311.snap @@ -0,0 +1,4 @@ +--- +source: crates/ruff/src/rules/pyupgrade/mod.rs +--- + diff --git a/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__non_pep695_type_alias_py312.snap b/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__non_pep695_type_alias_py312.snap new file mode 100644 index 0000000000000..b0e5752888cb9 --- /dev/null +++ b/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__non_pep695_type_alias_py312.snap @@ -0,0 +1,61 @@ +--- +source: crates/ruff/src/rules/pyupgrade/mod.rs +--- +UP100.py:5:1: UP100 [*] Type alias `x` uses `TypeAlias` annotation instead of the `type` keyword + | +4 | # UP100 +5 | x: typing.TypeAlias = int + | ^^^^^^^^^^^^^^^^^^^^^^^^^ UP100 +6 | x: TypeAlias = int + | + = help: Replace with the `type` keyword + +ℹ Fix +2 2 | from typing import TypeAlias +3 3 | +4 4 | # UP100 +5 |-x: typing.TypeAlias = int + 5 |+type x = int +6 6 | x: TypeAlias = int +7 7 | +8 8 | + +UP100.py:6:1: UP100 [*] Type alias `x` uses `TypeAlias` annotation instead of the `type` keyword + | +4 | # UP100 +5 | x: typing.TypeAlias = int +6 | x: TypeAlias = int + | ^^^^^^^^^^^^^^^^^^ UP100 + | + = help: Replace with the `type` keyword + +ℹ Fix +3 3 | +4 4 | # UP100 +5 5 | x: typing.TypeAlias = int +6 |-x: TypeAlias = int + 6 |+type x = int +7 7 | +8 8 | +9 9 | # UP100 with generics (todo) + +UP100.py:11:1: UP100 [*] Type alias `x` uses `TypeAlias` annotation instead of the `type` keyword + | + 9 | # UP100 with generics (todo) +10 | T = typing.TypeVar["T"] +11 | x: typing.TypeAlias = list[T] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP100 + | + = help: Replace with the `type` keyword + +ℹ Fix +8 8 | +9 9 | # UP100 with generics (todo) +10 10 | T = typing.TypeVar["T"] +11 |-x: typing.TypeAlias = list[T] + 11 |+type x = list[T] +12 12 | +13 13 | +14 14 | # OK + + diff --git a/crates/ruff/src/rules/ruff/mod.rs b/crates/ruff/src/rules/ruff/mod.rs index 98b2cc5133fbf..42350547abd15 100644 --- a/crates/ruff/src/rules/ruff/mod.rs +++ b/crates/ruff/src/rules/ruff/mod.rs @@ -36,7 +36,6 @@ mod tests { Path::new("RUF015.py") )] #[test_case(Rule::InvalidIndexType, Path::new("RUF016.py"))] - #[test_case(Rule::TypeAliasAnnotation, Path::new("RUF017.py"))] #[cfg_attr( feature = "unreachable-code", test_case(Rule::UnreachableCode, Path::new("RUF014.py")) diff --git a/crates/ruff/src/rules/ruff/rules/mod.rs b/crates/ruff/src/rules/ruff/rules/mod.rs index 2db41a251b575..e4d39feefd825 100644 --- a/crates/ruff/src/rules/ruff/rules/mod.rs +++ b/crates/ruff/src/rules/ruff/rules/mod.rs @@ -10,7 +10,6 @@ pub(crate) use mutable_class_default::*; pub(crate) use mutable_dataclass_default::*; pub(crate) use pairwise_over_zipped::*; pub(crate) use static_key_dict_comprehension::*; -pub(crate) use type_alias_annotation::*; pub(crate) use unnecessary_iterable_allocation_for_first_element::*; #[cfg(feature = "unreachable-code")] pub(crate) use unreachable::*; @@ -30,7 +29,6 @@ mod mutable_class_default; mod mutable_dataclass_default; mod pairwise_over_zipped; mod static_key_dict_comprehension; -mod type_alias_annotation; mod unnecessary_iterable_allocation_for_first_element; #[cfg(feature = "unreachable-code")] pub(crate) mod unreachable; diff --git a/crates/ruff/src/rules/ruff/snapshots/ruff__rules__ruff__tests__RUF017_RUF017.py.snap b/crates/ruff/src/rules/ruff/snapshots/ruff__rules__ruff__tests__RUF017_RUF017.py.snap deleted file mode 100644 index 5ac88c73a5bcf..0000000000000 --- a/crates/ruff/src/rules/ruff/snapshots/ruff__rules__ruff__tests__RUF017_RUF017.py.snap +++ /dev/null @@ -1,37 +0,0 @@ ---- -source: crates/ruff/src/rules/ruff/mod.rs ---- -RUF017.py:4:1: RUF017 [*] Type alias `x` uses `TypeAlias` annotation instead of the `type` keyword. - | -2 | from typing import TypeAlias -3 | -4 | x: typing.TypeAlias = int - | ^^^^^^^^^^^^^^^^^^^^^^^^^ RUF017 -5 | x: TypeAlias = int - | - = help: Use the `type` keyword instead - -ℹ Fix -1 1 | import typing -2 2 | from typing import TypeAlias -3 3 | -4 |-x: typing.TypeAlias = int - 4 |+type x = int -5 5 | x: TypeAlias = int - -RUF017.py:5:1: RUF017 [*] Type alias `x` uses `TypeAlias` annotation instead of the `type` keyword. - | -4 | x: typing.TypeAlias = int -5 | x: TypeAlias = int - | ^^^^^^^^^^^^^^^^^^ RUF017 - | - = help: Use the `type` keyword instead - -ℹ Fix -2 2 | from typing import TypeAlias -3 3 | -4 4 | x: typing.TypeAlias = int -5 |-x: TypeAlias = int - 5 |+type x = int - - diff --git a/crates/ruff_python_formatter/tests/snapshots/format@expression__boolean_operation.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@expression__boolean_operation.py.snap index 246483692811f..979f6fb80509d 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@expression__boolean_operation.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@expression__boolean_operation.py.snap @@ -68,17 +68,6 @@ if ( and [dddddddddddddd, eeeeeeeeee, fffffffffffffff] ): pass - -# Regression test for https://github.com/astral-sh/ruff/issues/6068 -if not ( - isinstance(aaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbb) or numpy and isinstance(ccccccccccc, dddddd) -): - pass - -if not ( - isinstance(aaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbb) and numpy or isinstance(ccccccccccc, dddddd) -): - pass ``` ## Output @@ -147,19 +136,6 @@ if ( and [dddddddddddddd, eeeeeeeeee, fffffffffffffff] ): pass - -# Regression test for https://github.com/astral-sh/ruff/issues/6068 -if not ( - isinstance(aaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbb) - or numpy and isinstance(ccccccccccc, dddddd) -): - pass - -if not ( - isinstance(aaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbb) and numpy - or isinstance(ccccccccccc, dddddd) -): - pass ``` diff --git a/ruff.schema.json b/ruff.schema.json index f419e9454dded..ba1148a297ed9 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -2453,7 +2453,6 @@ "RUF013", "RUF015", "RUF016", - "RUF017", "RUF1", "RUF10", "RUF100", @@ -2667,6 +2666,9 @@ "UP037", "UP038", "UP039", + "UP1", + "UP10", + "UP100", "W", "W1", "W19", From cd43b4601335039ab90498223f2466874dacc57a Mon Sep 17 00:00:00 2001 From: Zanie Date: Thu, 3 Aug 2023 10:18:54 -0500 Subject: [PATCH 3/7] Use UP040 instead of UP100 --- .../fixtures/pyupgrade/{UP100.py => UP040.py} | 4 ++-- crates/ruff/src/rules/pyupgrade/mod.rs | 4 ++-- .../pyupgrade/rules/use_pep695_type_alias.rs | 2 +- ...e__tests__non_pep695_type_alias_py312.snap | 20 +++++++++---------- ruff.schema.json | 5 ++--- 5 files changed, 17 insertions(+), 18 deletions(-) rename crates/ruff/resources/test/fixtures/pyupgrade/{UP100.py => UP040.py} (82%) diff --git a/crates/ruff/resources/test/fixtures/pyupgrade/UP100.py b/crates/ruff/resources/test/fixtures/pyupgrade/UP040.py similarity index 82% rename from crates/ruff/resources/test/fixtures/pyupgrade/UP100.py rename to crates/ruff/resources/test/fixtures/pyupgrade/UP040.py index 72bc9f565f4ef..69854a8af75f4 100644 --- a/crates/ruff/resources/test/fixtures/pyupgrade/UP100.py +++ b/crates/ruff/resources/test/fixtures/pyupgrade/UP040.py @@ -1,12 +1,12 @@ import typing from typing import TypeAlias -# UP100 +# UP040 x: typing.TypeAlias = int x: TypeAlias = int -# UP100 with generics (todo) +# UP040 with generics (todo) T = typing.TypeVar["T"] x: typing.TypeAlias = list[T] diff --git a/crates/ruff/src/rules/pyupgrade/mod.rs b/crates/ruff/src/rules/pyupgrade/mod.rs index 0d5360bfc87b3..7ffeb2b1165ff 100644 --- a/crates/ruff/src/rules/pyupgrade/mod.rs +++ b/crates/ruff/src/rules/pyupgrade/mod.rs @@ -91,7 +91,7 @@ mod tests { #[test] fn non_pep695_type_alias_not_applied_py311() -> Result<()> { let diagnostics = test_path( - Path::new("pyupgrade/UP100.py"), + Path::new("pyupgrade/UP040.py"), &settings::Settings { target_version: PythonVersion::Py311, ..settings::Settings::for_rule(Rule::NonPEP695TypeAlias) @@ -104,7 +104,7 @@ mod tests { #[test] fn non_pep695_type_alias_py312() -> Result<()> { let diagnostics = test_path( - Path::new("pyupgrade/UP100.py"), + Path::new("pyupgrade/UP040.py"), &settings::Settings { target_version: PythonVersion::Py312, ..settings::Settings::for_rule(Rule::NonPEP695TypeAlias) diff --git a/crates/ruff/src/rules/pyupgrade/rules/use_pep695_type_alias.rs b/crates/ruff/src/rules/pyupgrade/rules/use_pep695_type_alias.rs index 1aa2e3a0b5f6d..b42391a9b732c 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/use_pep695_type_alias.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/use_pep695_type_alias.rs @@ -42,7 +42,7 @@ impl Violation for NonPEP695TypeAlias { } } -/// UP100 +/// UP040 pub(crate) fn non_pep695_type_alias(checker: &mut Checker, stmt: &StmtAnnAssign) { let StmtAnnAssign { target, diff --git a/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__non_pep695_type_alias_py312.snap b/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__non_pep695_type_alias_py312.snap index b0e5752888cb9..87ddbb1533bf3 100644 --- a/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__non_pep695_type_alias_py312.snap +++ b/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__non_pep695_type_alias_py312.snap @@ -1,9 +1,9 @@ --- source: crates/ruff/src/rules/pyupgrade/mod.rs --- -UP100.py:5:1: UP100 [*] Type alias `x` uses `TypeAlias` annotation instead of the `type` keyword +UP040.py:5:1: UP100 [*] Type alias `x` uses `TypeAlias` annotation instead of the `type` keyword | -4 | # UP100 +4 | # UP040 5 | x: typing.TypeAlias = int | ^^^^^^^^^^^^^^^^^^^^^^^^^ UP100 6 | x: TypeAlias = int @@ -13,16 +13,16 @@ UP100.py:5:1: UP100 [*] Type alias `x` uses `TypeAlias` annotation instead of th ℹ Fix 2 2 | from typing import TypeAlias 3 3 | -4 4 | # UP100 +4 4 | # UP040 5 |-x: typing.TypeAlias = int 5 |+type x = int 6 6 | x: TypeAlias = int 7 7 | 8 8 | -UP100.py:6:1: UP100 [*] Type alias `x` uses `TypeAlias` annotation instead of the `type` keyword +UP040.py:6:1: UP100 [*] Type alias `x` uses `TypeAlias` annotation instead of the `type` keyword | -4 | # UP100 +4 | # UP040 5 | x: typing.TypeAlias = int 6 | x: TypeAlias = int | ^^^^^^^^^^^^^^^^^^ UP100 @@ -31,17 +31,17 @@ UP100.py:6:1: UP100 [*] Type alias `x` uses `TypeAlias` annotation instead of th ℹ Fix 3 3 | -4 4 | # UP100 +4 4 | # UP040 5 5 | x: typing.TypeAlias = int 6 |-x: TypeAlias = int 6 |+type x = int 7 7 | 8 8 | -9 9 | # UP100 with generics (todo) +9 9 | # UP040 with generics (todo) -UP100.py:11:1: UP100 [*] Type alias `x` uses `TypeAlias` annotation instead of the `type` keyword +UP040.py:11:1: UP100 [*] Type alias `x` uses `TypeAlias` annotation instead of the `type` keyword | - 9 | # UP100 with generics (todo) + 9 | # UP040 with generics (todo) 10 | T = typing.TypeVar["T"] 11 | x: typing.TypeAlias = list[T] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP100 @@ -50,7 +50,7 @@ UP100.py:11:1: UP100 [*] Type alias `x` uses `TypeAlias` annotation instead of t ℹ Fix 8 8 | -9 9 | # UP100 with generics (todo) +9 9 | # UP040 with generics (todo) 10 10 | T = typing.TypeVar["T"] 11 |-x: typing.TypeAlias = list[T] 11 |+type x = list[T] diff --git a/ruff.schema.json b/ruff.schema.json index ba1148a297ed9..12e8dedc271d6 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -2666,9 +2666,8 @@ "UP037", "UP038", "UP039", - "UP1", - "UP10", - "UP100", + "UP04", + "UP040", "W", "W1", "W19", From c37a57352e88a193042d8ba5f7fe7faa5cdf4dbf Mon Sep 17 00:00:00 2001 From: Zanie Date: Thu, 3 Aug 2023 10:39:21 -0500 Subject: [PATCH 4/7] Add to known parse errors --- scripts/check_docs_formatted.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/check_docs_formatted.py b/scripts/check_docs_formatted.py index c18d7a86c91b5..fd2894bfbefd9 100755 --- a/scripts/check_docs_formatted.py +++ b/scripts/check_docs_formatted.py @@ -89,6 +89,7 @@ "tab-before-operator", "trailing-whitespace", "unexpected-indentation", + "non-pep695-type-alias", # requires Python 3.12 ] From fa2afe53d673de4a79e396dcd6d588c89371175a Mon Sep 17 00:00:00 2001 From: Zanie Date: Thu, 3 Aug 2023 10:41:12 -0500 Subject: [PATCH 5/7] Fix registered code --- crates/ruff/src/codes.rs | 2 +- ...yupgrade__tests__non_pep695_type_alias_py312.snap | 12 ++++++------ ruff.schema.json | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/ruff/src/codes.rs b/crates/ruff/src/codes.rs index a581e26ccf532..8a246d42427a2 100644 --- a/crates/ruff/src/codes.rs +++ b/crates/ruff/src/codes.rs @@ -438,7 +438,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> { (Pyupgrade, "037") => (RuleGroup::Unspecified, rules::pyupgrade::rules::QuotedAnnotation), (Pyupgrade, "038") => (RuleGroup::Unspecified, rules::pyupgrade::rules::NonPEP604Isinstance), (Pyupgrade, "039") => (RuleGroup::Unspecified, rules::pyupgrade::rules::UnnecessaryClassParentheses), - (Pyupgrade, "100") => (RuleGroup::Unspecified, rules::pyupgrade::rules::NonPEP695TypeAlias), + (Pyupgrade, "040") => (RuleGroup::Unspecified, rules::pyupgrade::rules::NonPEP695TypeAlias), // pydocstyle (Pydocstyle, "100") => (RuleGroup::Unspecified, rules::pydocstyle::rules::UndocumentedPublicModule), diff --git a/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__non_pep695_type_alias_py312.snap b/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__non_pep695_type_alias_py312.snap index 87ddbb1533bf3..aa5a815e54cff 100644 --- a/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__non_pep695_type_alias_py312.snap +++ b/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__non_pep695_type_alias_py312.snap @@ -1,11 +1,11 @@ --- source: crates/ruff/src/rules/pyupgrade/mod.rs --- -UP040.py:5:1: UP100 [*] Type alias `x` uses `TypeAlias` annotation instead of the `type` keyword +UP040.py:5:1: UP040 [*] Type alias `x` uses `TypeAlias` annotation instead of the `type` keyword | 4 | # UP040 5 | x: typing.TypeAlias = int - | ^^^^^^^^^^^^^^^^^^^^^^^^^ UP100 + | ^^^^^^^^^^^^^^^^^^^^^^^^^ UP040 6 | x: TypeAlias = int | = help: Replace with the `type` keyword @@ -20,12 +20,12 @@ UP040.py:5:1: UP100 [*] Type alias `x` uses `TypeAlias` annotation instead of th 7 7 | 8 8 | -UP040.py:6:1: UP100 [*] Type alias `x` uses `TypeAlias` annotation instead of the `type` keyword +UP040.py:6:1: UP040 [*] Type alias `x` uses `TypeAlias` annotation instead of the `type` keyword | 4 | # UP040 5 | x: typing.TypeAlias = int 6 | x: TypeAlias = int - | ^^^^^^^^^^^^^^^^^^ UP100 + | ^^^^^^^^^^^^^^^^^^ UP040 | = help: Replace with the `type` keyword @@ -39,12 +39,12 @@ UP040.py:6:1: UP100 [*] Type alias `x` uses `TypeAlias` annotation instead of th 8 8 | 9 9 | # UP040 with generics (todo) -UP040.py:11:1: UP100 [*] Type alias `x` uses `TypeAlias` annotation instead of the `type` keyword +UP040.py:11:1: UP040 [*] Type alias `x` uses `TypeAlias` annotation instead of the `type` keyword | 9 | # UP040 with generics (todo) 10 | T = typing.TypeVar["T"] 11 | x: typing.TypeAlias = list[T] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP100 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP040 | = help: Replace with the `type` keyword diff --git a/ruff.schema.json b/ruff.schema.json index 12e8dedc271d6..15a0e5a35a60f 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -2744,4 +2744,4 @@ "type": "string" } } -} +} \ No newline at end of file From e4ca014422f6757f575f4408a438267fec3042b6 Mon Sep 17 00:00:00 2001 From: Zanie Date: Thu, 3 Aug 2023 11:02:35 -0500 Subject: [PATCH 6/7] Tweak message --- .../ruff/src/rules/pyupgrade/rules/use_pep695_type_alias.rs | 2 +- ...ules__pyupgrade__tests__non_pep695_type_alias_py312.snap | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/ruff/src/rules/pyupgrade/rules/use_pep695_type_alias.rs b/crates/ruff/src/rules/pyupgrade/rules/use_pep695_type_alias.rs index b42391a9b732c..64d00f6a80cf9 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/use_pep695_type_alias.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/use_pep695_type_alias.rs @@ -38,7 +38,7 @@ impl Violation for NonPEP695TypeAlias { } fn autofix_title(&self) -> Option { - Some("Replace with the `type` keyword".to_string()) + Some("Use the `type` keyword".to_string()) } } diff --git a/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__non_pep695_type_alias_py312.snap b/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__non_pep695_type_alias_py312.snap index aa5a815e54cff..c46a4b8879b8f 100644 --- a/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__non_pep695_type_alias_py312.snap +++ b/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__non_pep695_type_alias_py312.snap @@ -8,7 +8,7 @@ UP040.py:5:1: UP040 [*] Type alias `x` uses `TypeAlias` annotation instead of th | ^^^^^^^^^^^^^^^^^^^^^^^^^ UP040 6 | x: TypeAlias = int | - = help: Replace with the `type` keyword + = help: Use the `type` keyword ℹ Fix 2 2 | from typing import TypeAlias @@ -27,7 +27,7 @@ UP040.py:6:1: UP040 [*] Type alias `x` uses `TypeAlias` annotation instead of th 6 | x: TypeAlias = int | ^^^^^^^^^^^^^^^^^^ UP040 | - = help: Replace with the `type` keyword + = help: Use the `type` keyword ℹ Fix 3 3 | @@ -46,7 +46,7 @@ UP040.py:11:1: UP040 [*] Type alias `x` uses `TypeAlias` annotation instead of t 11 | x: typing.TypeAlias = list[T] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP040 | - = help: Replace with the `type` keyword + = help: Use the `type` keyword ℹ Fix 8 8 | From 2dda9f2bf6ec49d0c58efa0fbcc9872a8c7110c1 Mon Sep 17 00:00:00 2001 From: Zanie Date: Thu, 3 Aug 2023 11:03:11 -0500 Subject: [PATCH 7/7] Sort `KNOWN_PARSE_ERRORS` --- scripts/check_docs_formatted.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/check_docs_formatted.py b/scripts/check_docs_formatted.py index fd2894bfbefd9..a60c992de6102 100755 --- a/scripts/check_docs_formatted.py +++ b/scripts/check_docs_formatted.py @@ -82,6 +82,7 @@ "missing-newline-at-end-of-file", "mixed-spaces-and-tabs", "no-indented-block", + "non-pep695-type-alias", # requires Python 3.12 "tab-after-comma", "tab-after-keyword", "tab-after-operator", @@ -89,7 +90,6 @@ "tab-before-operator", "trailing-whitespace", "unexpected-indentation", - "non-pep695-type-alias", # requires Python 3.12 ]