mirror of https://github.com/astral-sh/ruff
Collect preview lint behaviors in separate module (#17646)
This PR collects all behavior gated under preview into a new module `ruff_linter::preview` that exposes functions like `is_my_new_feature_enabled` - just as is done in the formatter crate.
This commit is contained in:
parent
1ad5015e19
commit
152a0b6585
|
|
@ -65,6 +65,7 @@ use crate::docstrings::extraction::ExtractionTarget;
|
|||
use crate::importer::{ImportRequest, Importer, ResolutionError};
|
||||
use crate::noqa::NoqaMapping;
|
||||
use crate::package::PackageRoot;
|
||||
use crate::preview::{is_semantic_errors_enabled, is_undefined_export_in_dunder_init_enabled};
|
||||
use crate::registry::Rule;
|
||||
use crate::rules::pyflakes::rules::{
|
||||
LateFutureImport, ReturnOutsideFunction, YieldOutsideFunction,
|
||||
|
|
@ -618,7 +619,7 @@ impl SemanticSyntaxContext for Checker<'_> {
|
|||
| SemanticSyntaxErrorKind::AsyncComprehensionInSyncComprehension(_)
|
||||
| SemanticSyntaxErrorKind::DuplicateParameter(_)
|
||||
| SemanticSyntaxErrorKind::NonlocalDeclarationAtModuleLevel => {
|
||||
if self.settings.preview.is_enabled() {
|
||||
if is_semantic_errors_enabled(self.settings) {
|
||||
self.semantic_errors.borrow_mut().push(error);
|
||||
}
|
||||
}
|
||||
|
|
@ -2827,7 +2828,7 @@ impl<'a> Checker<'a> {
|
|||
}
|
||||
} else {
|
||||
if self.enabled(Rule::UndefinedExport) {
|
||||
if self.settings.preview.is_enabled()
|
||||
if is_undefined_export_in_dunder_init_enabled(self.settings)
|
||||
|| !self.path.ends_with("__init__.py")
|
||||
{
|
||||
self.diagnostics.get_mut().push(
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use ruff_python_ast::PythonVersion;
|
|||
use ruff_python_trivia::CommentRanges;
|
||||
|
||||
use crate::package::PackageRoot;
|
||||
use crate::preview::is_allow_nested_roots_enabled;
|
||||
use crate::registry::Rule;
|
||||
use crate::rules::flake8_builtins::rules::stdlib_module_shadowing;
|
||||
use crate::rules::flake8_no_pep420::rules::implicit_namespace_package;
|
||||
|
|
@ -24,6 +25,7 @@ pub(crate) fn check_file_path(
|
|||
|
||||
// flake8-no-pep420
|
||||
if settings.rules.enabled(Rule::ImplicitNamespacePackage) {
|
||||
let allow_nested_roots = is_allow_nested_roots_enabled(settings);
|
||||
if let Some(diagnostic) = implicit_namespace_package(
|
||||
path,
|
||||
package,
|
||||
|
|
@ -31,7 +33,7 @@ pub(crate) fn check_file_path(
|
|||
comment_ranges,
|
||||
&settings.project_root,
|
||||
&settings.src,
|
||||
settings.preview,
|
||||
allow_nested_roots,
|
||||
) {
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ use crate::fix::edits::delete_comment;
|
|||
use crate::noqa::{
|
||||
Code, Directive, FileExemption, FileNoqaDirectives, NoqaDirectives, NoqaMapping,
|
||||
};
|
||||
use crate::preview::is_check_file_level_directives_enabled;
|
||||
use crate::registry::{AsRule, Rule, RuleSet};
|
||||
use crate::rule_redirects::get_redirect_target;
|
||||
use crate::rules::pygrep_hooks;
|
||||
|
|
@ -110,7 +111,7 @@ pub(crate) fn check_noqa(
|
|||
&& !exemption.includes(Rule::UnusedNOQA)
|
||||
&& !per_file_ignores.contains(Rule::UnusedNOQA)
|
||||
{
|
||||
let directives: Vec<_> = if settings.preview.is_enabled() {
|
||||
let directives: Vec<_> = if is_check_file_level_directives_enabled(settings) {
|
||||
noqa_directives
|
||||
.lines()
|
||||
.iter()
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ pub mod message;
|
|||
mod noqa;
|
||||
pub mod package;
|
||||
pub mod packaging;
|
||||
pub mod preview;
|
||||
pub mod pyproject_toml;
|
||||
pub mod registry;
|
||||
mod renamer;
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ use crate::fix::{fix_file, FixResult};
|
|||
use crate::message::Message;
|
||||
use crate::noqa::add_noqa;
|
||||
use crate::package::PackageRoot;
|
||||
use crate::preview::is_unsupported_syntax_enabled;
|
||||
use crate::registry::{AsRule, Rule, RuleSet};
|
||||
#[cfg(any(feature = "test-rules", test))]
|
||||
use crate::rules::ruff::rules::test_rules::{self, TestRule, TEST_RULES};
|
||||
|
|
@ -360,7 +361,7 @@ pub fn check_path(
|
|||
}
|
||||
}
|
||||
|
||||
let syntax_errors = if settings.preview.is_enabled() {
|
||||
let syntax_errors = if is_unsupported_syntax_enabled(settings) {
|
||||
parsed.unsupported_syntax_errors()
|
||||
} else {
|
||||
&[]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,118 @@
|
|||
//! Helpers to test if a specific preview style is enabled or not.
|
||||
//!
|
||||
//! The motivation for these functions isn't to avoid code duplication but to ease promoting preview behavior
|
||||
//! to stable. The challenge with directly checking the `preview` attribute of [`LinterSettings`] is that it is unclear
|
||||
//! which specific feature this preview check is for. Having named functions simplifies the promotion:
|
||||
//! Simply delete the function and let Rust tell you which checks you have to remove.
|
||||
|
||||
use crate::settings::LinterSettings;
|
||||
|
||||
// https://github.com/astral-sh/ruff/issues/17412
|
||||
// https://github.com/astral-sh/ruff/issues/11934
|
||||
pub(crate) const fn is_semantic_errors_enabled(settings: &LinterSettings) -> bool {
|
||||
settings.preview.is_enabled()
|
||||
}
|
||||
|
||||
// https://github.com/astral-sh/ruff/pull/16429
|
||||
pub(crate) const fn is_unsupported_syntax_enabled(settings: &LinterSettings) -> bool {
|
||||
settings.preview.is_enabled()
|
||||
}
|
||||
|
||||
// Rule-specific behavior
|
||||
|
||||
// https://github.com/astral-sh/ruff/pull/17136
|
||||
pub(crate) const fn is_shell_injection_only_trusted_input_enabled(
|
||||
settings: &LinterSettings,
|
||||
) -> bool {
|
||||
settings.preview.is_enabled()
|
||||
}
|
||||
|
||||
// https://github.com/astral-sh/ruff/pull/15541
|
||||
pub(crate) const fn is_suspicious_function_reference_enabled(settings: &LinterSettings) -> bool {
|
||||
settings.preview.is_enabled()
|
||||
}
|
||||
|
||||
// https://github.com/astral-sh/ruff/pull/7501
|
||||
pub(crate) const fn is_bool_subtype_of_annotation_enabled(settings: &LinterSettings) -> bool {
|
||||
settings.preview.is_enabled()
|
||||
}
|
||||
|
||||
// https://github.com/astral-sh/ruff/pull/10759
|
||||
pub(crate) const fn is_comprehension_with_min_max_sum_enabled(settings: &LinterSettings) -> bool {
|
||||
settings.preview.is_enabled()
|
||||
}
|
||||
|
||||
// https://github.com/astral-sh/ruff/pull/12657
|
||||
pub(crate) const fn is_check_comprehensions_in_tuple_call_enabled(
|
||||
settings: &LinterSettings,
|
||||
) -> bool {
|
||||
settings.preview.is_enabled()
|
||||
}
|
||||
|
||||
// https://github.com/astral-sh/ruff/issues/15347
|
||||
pub(crate) const fn is_bad_version_info_in_non_stub_enabled(settings: &LinterSettings) -> bool {
|
||||
settings.preview.is_enabled()
|
||||
}
|
||||
|
||||
// https://github.com/astral-sh/ruff/pull/12676
|
||||
pub(crate) const fn is_fix_future_annotations_in_stub_enabled(settings: &LinterSettings) -> bool {
|
||||
settings.preview.is_enabled()
|
||||
}
|
||||
|
||||
// https://github.com/astral-sh/ruff/pull/11074
|
||||
pub(crate) const fn is_only_add_return_none_at_end_enabled(settings: &LinterSettings) -> bool {
|
||||
settings.preview.is_enabled()
|
||||
}
|
||||
|
||||
// https://github.com/astral-sh/ruff/pull/12796
|
||||
pub(crate) const fn is_simplify_ternary_to_binary_enabled(settings: &LinterSettings) -> bool {
|
||||
settings.preview.is_enabled()
|
||||
}
|
||||
|
||||
// https://github.com/astral-sh/ruff/pull/16719
|
||||
pub(crate) const fn is_fix_manual_dict_comprehension_enabled(settings: &LinterSettings) -> bool {
|
||||
settings.preview.is_enabled()
|
||||
}
|
||||
|
||||
// https://github.com/astral-sh/ruff/pull/13919
|
||||
pub(crate) const fn is_fix_manual_list_comprehension_enabled(settings: &LinterSettings) -> bool {
|
||||
settings.preview.is_enabled()
|
||||
}
|
||||
|
||||
// https://github.com/astral-sh/ruff/pull/11436
|
||||
// https://github.com/astral-sh/ruff/pull/11168
|
||||
pub(crate) const fn is_dunder_init_fix_unused_import_enabled(settings: &LinterSettings) -> bool {
|
||||
settings.preview.is_enabled()
|
||||
}
|
||||
|
||||
// https://github.com/astral-sh/ruff/pull/15313
|
||||
pub(crate) const fn is_defer_optional_to_up045_enabled(settings: &LinterSettings) -> bool {
|
||||
settings.preview.is_enabled()
|
||||
}
|
||||
|
||||
// https://github.com/astral-sh/ruff/pull/8473
|
||||
pub(crate) const fn is_unicode_to_unicode_confusables_enabled(settings: &LinterSettings) -> bool {
|
||||
settings.preview.is_enabled()
|
||||
}
|
||||
|
||||
// https://github.com/astral-sh/ruff/pull/17078
|
||||
pub(crate) const fn is_support_slices_in_literal_concatenation_enabled(
|
||||
settings: &LinterSettings,
|
||||
) -> bool {
|
||||
settings.preview.is_enabled()
|
||||
}
|
||||
|
||||
// https://github.com/astral-sh/ruff/pull/11370
|
||||
pub(crate) const fn is_undefined_export_in_dunder_init_enabled(settings: &LinterSettings) -> bool {
|
||||
settings.preview.is_enabled()
|
||||
}
|
||||
|
||||
// https://github.com/astral-sh/ruff/pull/14236
|
||||
pub(crate) const fn is_allow_nested_roots_enabled(settings: &LinterSettings) -> bool {
|
||||
settings.preview.is_enabled()
|
||||
}
|
||||
|
||||
// https://github.com/astral-sh/ruff/pull/17061
|
||||
pub(crate) const fn is_check_file_level_directives_enabled(settings: &LinterSettings) -> bool {
|
||||
settings.preview.is_enabled()
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
//! Checks relating to shell injection.
|
||||
|
||||
use crate::preview::is_shell_injection_only_trusted_input_enabled;
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
||||
use ruff_python_ast::helpers::Truthiness;
|
||||
|
|
@ -324,7 +325,9 @@ pub(crate) fn shell_injection(checker: &Checker, call: &ast::ExprCall) {
|
|||
}
|
||||
// S603
|
||||
_ => {
|
||||
if !is_trusted_input(arg) || checker.settings.preview.is_disabled() {
|
||||
if !is_trusted_input(arg)
|
||||
|| !is_shell_injection_only_trusted_input_enabled(checker.settings)
|
||||
{
|
||||
if checker.enabled(Rule::SubprocessWithoutShellEqualsTrue) {
|
||||
checker.report_diagnostic(Diagnostic::new(
|
||||
SubprocessWithoutShellEqualsTrue,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use ruff_python_ast::{self as ast, Arguments, Decorator, Expr, ExprCall, Operato
|
|||
use ruff_text_size::{Ranged, TextRange};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::preview::is_suspicious_function_reference_enabled;
|
||||
use crate::registry::AsRule;
|
||||
|
||||
/// ## What it does
|
||||
|
|
@ -936,7 +937,7 @@ pub(crate) fn suspicious_function_call(checker: &Checker, call: &ExprCall) {
|
|||
}
|
||||
|
||||
pub(crate) fn suspicious_function_reference(checker: &Checker, func: &Expr) {
|
||||
if checker.settings.preview.is_disabled() {
|
||||
if !is_suspicious_function_reference_enabled(checker.settings) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1210,7 +1211,7 @@ fn suspicious_function(
|
|||
/// S308
|
||||
pub(crate) fn suspicious_function_decorator(checker: &Checker, decorator: &Decorator) {
|
||||
// In preview mode, references are handled collectively by `suspicious_function_reference`
|
||||
if checker.settings.preview.is_disabled() {
|
||||
if !is_suspicious_function_reference_enabled(checker.settings) {
|
||||
suspicious_function(checker, &decorator.expression, None, decorator.range);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use ruff_python_semantic::analyze::visibility;
|
|||
use ruff_python_semantic::SemanticModel;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::preview::is_bool_subtype_of_annotation_enabled;
|
||||
use crate::rules::flake8_boolean_trap::helpers::is_allowed_func_def;
|
||||
|
||||
/// ## What it does
|
||||
|
|
@ -128,7 +129,7 @@ pub(crate) fn boolean_type_hint_positional_argument(
|
|||
let Some(annotation) = parameter.annotation() else {
|
||||
continue;
|
||||
};
|
||||
if checker.settings.preview.is_enabled() {
|
||||
if is_bool_subtype_of_annotation_enabled(checker.settings) {
|
||||
if !match_annotation_to_complex_bool(annotation, checker.semantic()) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use ruff_python_ast::{self as ast, Expr, Keyword};
|
|||
use ruff_text_size::{Ranged, TextSize};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::preview::is_comprehension_with_min_max_sum_enabled;
|
||||
use crate::rules::flake8_comprehensions::fixes;
|
||||
|
||||
/// ## What it does
|
||||
|
|
@ -125,7 +126,7 @@ pub(crate) fn unnecessary_comprehension_in_call(
|
|||
if !(matches!(
|
||||
builtin_function,
|
||||
SupportedBuiltins::Any | SupportedBuiltins::All
|
||||
) || (checker.settings.preview.is_enabled()
|
||||
) || (is_comprehension_with_min_max_sum_enabled(checker.settings)
|
||||
&& matches!(
|
||||
builtin_function,
|
||||
SupportedBuiltins::Sum | SupportedBuiltins::Min | SupportedBuiltins::Max
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use ruff_python_trivia::{SimpleTokenKind, SimpleTokenizer};
|
|||
use ruff_text_size::{Ranged, TextRange, TextSize};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::preview::is_check_comprehensions_in_tuple_call_enabled;
|
||||
use crate::rules::flake8_comprehensions::fixes;
|
||||
|
||||
use super::helpers;
|
||||
|
|
@ -100,7 +101,9 @@ pub(crate) fn unnecessary_literal_within_tuple_call(
|
|||
let argument_kind = match argument {
|
||||
Expr::Tuple(_) => TupleLiteralKind::Tuple,
|
||||
Expr::List(_) => TupleLiteralKind::List,
|
||||
Expr::ListComp(_) if checker.settings.preview.is_enabled() => TupleLiteralKind::ListComp,
|
||||
Expr::ListComp(_) if is_check_comprehensions_in_tuple_call_enabled(checker.settings) => {
|
||||
TupleLiteralKind::ListComp
|
||||
}
|
||||
_ => return,
|
||||
};
|
||||
if !checker.semantic().has_builtin_binding("tuple") {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ use ruff_text_size::{TextRange, TextSize};
|
|||
use crate::comments::shebang::ShebangDirective;
|
||||
use crate::fs;
|
||||
use crate::package::PackageRoot;
|
||||
use crate::settings::types::PreviewMode;
|
||||
use crate::Locator;
|
||||
|
||||
/// ## What it does
|
||||
|
|
@ -60,7 +59,7 @@ pub(crate) fn implicit_namespace_package(
|
|||
comment_ranges: &CommentRanges,
|
||||
project_root: &Path,
|
||||
src: &[PathBuf],
|
||||
preview: PreviewMode,
|
||||
allow_nested_roots: bool,
|
||||
) -> Option<Diagnostic> {
|
||||
if package.is_none()
|
||||
// Ignore non-`.py` files, which don't require an `__init__.py`.
|
||||
|
|
@ -93,7 +92,7 @@ pub(crate) fn implicit_namespace_package(
|
|||
));
|
||||
}
|
||||
|
||||
if preview.is_enabled() {
|
||||
if allow_nested_roots {
|
||||
if let Some(PackageRoot::Nested { path: root }) = package.as_ref() {
|
||||
if path.ends_with("__init__.py") {
|
||||
// Identify the intermediary package that's missing the `__init__.py` file.
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use ruff_macros::{derive_message_formats, ViolationMetadata};
|
|||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::preview::is_bad_version_info_in_non_stub_enabled;
|
||||
use crate::registry::Rule;
|
||||
|
||||
/// ## What it does
|
||||
|
|
@ -140,7 +141,7 @@ pub(crate) fn bad_version_info_comparison(checker: &Checker, test: &Expr, has_el
|
|||
if matches!(op, CmpOp::Lt) {
|
||||
if checker.enabled(Rule::BadVersionInfoOrder)
|
||||
// See https://github.com/astral-sh/ruff/issues/15347
|
||||
&& (checker.source_type.is_stub() || checker.settings.preview.is_enabled())
|
||||
&& (checker.source_type.is_stub() || is_bad_version_info_in_non_stub_enabled(checker.settings))
|
||||
{
|
||||
if has_else_clause {
|
||||
checker.report_diagnostic(Diagnostic::new(BadVersionInfoOrder, test.range()));
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use ruff_python_ast::StmtImportFrom;
|
|||
use ruff_diagnostics::{Diagnostic, Fix, FixAvailability, Violation};
|
||||
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
||||
|
||||
use crate::{checkers::ast::Checker, fix};
|
||||
use crate::{checkers::ast::Checker, fix, preview::is_fix_future_annotations_in_stub_enabled};
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for the presence of the `from __future__ import annotations` import
|
||||
|
|
@ -55,7 +55,7 @@ pub(crate) fn from_future_import(checker: &Checker, target: &StmtImportFrom) {
|
|||
|
||||
let mut diagnostic = Diagnostic::new(FutureAnnotationsInStub, *range);
|
||||
|
||||
if checker.settings.preview.is_enabled() {
|
||||
if is_fix_future_annotations_in_stub_enabled(checker.settings) {
|
||||
let stmt = checker.semantic().current_statement();
|
||||
|
||||
diagnostic.try_set_fix(|| {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ use ruff_text_size::{Ranged, TextRange, TextSize};
|
|||
use crate::checkers::ast::Checker;
|
||||
use crate::fix::edits;
|
||||
use crate::fix::edits::adjust_indentation;
|
||||
use crate::preview::is_only_add_return_none_at_end_enabled;
|
||||
use crate::registry::{AsRule, Rule};
|
||||
use crate::rules::flake8_return::helpers::end_of_last_statement;
|
||||
use crate::Locator;
|
||||
|
|
@ -552,7 +553,7 @@ fn implicit_return(checker: &Checker, function_def: &ast::StmtFunctionDef, stmt:
|
|||
return;
|
||||
}
|
||||
|
||||
if checker.settings.preview.is_enabled() {
|
||||
if is_only_add_return_none_at_end_enabled(checker.settings) {
|
||||
add_return_none(checker, stmt, function_def.range());
|
||||
} else {
|
||||
for implicit_stmt in implicit_stmts {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use ruff_text_size::{Ranged, TextRange};
|
|||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::fix::edits::fits;
|
||||
use crate::preview::is_simplify_ternary_to_binary_enabled;
|
||||
|
||||
/// ## What it does
|
||||
/// Check for `if`-`else`-blocks that can be replaced with a ternary operator.
|
||||
|
|
@ -180,13 +181,14 @@ pub(crate) fn if_else_block_instead_of_if_exp(checker: &Checker, stmt_if: &ast::
|
|||
// - If `test == not body_value` and preview enabled, replace with `target_var = body_value and else_value`
|
||||
// - If `not test == body_value` and preview enabled, replace with `target_var = body_value and else_value`
|
||||
// - Otherwise, replace with `target_var = body_value if test else else_value`
|
||||
let (contents, assignment_kind) =
|
||||
match (checker.settings.preview.is_enabled(), test, body_value) {
|
||||
let (contents, assignment_kind) = match (
|
||||
is_simplify_ternary_to_binary_enabled(checker.settings),
|
||||
test,
|
||||
body_value,
|
||||
) {
|
||||
(true, test_node, body_node)
|
||||
if ComparableExpr::from(test_node) == ComparableExpr::from(body_node)
|
||||
&& !contains_effect(test_node, |id| {
|
||||
checker.semantic().has_builtin_binding(id)
|
||||
}) =>
|
||||
&& !contains_effect(test_node, |id| checker.semantic().has_builtin_binding(id)) =>
|
||||
{
|
||||
let target_var = &body_target;
|
||||
let binary = assignment_binary_or(target_var, body_value, else_value);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use ruff_source_file::LineRanges;
|
|||
use ruff_text_size::{Ranged, TextRange};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::preview::is_fix_manual_dict_comprehension_enabled;
|
||||
use crate::rules::perflint::helpers::{comment_strings_in_range, statement_deletion_range};
|
||||
|
||||
/// ## What it does
|
||||
|
|
@ -229,7 +230,7 @@ pub(crate) fn manual_dict_comprehension(checker: &Checker, for_stmt: &ast::StmtF
|
|||
return;
|
||||
}
|
||||
|
||||
if checker.settings.preview.is_enabled() {
|
||||
if is_fix_manual_dict_comprehension_enabled(checker.settings) {
|
||||
let binding_stmt = binding.statement(checker.semantic());
|
||||
let binding_value = binding_stmt.and_then(|binding_stmt| match binding_stmt {
|
||||
ast::Stmt::AnnAssign(assign) => assign.value.as_deref(),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
use ruff_python_ast::{self as ast, Arguments, Expr};
|
||||
|
||||
use crate::{checkers::ast::Checker, rules::perflint::helpers::statement_deletion_range};
|
||||
use crate::{
|
||||
checkers::ast::Checker, preview::is_fix_manual_list_comprehension_enabled,
|
||||
rules::perflint::helpers::statement_deletion_range,
|
||||
};
|
||||
use anyhow::{anyhow, Result};
|
||||
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
|
||||
|
||||
|
|
@ -335,7 +338,7 @@ pub(crate) fn manual_list_comprehension(checker: &Checker, for_stmt: &ast::StmtF
|
|||
);
|
||||
|
||||
// TODO: once this fix is stabilized, change the rule to always fixable
|
||||
if checker.settings.preview.is_enabled() {
|
||||
if is_fix_manual_list_comprehension_enabled(checker.settings) {
|
||||
diagnostic.try_set_fix(|| {
|
||||
convert_to_list_extend(
|
||||
comprehension_type,
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ use ruff_text_size::{Ranged, TextRange};
|
|||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::fix;
|
||||
use crate::preview::is_dunder_init_fix_unused_import_enabled;
|
||||
use crate::registry::Rule;
|
||||
use crate::rules::{isort, isort::ImportSection, isort::ImportType};
|
||||
|
||||
|
|
@ -352,7 +353,7 @@ pub(crate) fn unused_import(checker: &Checker, scope: &Scope) {
|
|||
|
||||
let in_init = checker.path().ends_with("__init__.py");
|
||||
let fix_init = !checker.settings.ignore_init_module_imports;
|
||||
let preview_mode = checker.settings.preview.is_enabled();
|
||||
let preview_mode = is_dunder_init_fix_unused_import_enabled(checker.settings);
|
||||
let dunder_all_exprs = find_dunder_all_exprs(checker.semantic());
|
||||
|
||||
// Generate a diagnostic for every import, but share fixes across all imports within the same
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use ruff_text_size::Ranged;
|
|||
use crate::checkers::ast::Checker;
|
||||
use crate::codes::Rule;
|
||||
use crate::fix::edits::pad;
|
||||
use crate::settings::types::PreviewMode;
|
||||
use crate::preview::is_defer_optional_to_up045_enabled;
|
||||
|
||||
/// ## What it does
|
||||
/// Check for type annotations that can be rewritten based on [PEP 604] syntax.
|
||||
|
|
@ -150,15 +150,16 @@ pub(crate) fn non_pep604_annotation(
|
|||
|
||||
match operator {
|
||||
Pep604Operator::Optional => {
|
||||
let (rule, diagnostic_kind) = match checker.settings.preview {
|
||||
PreviewMode::Disabled => (
|
||||
Rule::NonPEP604AnnotationUnion,
|
||||
DiagnosticKind::from(NonPEP604AnnotationUnion),
|
||||
),
|
||||
PreviewMode::Enabled => (
|
||||
let (rule, diagnostic_kind) = if is_defer_optional_to_up045_enabled(checker.settings) {
|
||||
(
|
||||
Rule::NonPEP604AnnotationOptional,
|
||||
DiagnosticKind::from(NonPEP604AnnotationOptional),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
Rule::NonPEP604AnnotationUnion,
|
||||
DiagnosticKind::from(NonPEP604AnnotationUnion),
|
||||
)
|
||||
};
|
||||
|
||||
if !checker.enabled(rule) {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use ruff_python_ast::{self as ast, StringLike};
|
|||
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::preview::is_unicode_to_unicode_confusables_enabled;
|
||||
use crate::registry::AsRule;
|
||||
use crate::rules::ruff::rules::confusables::confusable;
|
||||
use crate::rules::ruff::rules::Context;
|
||||
|
|
@ -264,9 +265,9 @@ fn ambiguous_unicode_character(
|
|||
// Check if the boundary character is itself an ambiguous unicode character, in which
|
||||
// case, it's always included as a diagnostic.
|
||||
if !current_char.is_ascii() {
|
||||
if let Some(representant) = confusable(current_char as u32)
|
||||
.filter(|representant| settings.preview.is_enabled() || representant.is_ascii())
|
||||
{
|
||||
if let Some(representant) = confusable(current_char as u32).filter(|representant| {
|
||||
is_unicode_to_unicode_confusables_enabled(settings) || representant.is_ascii()
|
||||
}) {
|
||||
let candidate = Candidate::new(
|
||||
TextSize::try_from(relative_offset).unwrap() + range.start(),
|
||||
current_char,
|
||||
|
|
@ -280,9 +281,9 @@ fn ambiguous_unicode_character(
|
|||
} else if current_char.is_ascii() {
|
||||
// The current word contains at least one ASCII character.
|
||||
word_flags |= WordFlags::ASCII;
|
||||
} else if let Some(representant) = confusable(current_char as u32)
|
||||
.filter(|representant| settings.preview.is_enabled() || representant.is_ascii())
|
||||
{
|
||||
} else if let Some(representant) = confusable(current_char as u32).filter(|representant| {
|
||||
is_unicode_to_unicode_confusables_enabled(settings) || representant.is_ascii()
|
||||
}) {
|
||||
// The current word contains an ambiguous unicode character.
|
||||
word_candidates.push(Candidate::new(
|
||||
TextSize::try_from(relative_offset).unwrap() + range.start(),
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use ruff_text_size::{Ranged, TextRange};
|
|||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::fix::snippet::SourceCodeSnippet;
|
||||
use crate::preview::is_support_slices_in_literal_concatenation_enabled;
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for uses of the `+` operator to concatenate collections.
|
||||
|
|
@ -197,7 +198,8 @@ pub(crate) fn collection_literal_concatenation(checker: &Checker, expr: &Expr) {
|
|||
return;
|
||||
}
|
||||
|
||||
let should_support_slices = checker.settings.preview.is_enabled();
|
||||
let should_support_slices =
|
||||
is_support_slices_in_literal_concatenation_enabled(checker.settings);
|
||||
|
||||
let Some((new_expr, type_)) = concatenate_expressions(expr, should_support_slices) else {
|
||||
return;
|
||||
|
|
|
|||
Loading…
Reference in New Issue