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",
"linked-hash-map",
"regex",
"serde",
"similar",
"walkdir",
"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]]
name = "instant"
version = "0.1.12"
@ -2169,6 +2181,7 @@ dependencies = [
"glob",
"ignore",
"insta",
"insta-cmd",
"is-macro",
"itertools",
"itoa",

View file

@ -70,7 +70,10 @@ wild = { version = "2" }
[dev-dependencies]
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-cmd = { version = "0.4.0" }
tempfile = "3.6.0"
ureq = { version = "2.6.2", features = [] }

View file

@ -1,15 +1,15 @@
#![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::path::{Path, PathBuf};
use std::process::Stdio;
use std::process::{Command, Stdio};
use std::thread::sleep;
use std::time::Duration;
use std::{fs, process, str};
use anyhow::{anyhow, Context, Result};
use assert_cmd::Command;
use anyhow::{anyhow, bail, Context, Result};
use insta_cmd::get_cargo_bin;
use log::info;
use walkdir::WalkDir;
@ -29,13 +29,14 @@ impl Blackd {
// Get free TCP port to run on
let address = TcpListener::bind(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 0))?.local_addr()?;
let server = process::Command::new("blackd")
.args([
"--bind-host",
&address.ip().to_string(),
"--bind-port",
&address.port().to_string(),
])
let args = [
"--bind-host",
&address.ip().to_string(),
"--bind-port",
&address.port().to_string(),
];
let server = Command::new("blackd")
.args(args)
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()
@ -51,16 +52,16 @@ impl Blackd {
Err(e) => return Err(e.into()),
Ok(_) => {
info!("`blackd` ready");
break;
return Ok(Self {
address,
server,
client: ureq::agent(),
});
}
}
}
Ok(Self {
address,
server,
client: ureq::agent(),
})
bail!("blackd {:?} failed to start", args)
}
/// 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)?;
// 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)
.write_stdin(input)
.assert()
.append_context("step", "running input through ruff");
if !step_1.get_output().status.success() {
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()?;
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!(
"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.
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.
let step_3 = &Command::cargo_bin(BIN_NAME)?
let mut step_3 = Command::new(get_cargo_bin(BIN_NAME))
.args(ruff_args)
.write_stdin(step_2_output.clone())
.assert();
if !step_3.get_output().status.success() {
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.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!(
"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!(
str::from_utf8(&step_2_output),
@ -177,11 +186,13 @@ fn test_ruff_black_compatibility() -> Result<()> {
"--fix",
"--line-length",
"88",
"--select ALL",
"--select",
"ALL",
// 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
// newline, and ruff removes the `# noqa: W292` again.
"--ignore RUF",
"--ignore",
"RUF",
];
for entry in paths {

View file

@ -8,14 +8,15 @@ use std::fs::Permissions;
use std::os::unix::fs::{OpenOptionsExt, PermissionsExt};
#[cfg(unix)]
use std::path::Path;
use std::process::Command;
use std::str;
#[cfg(unix)]
use anyhow::Context;
use anyhow::Result;
use assert_cmd::Command;
#[cfg(unix)]
use clap::Parser;
use insta_cmd::{assert_cmd_snapshot, get_cargo_bin};
#[cfg(unix)]
use path_absolutize::path_dedot;
#[cfg(unix)]
@ -27,315 +28,280 @@ use ruff_cli::args::Args;
use ruff_cli::run;
const BIN_NAME: &str = "ruff";
const STDIN_BASE_OPTIONS: &[&str] = &["--isolated", "--no-cache", "-", "--format", "text"];
#[test]
fn stdin_success() -> Result<()> {
let mut cmd = Command::cargo_bin(BIN_NAME)?;
cmd.args(["-", "--format", "text", "--isolated"])
.write_stdin("")
.assert()
.success();
Ok(())
fn stdin_success() {
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(STDIN_BASE_OPTIONS)
.pass_stdin(""), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
"###);
}
#[test]
fn stdin_error() -> Result<()> {
let mut cmd = Command::cargo_bin(BIN_NAME)?;
let output = cmd
.args(["-", "--format", "text", "--isolated"])
.write_stdin("import os\n")
.assert()
.failure();
assert_eq!(
str::from_utf8(&output.get_output().stdout)?,
r#"-:1:8: F401 [*] `os` imported but unused
Found 1 error.
[*] 1 potentially fixable with the --fix option.
"#
);
Ok(())
fn stdin_error() {
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(STDIN_BASE_OPTIONS)
.pass_stdin("import os\n"), @r#"
success: false
exit_code: 1
----- stdout -----
-:1:8: F401 [*] `os` imported but unused
Found 1 error.
[*] 1 potentially fixable with the --fix option.
----- stderr -----
"#);
}
#[test]
fn stdin_filename() -> Result<()> {
let mut cmd = Command::cargo_bin(BIN_NAME)?;
let output = cmd
.args([
"-",
"--format",
"text",
"--stdin-filename",
"F401.py",
"--isolated",
])
.write_stdin("import os\n")
.assert()
.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(())
fn stdin_filename() {
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(STDIN_BASE_OPTIONS)
.args(["--stdin-filename", "F401.py"])
.pass_stdin("import os\n"), @r###"
success: false
exit_code: 1
----- stdout -----
F401.py:1:8: F401 [*] `os` imported but unused
Found 1 error.
[*] 1 potentially fixable with the --fix option.
----- stderr -----
"###);
}
#[test]
fn stdin_source_type() -> Result<()> {
// Raise `TCH` errors in `.py` files.
let mut cmd = Command::cargo_bin(BIN_NAME)?;
let output = cmd
.args([
"-",
"--format",
"text",
"--stdin-filename",
"TCH.py",
"--isolated",
])
.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.
"#
);
/// Raise `TCH` errors in `.py` files ...
fn stdin_source_type_py() {
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(STDIN_BASE_OPTIONS)
.args(["--stdin-filename", "TCH.py"])
.pass_stdin("import os\n"), @r###"
success: false
exit_code: 1
----- stdout -----
TCH.py:1:8: F401 [*] `os` imported but unused
Found 1 error.
[*] 1 potentially fixable with the --fix option.
// But not in `.pyi` files.
let mut cmd = Command::cargo_bin(BIN_NAME)?;
cmd.args([
"-",
"--format",
"text",
"--stdin-filename",
"TCH.pyi",
"--isolated",
"--select",
"TCH",
])
.write_stdin("import os\n")
.assert()
.success();
Ok(())
----- stderr -----
"###);
}
/// ... but not in `.pyi` files.
#[test]
fn stdin_source_type_pyi() {
let args = ["--stdin-filename", "TCH.pyi", "--select", "TCH"];
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(STDIN_BASE_OPTIONS)
.args(args)
.pass_stdin("import os\n"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
"###);
}
#[cfg(unix)]
#[test]
fn stdin_json() -> Result<()> {
let mut cmd = Command::cargo_bin(BIN_NAME)?;
let output = cmd
.args([
"-",
"--format",
"json",
"--stdin-filename",
"F401.py",
"--isolated",
])
.write_stdin("import os\n")
.assert()
.failure();
fn stdin_json() {
let args = [
"-",
"--isolated",
"--no-cache",
"--format",
"json",
"--stdin-filename",
"F401.py",
];
let directory = path_dedot::CWD.to_str().unwrap();
let binding = Path::new(directory).join("F401.py");
let file_path = binding.display();
assert_eq!(
str::from_utf8(&output.get_output().stdout)?,
format!(
r#"[
{{
"code": "F401",
"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(())
insta::with_settings!({filters => vec![
(file_path.to_string().as_str(), "/path/to/F401.py"),
]}, {
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(args)
.pass_stdin("import os\n"));
});
}
#[test]
fn stdin_autofix() -> Result<()> {
let mut cmd = Command::cargo_bin(BIN_NAME)?;
let output = cmd
.args(["-", "--format", "text", "--fix", "--isolated"])
.write_stdin("import os\nimport sys\n\nprint(sys.version)\n")
.assert()
.success();
assert_eq!(
str::from_utf8(&output.get_output().stdout)?,
"import sys\n\nprint(sys.version)\n"
);
Ok(())
fn stdin_autofix() {
let args = ["--fix"];
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(STDIN_BASE_OPTIONS)
.args(args)
.pass_stdin("import os\nimport sys\n\nprint(sys.version)\n"), @r###"
success: true
exit_code: 0
----- stdout -----
import sys
print(sys.version)
----- stderr -----
"###);
}
#[test]
fn stdin_autofix_when_not_fixable_should_still_print_contents() -> Result<()> {
let mut cmd = Command::cargo_bin(BIN_NAME)?;
let output = cmd
.args(["-", "--format", "text", "--fix", "--isolated"])
.write_stdin("import os\nimport sys\n\nif (1, 2):\n print(sys.version)\n")
.assert()
.failure();
assert_eq!(
str::from_utf8(&output.get_output().stdout)?,
"import sys\n\nif (1, 2):\n print(sys.version)\n"
);
Ok(())
fn stdin_autofix_when_not_fixable_should_still_print_contents() {
let args = ["--fix"];
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(STDIN_BASE_OPTIONS)
.args(args)
.pass_stdin("import os\nimport sys\n\nif (1, 2):\n print(sys.version)\n"), @r###"
success: false
exit_code: 1
----- stdout -----
import sys
if (1, 2):
print(sys.version)
----- stderr -----
"###);
}
#[test]
fn stdin_autofix_when_no_issues_should_still_print_contents() -> Result<()> {
let mut cmd = Command::cargo_bin(BIN_NAME)?;
let output = cmd
.args(["-", "--format", "text", "--fix", "--isolated"])
.write_stdin("import sys\n\nprint(sys.version)\n")
.assert()
.success();
assert_eq!(
str::from_utf8(&output.get_output().stdout)?,
"import sys\n\nprint(sys.version)\n"
);
Ok(())
fn stdin_autofix_when_no_issues_should_still_print_contents() {
let args = ["--fix"];
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(STDIN_BASE_OPTIONS)
.args(args)
.pass_stdin("import sys\n\nprint(sys.version)\n"), @r###"
success: true
exit_code: 0
----- stdout -----
import sys
print(sys.version)
----- stderr -----
"###);
}
#[test]
fn show_source() -> Result<()> {
let mut cmd = Command::cargo_bin(BIN_NAME)?;
let output = cmd
.args(["-", "--format", "text", "--show-source", "--isolated"])
.write_stdin("l = 1")
.assert()
.failure();
assert!(str::from_utf8(&output.get_output().stdout)?.contains("l = 1"));
Ok(())
fn show_source() {
let args = ["--show-source"];
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(STDIN_BASE_OPTIONS)
.args(args)
.pass_stdin("l = 1"), @r###"
success: false
exit_code: 1
----- stdout -----
-:1:1: E741 Ambiguous variable name: `l`
|
1 | l = 1
| ^ E741
|
Found 1 error.
----- stderr -----
"###);
}
#[test]
fn explain_status_codes() -> Result<()> {
let mut cmd = Command::cargo_bin(BIN_NAME)?;
cmd.args(["--explain", "F401"]).assert().success();
let mut cmd = Command::cargo_bin(BIN_NAME)?;
cmd.args(["--explain", "RUF404"]).assert().failure();
Ok(())
fn explain_status_codes_f401() {
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)).args(["--explain", "F401"]));
}
#[test]
fn explain_status_codes_ruf404() {
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]
fn show_statistics() -> Result<()> {
let mut cmd = Command::cargo_bin(BIN_NAME)?;
let output = cmd
.args([
"-",
"--format",
"text",
"--select",
"F401",
"--statistics",
"--isolated",
])
.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(())
fn show_statistics() {
let args = ["--select", "F401", "--statistics"];
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(STDIN_BASE_OPTIONS)
.args(args)
.pass_stdin("import sys\nimport os\n\nprint(os.getuid())\n"), @r###"
success: false
exit_code: 1
----- stdout -----
1 F401 [*] `sys` imported but unused
----- stderr -----
"###);
}
#[test]
fn nursery_prefix() -> Result<()> {
let mut cmd = Command::cargo_bin(BIN_NAME)?;
fn nursery_prefix() {
// `--select E` should detect E741, but not E225, which is in the nursery.
let output = cmd
.args(["-", "--format", "text", "--isolated", "--select", "E"])
.write_stdin("I=42\n")
.assert()
.failure();
assert_eq!(
str::from_utf8(&output.get_output().stdout)?,
r#"-:1:1: E741 Ambiguous variable name: `I`
Found 1 error.
"#
);
let args = ["--select", "E"];
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(STDIN_BASE_OPTIONS)
.args(args)
.pass_stdin("I=42\n"), @r###"
success: false
exit_code: 1
----- stdout -----
-:1:1: E741 Ambiguous variable name: `I`
Found 1 error.
Ok(())
----- stderr -----
"###);
}
#[test]
fn nursery_all() -> Result<()> {
let mut cmd = Command::cargo_bin(BIN_NAME)?;
fn nursery_all() {
// `--select ALL` should detect E741, but not E225, which is in the nursery.
let output = cmd
.args(["-", "--format", "text", "--isolated", "--select", "E"])
.write_stdin("I=42\n")
.assert()
.failure();
assert_eq!(
str::from_utf8(&output.get_output().stdout)?,
r#"-:1:1: E741 Ambiguous variable name: `I`
Found 1 error.
"#
);
let args = ["--select", "ALL"];
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(STDIN_BASE_OPTIONS)
.args(args)
.pass_stdin("I=42\n"), @r###"
success: false
exit_code: 1
----- stdout -----
-: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]
fn nursery_direct() -> Result<()> {
let mut cmd = Command::cargo_bin(BIN_NAME)?;
fn nursery_direct() {
// `--select E225` should detect E225.
let output = cmd
.args(["-", "--format", "text", "--isolated", "--select", "E225"])
.write_stdin("I=42\n")
.assert()
.failure();
assert_eq!(
str::from_utf8(&output.get_output().stdout)?,
r#"-:1:2: E225 Missing whitespace around operator
Found 1 error.
"#
);
let args = ["--select", "E225"];
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(STDIN_BASE_OPTIONS)
.args(args)
.pass_stdin("I=42\n"), @r###"
success: false
exit_code: 1
----- stdout -----
-: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
@ -376,17 +342,17 @@ fn unreadable_dir() -> Result<()> {
// We (currently?) have to use a subcommand to check exit status (currently wrong) and logging
// output
let mut cmd = Command::cargo_bin(BIN_NAME)?;
let output = cmd
// TODO(konstin): This should be a failure, but we currently can't track that
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(["--no-cache", "--isolated"])
.arg(&unreadable_dir)
.assert()
// TODO(konstin): This should be a failure, but we currently can't track that
.success();
assert_eq!(
str::from_utf8(&output.get_output().stderr)?,
"warning: Encountered error: Permission denied (os error 13)\n"
);
.arg(&unreadable_dir), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: Encountered error: Permission denied (os error 13)
"###);
Ok(())
}
@ -416,17 +382,22 @@ fn check_input_from_argfile() -> Result<()> {
format!("@{}", &input_file_path.display()),
];
let mut cmd = Command::cargo_bin(BIN_NAME)?;
let output = cmd.args(args).write_stdin("").assert().failure();
assert_eq!(
str::from_utf8(&output.get_output().stdout)?,
format!(
"{}:1:8: F401 [*] `os` imported but unused
Found 1 error.
[*] 1 potentially fixable with the --fix option.
",
file_a_path.display()
)
);
insta::with_settings!({filters => vec![
(file_a_path.display().to_string().as_str(), "/path/to/a.py"),
]}, {
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(args)
.pass_stdin(""), @r###"
success: false
exit_code: 1
----- stdout -----
/path/to/a.py:1:8: F401 [*] `os` imported but unused
Found 1 error.
[*] 1 potentially fixable with the --fix option.
----- stderr -----
"###);
});
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 -----