From fa578d9434fdb090d27c7b5598dcd7f0ff0965cc Mon Sep 17 00:00:00 2001 From: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> Date: Thu, 18 Dec 2025 12:25:00 +0100 Subject: [PATCH] lint: [move-only] Move python related lints to lint_py.rs --- test/lint/test_runner/src/lint_py.rs | 75 ++++++++++++++++++++++++++++ test/lint/test_runner/src/main.rs | 75 ++-------------------------- 2 files changed, 78 insertions(+), 72 deletions(-) create mode 100644 test/lint/test_runner/src/lint_py.rs 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 00000000000..d9177c86907 --- /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 ba774238f28..fa69d2b5f9a 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");