lint: [move-only] Move python related lints to lint_py.rs
What changed, and why it matters
This commit simply moves existing Python linting code from one file to another without changing what it does. It is a code cleanup change with no security relevance.
No security action required. Treat as normal code-maintenance review.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit is a pure refactor: the lint_py_lint() function and its ruff check configuration are relocated from test/lint/test_runner/src/main.rs into a new module test/lint/test_runner/src/lint_py.rs. The function body, the list of ruff rules, and the invocation logic are byte-for-byte identical. No functional changes were made to the lint runner or to any Bitcoin Core runtime code.
Changed components
test/lint/test_runner/src/main.rstest/lint/test_runner/src/lint_py.rsInspect captured patch +78 / −72
diff --git a/test/lint/test_runner/src/lint_py.rs b/test/lint/test_runner/src/lint_py.rs
new file mode 100644
index 00000000..d9177c86
--- /dev/null
+++ b/test/lint/test_runner/src/lint_py.rs
@@ -0,0 +1,75 @@
+// Copyright (c) The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or https://opensource.org/license/mit/.
+
+use std::io::ErrorKind;
+use std::process::Command;
+
+use crate::util::{check_output, get_pathspecs_default_excludes, git, LintResult};
+
+pub fn lint_py_lint() -> LintResult {
+ let bin_name = "ruff";
+ let checks = format!(
+ "--select={}",
+ [
+ "B006", // mutable-argument-default
+ "B008", // function-call-in-default-argument
+ "E101", // indentation contains mixed spaces and tabs
+ "E401", // multiple imports on one line
+ "E402", // module level import not at top of file
+ "E701", // multiple statements on one line (colon)
+ "E702", // multiple statements on one line (semicolon)
+ "E703", // statement ends with a semicolon
+ "E711", // comparison to None should be 'if cond is None:'
+ "E713", // test for membership should be "not in"
+ "E714", // test for object identity should be "is not"
+ "E721", // do not compare types, use "isinstance()"
+ "E722", // do not use bare 'except'
+ "E742", // do not define classes named "l", "O", or "I"
+ "E743", // do not define functions named "l", "O", or "I"
+ "F401", // module imported but unused
+ "F402", // import module from line N shadowed by loop variable
+ "F403", // 'from foo_module import *' used; unable to detect undefined names
+ "F404", // future import(s) name after other statements
+ "F405", // foo_function may be undefined, or defined from star imports: bar_module
+ "F406", // "from module import *" only allowed at module level
+ "F407", // an undefined __future__ feature name was imported
+ "F541", // f-string without any placeholders
+ "F601", // dictionary key name repeated with different values
+ "F602", // dictionary key variable name repeated with different values
+ "F621", // too many expressions in an assignment with star-unpacking
+ "F631", // assertion test is a tuple, which are always True
+ "F632", // use ==/!= to compare str, bytes, and int literals
+ "F811", // redefinition of unused name from line N
+ "F821", // undefined name 'Foo'
+ "F822", // undefined name name in __all__
+ "F823", // local variable name … referenced before assignment
+ "F841", // local variable 'foo' is assigned to but never used
+ "PLE", // Pylint errors
+ "W191", // indentation contains tabs
+ "W291", // trailing whitespace
+ "W292", // no newline at end of file
+ "W293", // blank line contains whitespace
+ "W605", // invalid escape sequence "x"
+ ]
+ .join(",")
+ );
+ let files = check_output(
+ git()
+ .args(["ls-files", "--", "*.py"])
+ .args(get_pathspecs_default_excludes()),
+ )?;
+
+ let mut cmd = Command::new(bin_name);
+ cmd.args(["check", &checks]).args(files.lines());
+
+ match cmd.status() {
+ Ok(status) if status.success() => Ok(()),
+ Ok(_) => Err(format!("`{bin_name}` found errors!")),
+ Err(e) if e.kind() == ErrorKind::NotFound => {
+ println!("`{bin_name}` was not found in $PATH, skipping those checks.");
+ Ok(())
+ }
+ Err(e) => Err(format!("Error running `{bin_name}`: {e}")),
+ }
+}
diff --git a/test/lint/test_runner/src/main.rs b/test/lint/test_runner/src/main.rs
index ba774238..fa69d2b5 100644
--- a/test/lint/test_runner/src/main.rs
+++ b/test/lint/test_runner/src/main.rs
@@ -4,27 +4,25 @@
mod lint_cpp;
mod lint_docs;
+mod lint_py;
mod lint_repo_hygiene;
mod lint_text_format;
mod util;
use std::env;
use std::fs;
-use std::io::ErrorKind;
use std::process::{Command, ExitCode};
use lint_cpp::{
lint_boost_assert, lint_includes_build_config, lint_rpc_assert, lint_std_filesystem,
};
use lint_docs::{lint_doc_args, lint_doc_release_note_snippets, lint_markdown};
+use lint_py::lint_py_lint;
use lint_repo_hygiene::{lint_scripted_diff, lint_subtree};
use lint_text_format::{
lint_commit_msg, lint_tabs_whitespace, lint_trailing_newline, lint_trailing_whitespace,
};
-use util::{
- check_output, commit_range, get_git_root, get_pathspecs_default_excludes, git, LintFn,
- LintResult,
-};
+use util::{check_output, commit_range, get_git_root, git, LintFn, LintResult};
struct Linter {
pub description: &'static str,
@@ -168,73 +166,6 @@ fn parse_lint_args(args: &[String]) -> Vec<&'static Linter> {
lint_values
}
-fn lint_py_lint() -> LintResult {
- let bin_name = "ruff";
- let checks = format!(
- "--select={}",
- [
- "B006", // mutable-argument-default
- "B008", // function-call-in-default-argument
- "E101", // indentation contains mixed spaces and tabs
- "E401", // multiple imports on one line
- "E402", // module level import not at top of file
- "E701", // multiple statements on one line (colon)
- "E702", // multiple statements on one line (semicolon)
- "E703", // statement ends with a semicolon
- "E711", // comparison to None should be 'if cond is None:'
- "E713", // test for membership should be "not in"
- "E714", // test for object identity should be "is not"
- "E721", // do not compare types, use "isinstance()"
- "E722", // do not use bare 'except'
- "E742", // do not define classes named "l", "O", or "I"
- "E743", // do not define functions named "l", "O", or "I"
- "F401", // module imported but unused
- "F402", // import module from line N shadowed by loop variable
- "F403", // 'from foo_module import *' used; unable to detect undefined names
- "F404", // future import(s) name after other statements
- "F405", // foo_function may be undefined, or defined from star imports: bar_module
- "F406", // "from module import *" only allowed at module level
- "F407", // an undefined __future__ feature name was imported
- "F541", // f-string without any placeholders
- "F601", // dictionary key name repeated with different values
- "F602", // dictionary key variable name repeated with different values
- "F621", // too many expressions in an assignment with star-unpacking
- "F631", // assertion test is a tuple, which are always True
- "F632", // use ==/!= to compare str, bytes, and int literals
- "F811", // redefinition of unused name from line N
- "F821", // undefined name 'Foo'
- "F822", // undefined name name in __all__
- "F823", // local variable name … referenced before assignment
- "F841", // local variable 'foo' is assigned to but never used
- "PLE", // Pylint errors
- "W191", // indentation contains tabs
- "W291", // trailing whitespace
- "W292", // no newline at end of file
- "W293", // blank line contains whitespace
- "W605", // invalid escape sequence "x"
- ]
- .join(",")
- );
- let files = check_output(
- git()
- .args(["ls-files", "--", "*.py"])
- .args(get_pathspecs_default_excludes()),
- )?;
-
- let mut cmd = Command::new(bin_name);
- cmd.args(["check", &checks]).args(files.lines());
-
- match cmd.status() {
- Ok(status) if status.success() => Ok(()),
- Ok(_) => Err(format!("`{bin_name}` found errors!")),
- Err(e) if e.kind() == ErrorKind::NotFound => {
- println!("`{bin_name}` was not found in $PATH, skipping those checks.");
- Ok(())
- }
- Err(e) => Err(format!("Error running `{bin_name}`: {e}")),
- }
-}
-
fn run_all_python_linters() -> LintResult {
let mut good = true;
let lint_dir = get_git_root().join("test/lint");
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.