mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-26 20:09:22 +00:00
Implement --extend-fixable
option (#4297)
This commit is contained in:
parent
2e2ba2cb16
commit
15cb21a6f4
7 changed files with 114 additions and 12 deletions
|
@ -32,6 +32,7 @@ pub struct RuleSelection {
|
||||||
pub extend_select: Vec<RuleSelector>,
|
pub extend_select: Vec<RuleSelector>,
|
||||||
pub fixable: Option<Vec<RuleSelector>>,
|
pub fixable: Option<Vec<RuleSelector>>,
|
||||||
pub unfixable: Vec<RuleSelector>,
|
pub unfixable: Vec<RuleSelector>,
|
||||||
|
pub extend_fixable: Vec<RuleSelector>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
|
@ -101,7 +102,13 @@ impl Configuration {
|
||||||
.collect(),
|
.collect(),
|
||||||
extend_select: options.extend_select.unwrap_or_default(),
|
extend_select: options.extend_select.unwrap_or_default(),
|
||||||
fixable: options.fixable,
|
fixable: options.fixable,
|
||||||
unfixable: options.unfixable.unwrap_or_default(),
|
unfixable: options
|
||||||
|
.unfixable
|
||||||
|
.into_iter()
|
||||||
|
.flatten()
|
||||||
|
.chain(options.extend_unfixable.into_iter().flatten())
|
||||||
|
.collect(),
|
||||||
|
extend_fixable: options.extend_fixable.unwrap_or_default(),
|
||||||
}],
|
}],
|
||||||
allowed_confusables: options.allowed_confusables,
|
allowed_confusables: options.allowed_confusables,
|
||||||
builtins: options.builtins,
|
builtins: options.builtins,
|
||||||
|
|
|
@ -258,16 +258,11 @@ impl From<&Configuration> for RuleTable {
|
||||||
// across config files (which otherwise wouldn't be possible since ruff
|
// across config files (which otherwise wouldn't be possible since ruff
|
||||||
// only has `extended` but no `extended-by`).
|
// only has `extended` but no `extended-by`).
|
||||||
let mut carryover_ignores: Option<&[RuleSelector]> = None;
|
let mut carryover_ignores: Option<&[RuleSelector]> = None;
|
||||||
|
let mut carryover_unfixables: Option<&[RuleSelector]> = None;
|
||||||
|
|
||||||
let mut redirects = FxHashMap::default();
|
let mut redirects = FxHashMap::default();
|
||||||
|
|
||||||
for selection in &config.rule_selections {
|
for selection in &config.rule_selections {
|
||||||
// We do not have an extend-fixable option, so fixable and unfixable
|
|
||||||
// selectors can simply be applied directly to fixable_set.
|
|
||||||
if selection.fixable.is_some() {
|
|
||||||
fixable_set.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// If a selection only specifies extend-select we cannot directly
|
// If a selection only specifies extend-select we cannot directly
|
||||||
// apply its rule selectors to the select_set because we firstly have
|
// apply its rule selectors to the select_set because we firstly have
|
||||||
// to resolve the effectively selected rules within the current rule selection
|
// to resolve the effectively selected rules within the current rule selection
|
||||||
|
@ -276,10 +271,13 @@ impl From<&Configuration> for RuleTable {
|
||||||
// We do this via the following HashMap where the bool indicates
|
// We do this via the following HashMap where the bool indicates
|
||||||
// whether to enable or disable the given rule.
|
// whether to enable or disable the given rule.
|
||||||
let mut select_map_updates: FxHashMap<Rule, bool> = FxHashMap::default();
|
let mut select_map_updates: FxHashMap<Rule, bool> = FxHashMap::default();
|
||||||
|
let mut fixable_map_updates: FxHashMap<Rule, bool> = FxHashMap::default();
|
||||||
|
|
||||||
let carriedover_ignores = carryover_ignores.take();
|
let carriedover_ignores = carryover_ignores.take();
|
||||||
|
let carriedover_unfixables = carryover_unfixables.take();
|
||||||
|
|
||||||
for spec in Specificity::iter() {
|
for spec in Specificity::iter() {
|
||||||
|
// Iterate over rule selectors in order of specificity.
|
||||||
for selector in selection
|
for selector in selection
|
||||||
.select
|
.select
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -301,17 +299,26 @@ impl From<&Configuration> for RuleTable {
|
||||||
select_map_updates.insert(rule, false);
|
select_map_updates.insert(rule, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(fixable) = &selection.fixable {
|
// Apply the same logic to `fixable` and `unfixable`.
|
||||||
fixable_set
|
for selector in selection
|
||||||
.extend(fixable.iter().filter(|s| s.specificity() == spec).flatten());
|
.fixable
|
||||||
|
.iter()
|
||||||
|
.flatten()
|
||||||
|
.chain(selection.extend_fixable.iter())
|
||||||
|
.filter(|s| s.specificity() == spec)
|
||||||
|
{
|
||||||
|
for rule in selector {
|
||||||
|
fixable_map_updates.insert(rule, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for selector in selection
|
for selector in selection
|
||||||
.unfixable
|
.unfixable
|
||||||
.iter()
|
.iter()
|
||||||
|
.chain(carriedover_unfixables.into_iter().flatten())
|
||||||
.filter(|s| s.specificity() == spec)
|
.filter(|s| s.specificity() == spec)
|
||||||
{
|
{
|
||||||
for rule in selector {
|
for rule in selector {
|
||||||
fixable_set.remove(rule);
|
fixable_map_updates.insert(rule, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -341,6 +348,29 @@ impl From<&Configuration> for RuleTable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply the same logic to `fixable` and `unfixable`.
|
||||||
|
if let Some(fixable) = &selection.fixable {
|
||||||
|
fixable_set = fixable_map_updates
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|(rule, enabled)| enabled.then_some(rule))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
if fixable.is_empty()
|
||||||
|
&& selection.extend_fixable.is_empty()
|
||||||
|
&& !selection.unfixable.is_empty()
|
||||||
|
{
|
||||||
|
carryover_unfixables = Some(&selection.unfixable);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (rule, enabled) in fixable_map_updates {
|
||||||
|
if enabled {
|
||||||
|
fixable_set.insert(rule);
|
||||||
|
} else {
|
||||||
|
fixable_set.remove(rule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// We insert redirects into the hashmap so that we
|
// We insert redirects into the hashmap so that we
|
||||||
// can warn the users about remapped rule codes.
|
// can warn the users about remapped rule codes.
|
||||||
for selector in selection
|
for selector in selection
|
||||||
|
@ -351,6 +381,7 @@ impl From<&Configuration> for RuleTable {
|
||||||
.chain(selection.ignore.iter())
|
.chain(selection.ignore.iter())
|
||||||
.chain(selection.extend_select.iter())
|
.chain(selection.extend_select.iter())
|
||||||
.chain(selection.unfixable.iter())
|
.chain(selection.unfixable.iter())
|
||||||
|
.chain(selection.extend_fixable.iter())
|
||||||
{
|
{
|
||||||
if let RuleSelector::Prefix {
|
if let RuleSelector::Prefix {
|
||||||
prefix,
|
prefix,
|
||||||
|
|
|
@ -175,6 +175,24 @@ pub struct Options {
|
||||||
/// A list of rule codes or prefixes to enable, in addition to those
|
/// A list of rule codes or prefixes to enable, in addition to those
|
||||||
/// specified by `select`.
|
/// specified by `select`.
|
||||||
pub extend_select: Option<Vec<RuleSelector>>,
|
pub extend_select: Option<Vec<RuleSelector>>,
|
||||||
|
#[option(
|
||||||
|
default = r#"[]"#,
|
||||||
|
value_type = "list[RuleSelector]",
|
||||||
|
example = r#"
|
||||||
|
# Enable autofix for flake8-bugbear (`B`), on top of any rules specified by `fixable`.
|
||||||
|
extend-fixable = ["B"]
|
||||||
|
"#
|
||||||
|
)]
|
||||||
|
/// A list of rule codes or prefixes to consider autofixable, in addition to those
|
||||||
|
/// specified by `fixable`.
|
||||||
|
pub extend_fixable: Option<Vec<RuleSelector>>,
|
||||||
|
/// A list of rule codes or prefixes to consider non-auto-fixable, in addition to those
|
||||||
|
/// specified by `unfixable`.
|
||||||
|
///
|
||||||
|
/// This option has been **deprecated** in favor of `unfixable` since its usage is now
|
||||||
|
/// interchangeable with `unfixable`.
|
||||||
|
#[schemars(skip)]
|
||||||
|
pub extend_unfixable: Option<Vec<RuleSelector>>,
|
||||||
#[option(
|
#[option(
|
||||||
default = "[]",
|
default = "[]",
|
||||||
value_type = "list[str]",
|
value_type = "list[str]",
|
||||||
|
|
|
@ -189,6 +189,27 @@ pub struct CheckArgs {
|
||||||
hide_possible_values = true
|
hide_possible_values = true
|
||||||
)]
|
)]
|
||||||
pub unfixable: Option<Vec<RuleSelector>>,
|
pub unfixable: Option<Vec<RuleSelector>>,
|
||||||
|
/// Like --fixable, but adds additional rule codes on top of the fixable
|
||||||
|
/// ones.
|
||||||
|
#[arg(
|
||||||
|
long,
|
||||||
|
value_delimiter = ',',
|
||||||
|
value_name = "RULE_CODE",
|
||||||
|
value_parser = parse_rule_selector,
|
||||||
|
help_heading = "Rule selection",
|
||||||
|
hide_possible_values = true
|
||||||
|
)]
|
||||||
|
pub extend_fixable: Option<Vec<RuleSelector>>,
|
||||||
|
/// Like --unfixable. (Deprecated: You can just use --unfixable instead.)
|
||||||
|
#[arg(
|
||||||
|
long,
|
||||||
|
value_delimiter = ',',
|
||||||
|
value_name = "RULE_CODE",
|
||||||
|
value_parser = parse_rule_selector,
|
||||||
|
help_heading = "Rule selection",
|
||||||
|
hide = true
|
||||||
|
)]
|
||||||
|
pub extend_unfixable: Option<Vec<RuleSelector>>,
|
||||||
/// Respect file exclusions via `.gitignore` and other standard ignore
|
/// Respect file exclusions via `.gitignore` and other standard ignore
|
||||||
/// files.
|
/// files.
|
||||||
#[arg(
|
#[arg(
|
||||||
|
@ -375,8 +396,10 @@ impl CheckArgs {
|
||||||
dummy_variable_rgx: self.dummy_variable_rgx,
|
dummy_variable_rgx: self.dummy_variable_rgx,
|
||||||
exclude: self.exclude,
|
exclude: self.exclude,
|
||||||
extend_exclude: self.extend_exclude,
|
extend_exclude: self.extend_exclude,
|
||||||
|
extend_fixable: self.extend_fixable,
|
||||||
extend_ignore: self.extend_ignore,
|
extend_ignore: self.extend_ignore,
|
||||||
extend_select: self.extend_select,
|
extend_select: self.extend_select,
|
||||||
|
extend_unfixable: self.extend_unfixable,
|
||||||
fixable: self.fixable,
|
fixable: self.fixable,
|
||||||
ignore: self.ignore,
|
ignore: self.ignore,
|
||||||
line_length: self.line_length,
|
line_length: self.line_length,
|
||||||
|
@ -442,8 +465,10 @@ pub struct Overrides {
|
||||||
pub dummy_variable_rgx: Option<Regex>,
|
pub dummy_variable_rgx: Option<Regex>,
|
||||||
pub exclude: Option<Vec<FilePattern>>,
|
pub exclude: Option<Vec<FilePattern>>,
|
||||||
pub extend_exclude: Option<Vec<FilePattern>>,
|
pub extend_exclude: Option<Vec<FilePattern>>,
|
||||||
|
pub extend_fixable: Option<Vec<RuleSelector>>,
|
||||||
pub extend_ignore: Option<Vec<RuleSelector>>,
|
pub extend_ignore: Option<Vec<RuleSelector>>,
|
||||||
pub extend_select: Option<Vec<RuleSelector>>,
|
pub extend_select: Option<Vec<RuleSelector>>,
|
||||||
|
pub extend_unfixable: Option<Vec<RuleSelector>>,
|
||||||
pub fixable: Option<Vec<RuleSelector>>,
|
pub fixable: Option<Vec<RuleSelector>>,
|
||||||
pub ignore: Option<Vec<RuleSelector>>,
|
pub ignore: Option<Vec<RuleSelector>>,
|
||||||
pub line_length: Option<usize>,
|
pub line_length: Option<usize>,
|
||||||
|
@ -493,7 +518,14 @@ impl ConfigProcessor for &Overrides {
|
||||||
.collect(),
|
.collect(),
|
||||||
extend_select: self.extend_select.clone().unwrap_or_default(),
|
extend_select: self.extend_select.clone().unwrap_or_default(),
|
||||||
fixable: self.fixable.clone(),
|
fixable: self.fixable.clone(),
|
||||||
unfixable: self.unfixable.clone().unwrap_or_default(),
|
unfixable: self
|
||||||
|
.unfixable
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.chain(self.extend_unfixable.iter().cloned())
|
||||||
|
.flatten()
|
||||||
|
.collect(),
|
||||||
|
extend_fixable: self.extend_fixable.clone().unwrap_or_default(),
|
||||||
});
|
});
|
||||||
if let Some(format) = &self.format {
|
if let Some(format) = &self.format {
|
||||||
config.format = Some(*format);
|
config.format = Some(*format);
|
||||||
|
|
|
@ -96,8 +96,10 @@ pub fn defaultSettings() -> Result<JsValue, JsValue> {
|
||||||
allowed_confusables: Some(Vec::default()),
|
allowed_confusables: Some(Vec::default()),
|
||||||
builtins: Some(Vec::default()),
|
builtins: Some(Vec::default()),
|
||||||
dummy_variable_rgx: Some(defaults::DUMMY_VARIABLE_RGX.as_str().to_string()),
|
dummy_variable_rgx: Some(defaults::DUMMY_VARIABLE_RGX.as_str().to_string()),
|
||||||
|
extend_fixable: Some(Vec::default()),
|
||||||
extend_ignore: Some(Vec::default()),
|
extend_ignore: Some(Vec::default()),
|
||||||
extend_select: Some(Vec::default()),
|
extend_select: Some(Vec::default()),
|
||||||
|
extend_unfixable: Some(Vec::default()),
|
||||||
external: Some(Vec::default()),
|
external: Some(Vec::default()),
|
||||||
ignore: Some(Vec::default()),
|
ignore: Some(Vec::default()),
|
||||||
line_length: Some(defaults::LINE_LENGTH),
|
line_length: Some(defaults::LINE_LENGTH),
|
||||||
|
|
|
@ -239,6 +239,8 @@ Rule selection:
|
||||||
List of rule codes to treat as eligible for autofix. Only applicable when autofix itself is enabled (e.g., via `--fix`)
|
List of rule codes to treat as eligible for autofix. Only applicable when autofix itself is enabled (e.g., via `--fix`)
|
||||||
--unfixable <RULE_CODE>
|
--unfixable <RULE_CODE>
|
||||||
List of rule codes to treat as ineligible for autofix. Only applicable when autofix itself is enabled (e.g., via `--fix`)
|
List of rule codes to treat as ineligible for autofix. Only applicable when autofix itself is enabled (e.g., via `--fix`)
|
||||||
|
--extend-fixable <RULE_CODE>
|
||||||
|
Like --fixable, but adds additional rule codes on top of the fixable ones
|
||||||
|
|
||||||
File selection:
|
File selection:
|
||||||
--exclude <FILE_PATTERN> List of paths, used to omit files and/or directories from analysis
|
--exclude <FILE_PATTERN> List of paths, used to omit files and/or directories from analysis
|
||||||
|
|
10
ruff.schema.json
generated
10
ruff.schema.json
generated
|
@ -66,6 +66,16 @@
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"extend-fixable": {
|
||||||
|
"description": "A list of rule codes or prefixes to consider autofixable, in addition to those specified by `fixable`.",
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/RuleSelector"
|
||||||
|
}
|
||||||
|
},
|
||||||
"extend-include": {
|
"extend-include": {
|
||||||
"description": "A list of file patterns to include when linting, in addition to those specified by `include`.\n\nInclusion are based on globs, and should be single-path patterns, like `*.pyw`, to include any file with the `.pyw` extension.\n\nFor more information on the glob syntax, refer to the [`globset` documentation](https://docs.rs/globset/latest/globset/#syntax).",
|
"description": "A list of file patterns to include when linting, in addition to those specified by `include`.\n\nInclusion are based on globs, and should be single-path patterns, like `*.pyw`, to include any file with the `.pyw` extension.\n\nFor more information on the glob syntax, refer to the [`globset` documentation](https://docs.rs/globset/latest/globset/#syntax).",
|
||||||
"type": [
|
"type": [
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue