lint_py.rs
1 // Copyright (c) The Bitcoin Core developers 2 // Distributed under the MIT software license, see the accompanying 3 // file COPYING or https://opensource.org/license/mit/. 4 5 use std::io::ErrorKind; 6 use std::process::Command; 7 8 use crate::util::{check_output, get_pathspecs_default_excludes, git, LintResult}; 9 10 pub fn lint_py_lint() -> LintResult { 11 let bin_name = "ruff"; 12 let checks = format!( 13 "--select={}", 14 [ 15 "B006", // mutable-argument-default 16 "B008", // function-call-in-default-argument 17 "E101", // indentation contains mixed spaces and tabs 18 "E401", // multiple imports on one line 19 "E402", // module level import not at top of file 20 "E701", // multiple statements on one line (colon) 21 "E702", // multiple statements on one line (semicolon) 22 "E703", // statement ends with a semicolon 23 "E711", // comparison to None should be 'if cond is None:' 24 "E713", // test for membership should be "not in" 25 "E714", // test for object identity should be "is not" 26 "E721", // do not compare types, use "isinstance()" 27 "E722", // do not use bare 'except' 28 "E742", // do not define classes named "l", "O", or "I" 29 "E743", // do not define functions named "l", "O", or "I" 30 "F401", // module imported but unused 31 "F402", // import module from line N shadowed by loop variable 32 "F403", // 'from foo_module import *' used; unable to detect undefined names 33 "F404", // future import(s) name after other statements 34 "F405", // foo_function may be undefined, or defined from star imports: bar_module 35 "F406", // "from module import *" only allowed at module level 36 "F407", // an undefined __future__ feature name was imported 37 "F541", // f-string without any placeholders 38 "F601", // dictionary key name repeated with different values 39 "F602", // dictionary key variable name repeated with different values 40 "F621", // too many expressions in an assignment with star-unpacking 41 "F631", // assertion test is a tuple, which are always True 42 "F632", // use ==/!= to compare str, bytes, and int literals 43 "F811", // redefinition of unused name from line N 44 "F821", // undefined name 'Foo' 45 "F822", // undefined name name in __all__ 46 "F823", // local variable name … referenced before assignment 47 "F841", // local variable 'foo' is assigned to but never used 48 "PLE", // Pylint errors 49 "W191", // indentation contains tabs 50 "W291", // trailing whitespace 51 "W292", // no newline at end of file 52 "W293", // blank line contains whitespace 53 "W605", // invalid escape sequence "x" 54 ] 55 .join(",") 56 ); 57 let files = check_output( 58 git() 59 .args(["ls-files", "--", "*.py"]) 60 .args(get_pathspecs_default_excludes()), 61 )?; 62 63 let mut cmd = Command::new(bin_name); 64 cmd.args(["check", &checks]).args(files.lines()); 65 66 match cmd.status() { 67 Ok(status) if status.success() => Ok(()), 68 Ok(_) => Err(format!("`{bin_name}` found errors!")), 69 Err(e) if e.kind() == ErrorKind::NotFound => { 70 println!("`{bin_name}` was not found in $PATH, skipping those checks."); 71 Ok(()) 72 } 73 Err(e) => Err(format!("Error running `{bin_name}`: {e}")), 74 } 75 }