Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions crates/ruff/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,17 @@ pub struct CheckCommand {
hide_possible_values = true
)]
pub select: Option<Vec<RuleSelector>>,
/// Comma-separated list of rule codes to enable (or ALL, to enable all
/// rules) with severity `warning`
#[arg(
long,
value_delimiter = ',',
value_name = "RULE_CODE",
value_parser = RuleSelectorParser,
help_heading = "Rule selection",
hide_possible_values = true
)]
pub warn: Option<Vec<RuleSelector>>,
/// Comma-separated list of rule codes to disable.
#[arg(
long,
Expand All @@ -314,6 +325,16 @@ pub struct CheckCommand {
hide_possible_values = true
)]
pub extend_select: Option<Vec<RuleSelector>>,
/// Like --warn, but adds additional rule codes on top of those already specified.
#[arg(
long,
value_delimiter = ',',
value_name = "RULE_CODE",
value_parser = RuleSelectorParser,
help_heading = "Rule selection",
hide_possible_values = true
)]
pub extend_warn: Option<Vec<RuleSelector>>,
/// Like --ignore. (Deprecated: You can just use --ignore instead.)
#[arg(
long,
Expand Down Expand Up @@ -786,6 +807,7 @@ impl CheckCommand {
extend_ignore: self.extend_ignore,
extend_per_file_ignores: self.extend_per_file_ignores,
extend_select: self.extend_select,
extend_warn: self.extend_warn,
extend_unfixable: self.extend_unfixable,
fixable: self.fixable,
ignore: self.ignore,
Expand All @@ -794,6 +816,7 @@ impl CheckCommand {
preview: resolve_bool_arg(self.preview, self.no_preview).map(PreviewMode::from),
respect_gitignore: resolve_bool_arg(self.respect_gitignore, self.no_respect_gitignore),
select: self.select,
warn: self.warn,
target_version: self.target_version.map(ast::PythonVersion::from),
unfixable: self.unfixable,
// TODO(charlie): Included in `pyproject.toml`, but not inherited.
Expand Down Expand Up @@ -1349,6 +1372,7 @@ struct ExplicitConfigOverrides {
extend_fixable: Option<Vec<RuleSelector>>,
extend_ignore: Option<Vec<RuleSelector>>,
extend_select: Option<Vec<RuleSelector>>,
extend_warn: Option<Vec<RuleSelector>>,
extend_unfixable: Option<Vec<RuleSelector>>,
fixable: Option<Vec<RuleSelector>>,
ignore: Option<Vec<RuleSelector>>,
Expand All @@ -1358,6 +1382,7 @@ struct ExplicitConfigOverrides {
preview: Option<PreviewMode>,
respect_gitignore: Option<bool>,
select: Option<Vec<RuleSelector>>,
warn: Option<Vec<RuleSelector>>,
target_version: Option<ast::PythonVersion>,
unfixable: Option<Vec<RuleSelector>>,
// TODO(charlie): Captured in pyproject.toml as a default, but not part of `Settings`.
Expand Down Expand Up @@ -1405,6 +1430,7 @@ impl ConfigurationTransformer for ExplicitConfigOverrides {
}
config.lint.rule_selections.push(RuleSelection {
select: self.select.clone(),
warn: self.warn.clone(),
ignore: self
.ignore
.iter()
Expand All @@ -1413,6 +1439,7 @@ impl ConfigurationTransformer for ExplicitConfigOverrides {
.flatten()
.collect(),
extend_select: self.extend_select.clone().unwrap_or_default(),
extend_warn: self.extend_warn.clone().unwrap_or_default(),
fixable: self.fixable.clone(),
unfixable: self
.unfixable
Expand Down
6 changes: 5 additions & 1 deletion crates/ruff/src/commands/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,11 @@ pub(crate) fn check(
SourceFileBuilder::new(path.to_string_lossy().as_ref(), "").finish();

Diagnostics::new(
vec![IOError { message }.into_diagnostic(TextRange::default(), &dummy)],
vec![IOError { message }.into_diagnostic(
TextRange::default(),
&dummy,
settings.linter.rules.severity(Rule::IOError),
)],
FxHashMap::default(),
)
} else {
Expand Down
6 changes: 5 additions & 1 deletion crates/ruff/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,11 @@ impl Diagnostics {
IOError {
message: err.to_string(),
}
.into_diagnostic(TextRange::default(), &source_file),
.into_diagnostic(
TextRange::default(),
&source_file,
settings.rules.severity(Rule::IOError),
),
],
FxHashMap::default(),
)
Expand Down
37 changes: 25 additions & 12 deletions crates/ruff/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use notify::{RecursiveMode, Watcher, recommended_watcher};
use args::{GlobalConfigArgs, ServerCommand};
use ruff_db::diagnostic::{Diagnostic, Severity};
use ruff_linter::logging::{LogLevel, set_up_logging};
use ruff_linter::preview::is_warning_severity_enabled;
use ruff_linter::settings::flags::FixMode;
use ruff_linter::{fs, warn_user, warn_user_once};
use ruff_workspace::Settings;
Expand Down Expand Up @@ -363,6 +364,21 @@ pub fn check(args: CheckCommand, global_options: GlobalConfigArgs) -> Result<Exi
// is resolved.
let preview = pyproject_config.settings.linter.preview;

if !is_warning_severity_enabled(preview)
&& pyproject_config
.settings
.linter
.rules
.iter_warn()
// TODO use `exact_size_is_empty` if that API stabilizes
.len()
.ne(&0)
{
warn_user_once!(
"Enabling rules with severity 'warning' requires preview mode, otherwise all rules are interpreted with severity 'error'."
);
}
Comment on lines +376 to +380
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd love feedback on whether or not this should be the behavior when preview is not enabled. Another option would be to interpret everything "correctly" but just warn the user that severities are in preview and experimental.

If we do like the idea of interpreting these as error there's some other design questions... for example, at the moment with preview disabled it will still "correctly" populate lint.warn if you do --show-settings. Is that we want?


if cli.watch {
// Configure the file watcher.
let (tx, rx) = channel();
Expand Down Expand Up @@ -452,7 +468,7 @@ pub fn check(args: CheckCommand, global_options: GlobalConfigArgs) -> Result<Exi
writer
};
if cli.statistics {
printer.write_statistics(&diagnostics, &mut summary_writer)?;
printer.write_statistics(&diagnostics, &mut summary_writer, preview)?;
} else {
printer.write_once(&diagnostics, &mut summary_writer, preview)?;
}
Expand Down Expand Up @@ -495,17 +511,14 @@ https://github.com/astral-sh/ruff/issues/new?title=%5BLinter%20panic%5D
}
}
} else {
// If we're running the linter (not just fixing), we want to exit non-zero if
// there are any violations, unless we're explicitly asked to exit zero on
// fix.
if cli.exit_non_zero_on_fix {
if !diagnostics.fixed.is_empty() || !diagnostics.inner.is_empty() {
return Ok(ExitStatus::Failure);
}
} else {
if !diagnostics.inner.is_empty() {
return Ok(ExitStatus::Failure);
}
// If we're running the linter (not just fixing), we want to
// exit non-zero if there are any (error level) violations,
// unless we're explicitly asked to exit zero on fix.
if max_severity >= Severity::Error
|| (!is_warning_severity_enabled(preview) && !diagnostics.inner.is_empty())
|| (cli.exit_non_zero_on_fix && !diagnostics.fixed.is_empty())
{
return Ok(ExitStatus::Failure);
}
}
}
Expand Down
32 changes: 22 additions & 10 deletions crates/ruff/src/printer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,12 @@ impl Printer {
}
}

fn write_summary_text(&self, writer: &mut dyn Write, diagnostics: &Diagnostics) -> Result<()> {
fn write_summary_text(
&self,
writer: &mut dyn Write,
diagnostics: &Diagnostics,
preview: PreviewMode,
) -> Result<()> {
if self.log_level >= LogLevel::Default {
let fixables = FixableStatistics::try_from(diagnostics, self.unsafe_fixes);

Expand All @@ -91,18 +96,24 @@ impl Printer {
.flat_map(FixTable::counts)
.sum::<usize>();

let reportable = if preview.is_enabled() {
"diagnostic"
} else {
"error"
};

if self.flags.intersects(Flags::SHOW_VIOLATIONS) {
let remaining = diagnostics.inner.len();
let total = fixed + remaining;
if fixed > 0 {
let s = if total == 1 { "" } else { "s" };
writeln!(
writer,
"Found {total} error{s} ({fixed} fixed, {remaining} remaining)."
"Found {total} {reportable}{s} ({fixed} fixed, {remaining} remaining)."
)?;
} else if remaining > 0 {
let s = if remaining == 1 { "" } else { "s" };
writeln!(writer, "Found {remaining} error{s}.")?;
writeln!(writer, "Found {remaining} {reportable}{s}.")?;
} else if remaining == 0 {
writeln!(writer, "All checks passed!")?;
}
Expand Down Expand Up @@ -169,12 +180,12 @@ impl Printer {
if self.fix_mode.is_apply() {
writeln!(
writer,
"Fixed {fixed} error{s} ({unapplied} additional fix{es} available with `--unsafe-fixes`)."
"Fixed {fixed} {reportable}{s} ({unapplied} additional fix{es} available with `--unsafe-fixes`)."
)?;
} else {
writeln!(
writer,
"Would fix {fixed} error{s} ({unapplied} additional fix{es} available with `--unsafe-fixes`)."
"Would fix {fixed} {reportable}{s} ({unapplied} additional fix{es} available with `--unsafe-fixes`)."
)?;
}
} else {
Expand All @@ -194,9 +205,9 @@ impl Printer {
if fixed > 0 {
let s = if fixed == 1 { "" } else { "s" };
if self.fix_mode.is_apply() {
writeln!(writer, "Fixed {fixed} error{s}.")?;
writeln!(writer, "Fixed {fixed} {reportable}{s}.")?;
} else {
writeln!(writer, "Would fix {fixed} error{s}.")?;
writeln!(writer, "Would fix {fixed} {reportable}{s}.")?;
}
}
}
Expand Down Expand Up @@ -227,7 +238,7 @@ impl Printer {
writeln!(writer)?;
}
}
self.write_summary_text(writer, diagnostics)?;
self.write_summary_text(writer, diagnostics, preview)?;
}
return Ok(());
}
Expand Down Expand Up @@ -256,7 +267,7 @@ impl Printer {
writeln!(writer)?;
}
}
self.write_summary_text(writer, diagnostics)?;
self.write_summary_text(writer, diagnostics, preview)?;
}

writer.flush()?;
Expand All @@ -268,6 +279,7 @@ impl Printer {
&self,
diagnostics: &Diagnostics,
writer: &mut dyn Write,
preview: PreviewMode,
) -> Result<()> {
let required_applicability = self.unsafe_fixes.required_applicability();
let statistics: Vec<ExpandedStatistics> = diagnostics
Expand Down Expand Up @@ -360,7 +372,7 @@ impl Printer {
)?;
}

self.write_summary_text(writer, diagnostics)?;
self.write_summary_text(writer, diagnostics, preview)?;
return Ok(());
}
OutputFormat::Json => {
Expand Down
Loading
Loading