mirror of https://github.com/astral-sh/ruff
red_knot: plumb through `DiagnosticFormat` to the CLI
The CLI calls this `OutputFormat`, and so does the type where the CLI is defined. But it's called `DiagnosticFormat` in `ruff_db` to be consistent with `DisplayDiagnosticConfig`. Ref https://github.com/astral-sh/ruff/issues/15697#issuecomment-2706477278
This commit is contained in:
parent
eb6871d209
commit
2bcd2b4147
|
|
@ -75,6 +75,10 @@ pub(crate) struct CheckCommand {
|
||||||
#[clap(flatten)]
|
#[clap(flatten)]
|
||||||
pub(crate) rules: RulesArg,
|
pub(crate) rules: RulesArg,
|
||||||
|
|
||||||
|
/// The format to use for printing diagnostic messages.
|
||||||
|
#[arg(long)]
|
||||||
|
pub(crate) output_format: Option<OutputFormat>,
|
||||||
|
|
||||||
/// Use exit code 1 if there are any warning-level diagnostics.
|
/// Use exit code 1 if there are any warning-level diagnostics.
|
||||||
#[arg(long, conflicts_with = "exit_zero", default_missing_value = "true", num_args=0..1)]
|
#[arg(long, conflicts_with = "exit_zero", default_missing_value = "true", num_args=0..1)]
|
||||||
pub(crate) error_on_warning: Option<bool>,
|
pub(crate) error_on_warning: Option<bool>,
|
||||||
|
|
@ -117,6 +121,9 @@ impl CheckCommand {
|
||||||
..EnvironmentOptions::default()
|
..EnvironmentOptions::default()
|
||||||
}),
|
}),
|
||||||
terminal: Some(TerminalOptions {
|
terminal: Some(TerminalOptions {
|
||||||
|
output_format: self
|
||||||
|
.output_format
|
||||||
|
.map(|output_format| RangedValue::cli(output_format.into())),
|
||||||
error_on_warning: self.error_on_warning,
|
error_on_warning: self.error_on_warning,
|
||||||
}),
|
}),
|
||||||
rules,
|
rules,
|
||||||
|
|
@ -211,3 +218,32 @@ impl clap::Args for RulesArg {
|
||||||
Self::augment_args(cmd)
|
Self::augment_args(cmd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The diagnostic output format.
|
||||||
|
#[derive(Copy, Clone, Hash, Debug, PartialEq, Eq, PartialOrd, Ord, Default, clap::ValueEnum)]
|
||||||
|
pub enum OutputFormat {
|
||||||
|
/// Print diagnostics verbosely, with context and helpful hints.
|
||||||
|
///
|
||||||
|
/// Diagnostic messages may include additional context and
|
||||||
|
/// annotations on the input to help understand the message.
|
||||||
|
#[default]
|
||||||
|
#[value(name = "full")]
|
||||||
|
Full,
|
||||||
|
/// Print diagnostics concisely, one per line.
|
||||||
|
///
|
||||||
|
/// This will guarantee that each diagnostic is printed on
|
||||||
|
/// a single line. Only the most important or primary aspects
|
||||||
|
/// of the diagnostic are included. Contextual information is
|
||||||
|
/// dropped.
|
||||||
|
#[value(name = "concise")]
|
||||||
|
Concise,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<OutputFormat> for ruff_db::diagnostic::DiagnosticFormat {
|
||||||
|
fn from(format: OutputFormat) -> ruff_db::diagnostic::DiagnosticFormat {
|
||||||
|
match format {
|
||||||
|
OutputFormat::Full => Self::Full,
|
||||||
|
OutputFormat::Concise => Self::Concise,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -256,6 +256,7 @@ impl MainLoop {
|
||||||
revision: check_revision,
|
revision: check_revision,
|
||||||
} => {
|
} => {
|
||||||
let display_config = DisplayDiagnosticConfig::default()
|
let display_config = DisplayDiagnosticConfig::default()
|
||||||
|
.format(db.project().settings(db).terminal().output_format)
|
||||||
.color(colored::control::SHOULD_COLORIZE.should_colorize());
|
.color(colored::control::SHOULD_COLORIZE.should_colorize());
|
||||||
|
|
||||||
let min_error_severity =
|
let min_error_severity =
|
||||||
|
|
|
||||||
|
|
@ -967,6 +967,30 @@ fn check_non_existing_path() -> anyhow::Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn concise_diagnostics() -> anyhow::Result<()> {
|
||||||
|
let case = TestCase::with_file(
|
||||||
|
"test.py",
|
||||||
|
r#"
|
||||||
|
print(x) # [unresolved-reference]
|
||||||
|
print(4[1]) # [non-subscriptable]
|
||||||
|
"#,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
assert_cmd_snapshot!(case.command().arg("--output-format=concise"), @r"
|
||||||
|
success: false
|
||||||
|
exit_code: 1
|
||||||
|
----- stdout -----
|
||||||
|
warning[lint:unresolved-reference] <temp_dir>/test.py:2:7: Name `x` used when not defined
|
||||||
|
error[lint:non-subscriptable] <temp_dir>/test.py:3:7: Cannot subscript object of type `Literal[4]` with no `__getitem__` method
|
||||||
|
Found 2 diagnostics
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
struct TestCase {
|
struct TestCase {
|
||||||
_temp_dir: TempDir,
|
_temp_dir: TempDir,
|
||||||
_settings_scope: SettingsBindDropGuard,
|
_settings_scope: SettingsBindDropGuard,
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use crate::metadata::value::{RangedValue, RelativePathBuf, ValueSource, ValueSou
|
||||||
use crate::Db;
|
use crate::Db;
|
||||||
use red_knot_python_semantic::lint::{GetLintError, Level, LintSource, RuleSelection};
|
use red_knot_python_semantic::lint::{GetLintError, Level, LintSource, RuleSelection};
|
||||||
use red_knot_python_semantic::{ProgramSettings, PythonPath, PythonPlatform, SearchPathSettings};
|
use red_knot_python_semantic::{ProgramSettings, PythonPath, PythonPlatform, SearchPathSettings};
|
||||||
use ruff_db::diagnostic::{DiagnosticId, OldDiagnosticTrait, Severity, Span};
|
use ruff_db::diagnostic::{DiagnosticFormat, DiagnosticId, OldDiagnosticTrait, Severity, Span};
|
||||||
use ruff_db::files::system_path_to_file;
|
use ruff_db::files::system_path_to_file;
|
||||||
use ruff_db::system::{System, SystemPath};
|
use ruff_db::system::{System, SystemPath};
|
||||||
use ruff_macros::Combine;
|
use ruff_macros::Combine;
|
||||||
|
|
@ -120,6 +120,11 @@ impl Options {
|
||||||
|
|
||||||
if let Some(terminal) = self.terminal.as_ref() {
|
if let Some(terminal) = self.terminal.as_ref() {
|
||||||
settings.set_terminal(TerminalSettings {
|
settings.set_terminal(TerminalSettings {
|
||||||
|
output_format: terminal
|
||||||
|
.output_format
|
||||||
|
.as_deref()
|
||||||
|
.copied()
|
||||||
|
.unwrap_or_default(),
|
||||||
error_on_warning: terminal.error_on_warning.unwrap_or_default(),
|
error_on_warning: terminal.error_on_warning.unwrap_or_default(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -277,6 +282,11 @@ impl FromIterator<(RangedValue<String>, RangedValue<Level>)> for Rules {
|
||||||
#[serde(rename_all = "kebab-case", deny_unknown_fields)]
|
#[serde(rename_all = "kebab-case", deny_unknown_fields)]
|
||||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||||
pub struct TerminalOptions {
|
pub struct TerminalOptions {
|
||||||
|
/// The format to use for printing diagnostic messages.
|
||||||
|
///
|
||||||
|
/// Defaults to `full`.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub output_format: Option<RangedValue<DiagnosticFormat>>,
|
||||||
/// Use exit code 1 if there are any warning-level diagnostics.
|
/// Use exit code 1 if there are any warning-level diagnostics.
|
||||||
///
|
///
|
||||||
/// Defaults to `false`.
|
/// Defaults to `false`.
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use red_knot_python_semantic::lint::RuleSelection;
|
use red_knot_python_semantic::lint::RuleSelection;
|
||||||
|
use ruff_db::diagnostic::DiagnosticFormat;
|
||||||
|
|
||||||
/// The resolved [`super::Options`] for the project.
|
/// The resolved [`super::Options`] for the project.
|
||||||
///
|
///
|
||||||
|
|
@ -49,5 +50,6 @@ impl Settings {
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||||
pub struct TerminalSettings {
|
pub struct TerminalSettings {
|
||||||
|
pub output_format: DiagnosticFormat,
|
||||||
pub error_on_warning: bool,
|
pub error_on_warning: bool,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,25 @@
|
||||||
},
|
},
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"definitions": {
|
"definitions": {
|
||||||
|
"DiagnosticFormat": {
|
||||||
|
"description": "The diagnostic output format.",
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"description": "The default full mode will print \"pretty\" diagnostics.\n\nThat is, color will be used when printing to a `tty`. Moreover, diagnostic messages may include additional context and annotations on the input to help understand the message.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"full"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Print diagnostics in a concise mode.\n\nThis will guarantee that each diagnostic is printed on a single line. Only the most important or primary aspects of the diagnostic are included. Contextual information is dropped.\n\nThis may use color when printing to a `tty`.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"concise"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"EnvironmentOptions": {
|
"EnvironmentOptions": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -748,6 +767,17 @@
|
||||||
"boolean",
|
"boolean",
|
||||||
"null"
|
"null"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"output-format": {
|
||||||
|
"description": "The format to use for printing diagnostic messages.\n\nDefaults to `full`.",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/DiagnosticFormat"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue