Use insta_cmd (#6737)

This commit is contained in:
konsti 2023-09-05 14:21:27 +02:00 committed by GitHub
parent 7ead2c17b1
commit e02d76f070
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 423 additions and 311 deletions

13
Cargo.lock generated
View file

@ -1114,11 +1114,23 @@ dependencies = [
"lazy_static", "lazy_static",
"linked-hash-map", "linked-hash-map",
"regex", "regex",
"serde",
"similar", "similar",
"walkdir", "walkdir",
"yaml-rust", "yaml-rust",
] ]
[[package]]
name = "insta-cmd"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "809d3023d1d6e8d5c2206f199251f75cb26180e41f18cb0f22dd119161cb5127"
dependencies = [
"insta",
"serde",
"serde_json",
]
[[package]] [[package]]
name = "instant" name = "instant"
version = "0.1.12" version = "0.1.12"
@ -2169,6 +2181,7 @@ dependencies = [
"glob", "glob",
"ignore", "ignore",
"insta", "insta",
"insta-cmd",
"is-macro", "is-macro",
"itertools", "itertools",
"itoa", "itoa",

View file

@ -70,7 +70,10 @@ wild = { version = "2" }
[dev-dependencies] [dev-dependencies]
assert_cmd = { version = "2.0.8" } assert_cmd = { version = "2.0.8" }
# Avoid writing colored snapshots when running tests from the terminal
colored = { workspace = true, features = ["no-color"]}
insta = { workspace = true, features = ["filters"] } insta = { workspace = true, features = ["filters"] }
insta-cmd = { version = "0.4.0" }
tempfile = "3.6.0" tempfile = "3.6.0"
ureq = { version = "2.6.2", features = [] } ureq = { version = "2.6.2", features = [] }

View file

@ -1,15 +1,15 @@
#![cfg(not(target_family = "wasm"))] #![cfg(not(target_family = "wasm"))]
use std::io::{ErrorKind, Read}; use std::io::{ErrorKind, Read, Write};
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpListener, TcpStream}; use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpListener, TcpStream};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::process::Stdio; use std::process::{Command, Stdio};
use std::thread::sleep; use std::thread::sleep;
use std::time::Duration; use std::time::Duration;
use std::{fs, process, str}; use std::{fs, process, str};
use anyhow::{anyhow, Context, Result}; use anyhow::{anyhow, bail, Context, Result};
use assert_cmd::Command; use insta_cmd::get_cargo_bin;
use log::info; use log::info;
use walkdir::WalkDir; use walkdir::WalkDir;
@ -29,13 +29,14 @@ impl Blackd {
// Get free TCP port to run on // Get free TCP port to run on
let address = TcpListener::bind(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 0))?.local_addr()?; let address = TcpListener::bind(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 0))?.local_addr()?;
let server = process::Command::new("blackd") let args = [
.args([ "--bind-host",
"--bind-host", &address.ip().to_string(),
&address.ip().to_string(), "--bind-port",
"--bind-port", &address.port().to_string(),
&address.port().to_string(), ];
]) let server = Command::new("blackd")
.args(args)
.stdout(Stdio::null()) .stdout(Stdio::null())
.stderr(Stdio::null()) .stderr(Stdio::null())
.spawn() .spawn()
@ -51,16 +52,16 @@ impl Blackd {
Err(e) => return Err(e.into()), Err(e) => return Err(e.into()),
Ok(_) => { Ok(_) => {
info!("`blackd` ready"); info!("`blackd` ready");
break; return Ok(Self {
address,
server,
client: ureq::agent(),
});
} }
} }
} }
Ok(Self { bail!("blackd {:?} failed to start", args)
address,
server,
client: ureq::agent(),
})
} }
/// Format given code with blackd. /// Format given code with blackd.
@ -104,34 +105,42 @@ fn run_test(path: &Path, blackd: &Blackd, ruff_args: &[&str]) -> Result<()> {
let input = fs::read(path)?; let input = fs::read(path)?;
// Step 1: Run `ruff` on the input. // Step 1: Run `ruff` on the input.
let step_1 = &Command::cargo_bin(BIN_NAME)? let mut step_1 = Command::new(get_cargo_bin(BIN_NAME))
.args(ruff_args) .args(ruff_args)
.write_stdin(input) .stdin(Stdio::piped())
.assert() .stdout(Stdio::piped())
.append_context("step", "running input through ruff"); .spawn()?;
if !step_1.get_output().status.success() { if let Some(mut stdin) = step_1.stdin.take() {
stdin.write_all(input.as_ref())?;
}
let step_1_output = step_1.wait_with_output()?;
if !step_1_output.status.success() {
return Err(anyhow!( return Err(anyhow!(
"Running input through ruff failed:\n{}", "Running input through ruff failed:\n{}",
str::from_utf8(&step_1.get_output().stderr)? str::from_utf8(&step_1_output.stderr)?
)); ));
} }
let step_1_output = step_1.get_output().stdout.clone();
// Step 2: Run `blackd` on the input. // Step 2: Run `blackd` on the input.
let step_2_output = blackd.check(&step_1_output)?; let step_2_output = blackd.check(&step_1_output.stdout.clone())?;
// Step 3: Re-run `ruff` on the input. // Step 3: Re-run `ruff` on the input.
let step_3 = &Command::cargo_bin(BIN_NAME)? let mut step_3 = Command::new(get_cargo_bin(BIN_NAME))
.args(ruff_args) .args(ruff_args)
.write_stdin(step_2_output.clone()) .stdin(Stdio::piped())
.assert(); .stdout(Stdio::piped())
if !step_3.get_output().status.success() { .spawn()?;
if let Some(mut stdin) = step_3.stdin.take() {
stdin.write_all(step_2_output.as_ref())?;
}
let step_3_output = step_3.wait_with_output()?;
if !step_3_output.status.success() {
return Err(anyhow!( return Err(anyhow!(
"Running input through ruff after black failed:\n{}", "Running input through ruff after black failed:\n{}",
str::from_utf8(&step_3.get_output().stderr)? str::from_utf8(&step_3_output.stderr)?
)); ));
} }
let step_3_output = step_3.get_output().stdout.clone(); let step_3_output = step_3_output.stdout.clone();
assert_eq!( assert_eq!(
str::from_utf8(&step_2_output), str::from_utf8(&step_2_output),
@ -177,11 +186,13 @@ fn test_ruff_black_compatibility() -> Result<()> {
"--fix", "--fix",
"--line-length", "--line-length",
"88", "88",
"--select ALL", "--select",
"ALL",
// Exclude ruff codes, specifically RUF100, because it causes differences that are not a // Exclude ruff codes, specifically RUF100, because it causes differences that are not a
// problem. Ruff would add a `# noqa: W292` after the first run, black introduces a // problem. Ruff would add a `# noqa: W292` after the first run, black introduces a
// newline, and ruff removes the `# noqa: W292` again. // newline, and ruff removes the `# noqa: W292` again.
"--ignore RUF", "--ignore",
"RUF",
]; ];
for entry in paths { for entry in paths {

View file

@ -8,14 +8,15 @@ use std::fs::Permissions;
use std::os::unix::fs::{OpenOptionsExt, PermissionsExt}; use std::os::unix::fs::{OpenOptionsExt, PermissionsExt};
#[cfg(unix)] #[cfg(unix)]
use std::path::Path; use std::path::Path;
use std::process::Command;
use std::str; use std::str;
#[cfg(unix)] #[cfg(unix)]
use anyhow::Context; use anyhow::Context;
use anyhow::Result; use anyhow::Result;
use assert_cmd::Command;
#[cfg(unix)] #[cfg(unix)]
use clap::Parser; use clap::Parser;
use insta_cmd::{assert_cmd_snapshot, get_cargo_bin};
#[cfg(unix)] #[cfg(unix)]
use path_absolutize::path_dedot; use path_absolutize::path_dedot;
#[cfg(unix)] #[cfg(unix)]
@ -27,315 +28,280 @@ use ruff_cli::args::Args;
use ruff_cli::run; use ruff_cli::run;
const BIN_NAME: &str = "ruff"; const BIN_NAME: &str = "ruff";
const STDIN_BASE_OPTIONS: &[&str] = &["--isolated", "--no-cache", "-", "--format", "text"];
#[test] #[test]
fn stdin_success() -> Result<()> { fn stdin_success() {
let mut cmd = Command::cargo_bin(BIN_NAME)?; assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
cmd.args(["-", "--format", "text", "--isolated"]) .args(STDIN_BASE_OPTIONS)
.write_stdin("") .pass_stdin(""), @r###"
.assert() success: true
.success(); exit_code: 0
Ok(()) ----- stdout -----
----- stderr -----
"###);
} }
#[test] #[test]
fn stdin_error() -> Result<()> { fn stdin_error() {
let mut cmd = Command::cargo_bin(BIN_NAME)?; assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
let output = cmd .args(STDIN_BASE_OPTIONS)
.args(["-", "--format", "text", "--isolated"]) .pass_stdin("import os\n"), @r#"
.write_stdin("import os\n") success: false
.assert() exit_code: 1
.failure(); ----- stdout -----
assert_eq!( -:1:8: F401 [*] `os` imported but unused
str::from_utf8(&output.get_output().stdout)?, Found 1 error.
r#"-:1:8: F401 [*] `os` imported but unused [*] 1 potentially fixable with the --fix option.
Found 1 error.
[*] 1 potentially fixable with the --fix option. ----- stderr -----
"# "#);
);
Ok(())
} }
#[test] #[test]
fn stdin_filename() -> Result<()> { fn stdin_filename() {
let mut cmd = Command::cargo_bin(BIN_NAME)?; assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
let output = cmd .args(STDIN_BASE_OPTIONS)
.args([ .args(["--stdin-filename", "F401.py"])
"-", .pass_stdin("import os\n"), @r###"
"--format", success: false
"text", exit_code: 1
"--stdin-filename", ----- stdout -----
"F401.py", F401.py:1:8: F401 [*] `os` imported but unused
"--isolated", Found 1 error.
]) [*] 1 potentially fixable with the --fix option.
.write_stdin("import os\n")
.assert() ----- stderr -----
.failure(); "###);
assert_eq!(
str::from_utf8(&output.get_output().stdout)?,
r#"F401.py:1:8: F401 [*] `os` imported but unused
Found 1 error.
[*] 1 potentially fixable with the --fix option.
"#
);
Ok(())
} }
#[test] #[test]
fn stdin_source_type() -> Result<()> { /// Raise `TCH` errors in `.py` files ...
// Raise `TCH` errors in `.py` files. fn stdin_source_type_py() {
let mut cmd = Command::cargo_bin(BIN_NAME)?; assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
let output = cmd .args(STDIN_BASE_OPTIONS)
.args([ .args(["--stdin-filename", "TCH.py"])
"-", .pass_stdin("import os\n"), @r###"
"--format", success: false
"text", exit_code: 1
"--stdin-filename", ----- stdout -----
"TCH.py", TCH.py:1:8: F401 [*] `os` imported but unused
"--isolated", Found 1 error.
]) [*] 1 potentially fixable with the --fix option.
.write_stdin("import os\n")
.assert()
.failure();
assert_eq!(
str::from_utf8(&output.get_output().stdout)?,
r#"TCH.py:1:8: F401 [*] `os` imported but unused
Found 1 error.
[*] 1 potentially fixable with the --fix option.
"#
);
// But not in `.pyi` files. ----- stderr -----
let mut cmd = Command::cargo_bin(BIN_NAME)?; "###);
cmd.args([ }
"-",
"--format", /// ... but not in `.pyi` files.
"text", #[test]
"--stdin-filename", fn stdin_source_type_pyi() {
"TCH.pyi", let args = ["--stdin-filename", "TCH.pyi", "--select", "TCH"];
"--isolated", assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
"--select", .args(STDIN_BASE_OPTIONS)
"TCH", .args(args)
]) .pass_stdin("import os\n"), @r###"
.write_stdin("import os\n") success: true
.assert() exit_code: 0
.success(); ----- stdout -----
Ok(())
----- stderr -----
"###);
} }
#[cfg(unix)] #[cfg(unix)]
#[test] #[test]
fn stdin_json() -> Result<()> { fn stdin_json() {
let mut cmd = Command::cargo_bin(BIN_NAME)?; let args = [
let output = cmd "-",
.args([ "--isolated",
"-", "--no-cache",
"--format", "--format",
"json", "json",
"--stdin-filename", "--stdin-filename",
"F401.py", "F401.py",
"--isolated", ];
])
.write_stdin("import os\n")
.assert()
.failure();
let directory = path_dedot::CWD.to_str().unwrap(); let directory = path_dedot::CWD.to_str().unwrap();
let binding = Path::new(directory).join("F401.py"); let binding = Path::new(directory).join("F401.py");
let file_path = binding.display(); let file_path = binding.display();
assert_eq!( insta::with_settings!({filters => vec![
str::from_utf8(&output.get_output().stdout)?, (file_path.to_string().as_str(), "/path/to/F401.py"),
format!( ]}, {
r#"[ assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
{{ .args(args)
"code": "F401", .pass_stdin("import os\n"));
"end_location": {{ });
"column": 10,
"row": 1
}},
"filename": "{file_path}",
"fix": {{
"applicability": "Automatic",
"edits": [
{{
"content": "",
"end_location": {{
"column": 1,
"row": 2
}},
"location": {{
"column": 1,
"row": 1
}}
}}
],
"message": "Remove unused import: `os`"
}},
"location": {{
"column": 8,
"row": 1
}},
"message": "`os` imported but unused",
"noqa_row": 1,
"url": "https://beta.ruff.rs/docs/rules/unused-import"
}}
]"#
)
);
Ok(())
} }
#[test] #[test]
fn stdin_autofix() -> Result<()> { fn stdin_autofix() {
let mut cmd = Command::cargo_bin(BIN_NAME)?; let args = ["--fix"];
let output = cmd assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(["-", "--format", "text", "--fix", "--isolated"]) .args(STDIN_BASE_OPTIONS)
.write_stdin("import os\nimport sys\n\nprint(sys.version)\n") .args(args)
.assert() .pass_stdin("import os\nimport sys\n\nprint(sys.version)\n"), @r###"
.success(); success: true
assert_eq!( exit_code: 0
str::from_utf8(&output.get_output().stdout)?, ----- stdout -----
"import sys\n\nprint(sys.version)\n" import sys
);
Ok(()) print(sys.version)
----- stderr -----
"###);
} }
#[test] #[test]
fn stdin_autofix_when_not_fixable_should_still_print_contents() -> Result<()> { fn stdin_autofix_when_not_fixable_should_still_print_contents() {
let mut cmd = Command::cargo_bin(BIN_NAME)?; let args = ["--fix"];
let output = cmd assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(["-", "--format", "text", "--fix", "--isolated"]) .args(STDIN_BASE_OPTIONS)
.write_stdin("import os\nimport sys\n\nif (1, 2):\n print(sys.version)\n") .args(args)
.assert() .pass_stdin("import os\nimport sys\n\nif (1, 2):\n print(sys.version)\n"), @r###"
.failure(); success: false
assert_eq!( exit_code: 1
str::from_utf8(&output.get_output().stdout)?, ----- stdout -----
"import sys\n\nif (1, 2):\n print(sys.version)\n" import sys
);
Ok(()) if (1, 2):
print(sys.version)
----- stderr -----
"###);
} }
#[test] #[test]
fn stdin_autofix_when_no_issues_should_still_print_contents() -> Result<()> { fn stdin_autofix_when_no_issues_should_still_print_contents() {
let mut cmd = Command::cargo_bin(BIN_NAME)?; let args = ["--fix"];
let output = cmd assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(["-", "--format", "text", "--fix", "--isolated"]) .args(STDIN_BASE_OPTIONS)
.write_stdin("import sys\n\nprint(sys.version)\n") .args(args)
.assert() .pass_stdin("import sys\n\nprint(sys.version)\n"), @r###"
.success(); success: true
assert_eq!( exit_code: 0
str::from_utf8(&output.get_output().stdout)?, ----- stdout -----
"import sys\n\nprint(sys.version)\n" import sys
);
Ok(()) print(sys.version)
----- stderr -----
"###);
} }
#[test] #[test]
fn show_source() -> Result<()> { fn show_source() {
let mut cmd = Command::cargo_bin(BIN_NAME)?; let args = ["--show-source"];
let output = cmd assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(["-", "--format", "text", "--show-source", "--isolated"]) .args(STDIN_BASE_OPTIONS)
.write_stdin("l = 1") .args(args)
.assert() .pass_stdin("l = 1"), @r###"
.failure(); success: false
assert!(str::from_utf8(&output.get_output().stdout)?.contains("l = 1")); exit_code: 1
Ok(()) ----- stdout -----
-:1:1: E741 Ambiguous variable name: `l`
|
1 | l = 1
| ^ E741
|
Found 1 error.
----- stderr -----
"###);
} }
#[test] #[test]
fn explain_status_codes() -> Result<()> { fn explain_status_codes_f401() {
let mut cmd = Command::cargo_bin(BIN_NAME)?; assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)).args(["--explain", "F401"]));
cmd.args(["--explain", "F401"]).assert().success(); }
let mut cmd = Command::cargo_bin(BIN_NAME)?; #[test]
cmd.args(["--explain", "RUF404"]).assert().failure(); fn explain_status_codes_ruf404() {
Ok(()) assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)).args(["--explain", "RUF404"]), @r###"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: invalid value 'RUF404' for '[RULE]': unknown rule code
For more information, try '--help'.
"###);
} }
#[test] #[test]
fn show_statistics() -> Result<()> { fn show_statistics() {
let mut cmd = Command::cargo_bin(BIN_NAME)?; let args = ["--select", "F401", "--statistics"];
let output = cmd assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args([ .args(STDIN_BASE_OPTIONS)
"-", .args(args)
"--format", .pass_stdin("import sys\nimport os\n\nprint(os.getuid())\n"), @r###"
"text", success: false
"--select", exit_code: 1
"F401", ----- stdout -----
"--statistics", 1 F401 [*] `sys` imported but unused
"--isolated",
]) ----- stderr -----
.write_stdin("import sys\nimport os\n\nprint(os.getuid())\n") "###);
.assert()
.failure();
assert_eq!(
str::from_utf8(&output.get_output().stdout)?
.lines()
.last()
.unwrap(),
"1\tF401\t[*] `sys` imported but unused"
);
Ok(())
} }
#[test] #[test]
fn nursery_prefix() -> Result<()> { fn nursery_prefix() {
let mut cmd = Command::cargo_bin(BIN_NAME)?;
// `--select E` should detect E741, but not E225, which is in the nursery. // `--select E` should detect E741, but not E225, which is in the nursery.
let output = cmd let args = ["--select", "E"];
.args(["-", "--format", "text", "--isolated", "--select", "E"]) assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.write_stdin("I=42\n") .args(STDIN_BASE_OPTIONS)
.assert() .args(args)
.failure(); .pass_stdin("I=42\n"), @r###"
assert_eq!( success: false
str::from_utf8(&output.get_output().stdout)?, exit_code: 1
r#"-:1:1: E741 Ambiguous variable name: `I` ----- stdout -----
Found 1 error. -:1:1: E741 Ambiguous variable name: `I`
"# Found 1 error.
);
Ok(()) ----- stderr -----
"###);
} }
#[test] #[test]
fn nursery_all() -> Result<()> { fn nursery_all() {
let mut cmd = Command::cargo_bin(BIN_NAME)?;
// `--select ALL` should detect E741, but not E225, which is in the nursery. // `--select ALL` should detect E741, but not E225, which is in the nursery.
let output = cmd let args = ["--select", "ALL"];
.args(["-", "--format", "text", "--isolated", "--select", "E"]) assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.write_stdin("I=42\n") .args(STDIN_BASE_OPTIONS)
.assert() .args(args)
.failure(); .pass_stdin("I=42\n"), @r###"
assert_eq!( success: false
str::from_utf8(&output.get_output().stdout)?, exit_code: 1
r#"-:1:1: E741 Ambiguous variable name: `I` ----- stdout -----
Found 1 error. -:1:1: E741 Ambiguous variable name: `I`
"# -:1:1: D100 Missing docstring in public module
); Found 2 errors.
Ok(()) ----- stderr -----
warning: `one-blank-line-before-class` (D203) and `no-blank-line-before-class` (D211) are incompatible. Ignoring `one-blank-line-before-class`.
warning: `multi-line-summary-first-line` (D212) and `multi-line-summary-second-line` (D213) are incompatible. Ignoring `multi-line-summary-second-line`.
"###);
} }
#[test] #[test]
fn nursery_direct() -> Result<()> { fn nursery_direct() {
let mut cmd = Command::cargo_bin(BIN_NAME)?;
// `--select E225` should detect E225. // `--select E225` should detect E225.
let output = cmd let args = ["--select", "E225"];
.args(["-", "--format", "text", "--isolated", "--select", "E225"]) assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.write_stdin("I=42\n") .args(STDIN_BASE_OPTIONS)
.assert() .args(args)
.failure(); .pass_stdin("I=42\n"), @r###"
assert_eq!( success: false
str::from_utf8(&output.get_output().stdout)?, exit_code: 1
r#"-:1:2: E225 Missing whitespace around operator ----- stdout -----
Found 1 error. -:1:2: E225 Missing whitespace around operator
"# Found 1 error.
);
Ok(()) ----- stderr -----
"###);
} }
/// An unreadable pyproject.toml in non-isolated mode causes ruff to hard-error trying to build up /// An unreadable pyproject.toml in non-isolated mode causes ruff to hard-error trying to build up
@ -376,17 +342,17 @@ fn unreadable_dir() -> Result<()> {
// We (currently?) have to use a subcommand to check exit status (currently wrong) and logging // We (currently?) have to use a subcommand to check exit status (currently wrong) and logging
// output // output
let mut cmd = Command::cargo_bin(BIN_NAME)?; // TODO(konstin): This should be a failure, but we currently can't track that
let output = cmd assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(["--no-cache", "--isolated"]) .args(["--no-cache", "--isolated"])
.arg(&unreadable_dir) .arg(&unreadable_dir), @r###"
.assert() success: true
// TODO(konstin): This should be a failure, but we currently can't track that exit_code: 0
.success(); ----- stdout -----
assert_eq!(
str::from_utf8(&output.get_output().stderr)?, ----- stderr -----
"warning: Encountered error: Permission denied (os error 13)\n" warning: Encountered error: Permission denied (os error 13)
); "###);
Ok(()) Ok(())
} }
@ -416,17 +382,22 @@ fn check_input_from_argfile() -> Result<()> {
format!("@{}", &input_file_path.display()), format!("@{}", &input_file_path.display()),
]; ];
let mut cmd = Command::cargo_bin(BIN_NAME)?; insta::with_settings!({filters => vec![
let output = cmd.args(args).write_stdin("").assert().failure(); (file_a_path.display().to_string().as_str(), "/path/to/a.py"),
assert_eq!( ]}, {
str::from_utf8(&output.get_output().stdout)?, assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
format!( .args(args)
"{}:1:8: F401 [*] `os` imported but unused .pass_stdin(""), @r###"
Found 1 error. success: false
[*] 1 potentially fixable with the --fix option. exit_code: 1
", ----- stdout -----
file_a_path.display() /path/to/a.py:1:8: F401 [*] `os` imported but unused
) Found 1 error.
); [*] 1 potentially fixable with the --fix option.
----- stderr -----
"###);
});
Ok(()) Ok(())
} }

View file

@ -0,0 +1,61 @@
---
source: crates/ruff_cli/tests/integration_test.rs
info:
program: ruff
args:
- "--explain"
- F401
---
success: true
exit_code: 0
----- stdout -----
# unused-import (F401)
Derived from the **Pyflakes** linter.
Autofix is sometimes available.
## What it does
Checks for unused imports.
## Why is this bad?
Unused imports add a performance overhead at runtime, and risk creating
import cycles. They also increase the cognitive load of reading the code.
If an import statement is used to check for the availability or existence
of a module, consider using `importlib.util.find_spec` instead.
## Example
```python
import numpy as np # unused import
def area(radius):
return 3.14 * radius**2
```
Use instead:
```python
def area(radius):
return 3.14 * radius**2
```
To check the availability of a module, use `importlib.util.find_spec`:
```python
from importlib.util import find_spec
if find_spec("numpy") is not None:
print("numpy is installed")
else:
print("numpy is not installed")
```
## Options
- `pyflakes.extend-generics`
## References
- [Python documentation: `import`](https://docs.python.org/3/reference/simple_stmts.html#the-import-statement)
- [Python documentation: `importlib.util.find_spec`](https://docs.python.org/3/library/importlib.html#importlib.util.find_spec)
----- stderr -----

View file

@ -0,0 +1,53 @@
---
source: crates/ruff_cli/tests/integration_test.rs
info:
program: ruff
args:
- "-"
- "--isolated"
- "--no-cache"
- "--format"
- json
- "--stdin-filename"
- F401.py
stdin: "import os\n"
---
success: false
exit_code: 1
----- stdout -----
[
{
"code": "F401",
"end_location": {
"column": 10,
"row": 1
},
"filename": "/path/to/F401.py",
"fix": {
"applicability": "Automatic",
"edits": [
{
"content": "",
"end_location": {
"column": 1,
"row": 2
},
"location": {
"column": 1,
"row": 1
}
}
],
"message": "Remove unused import: `os`"
},
"location": {
"column": 8,
"row": 1
},
"message": "`os` imported but unused",
"noqa_row": 1,
"url": "https://beta.ruff.rs/docs/rules/unused-import"
}
]
----- stderr -----