A Python lint tool
main()
The Py7 script invokes main()(Listing 2) automatically unless you do not include source code files as CLI parameters (if there are no parameters, Py7 exits with an error). It reports the Py7 tool version information and then checks for additional CLI parameters. If a help parameter (-h or --help) is present, then usage() is called, with a normal exit.
Listing 2
main()
01 def main():
02 print("")
03 version()
04 print("")
05
06 if len(sys.argv) == 2 and sys.argv[1] in ('-h', '--help'):
07 usage()
08 sys.exit(0)
09
10 if len(sys.argv) < 2:
11 print(":: ")
12 print(":: Error: No Python files given to check!")
13 print(":: ")
14 usage()
15 sys.exit(1)
16
17 check_modules() # check for and install required modules
18
19 print("::")
20 print(":: Beginning Py7 Lint")
21 print("::")
22 print(" ")
23 for i in range(1, len(sys.argv)):
24 print("\n::--- ... ---::\n")
25 run_lint_tests(sys.argv[i])
26 print(" ")
27 print("::")
28 print(":: Completed Py7 Lint")
29 print("::")
30 input("\nPress any key to continue...\n")
31 sys.exit(0)
The main() function then checks that the various modules are installed in the Python environment by calling check_modules() (line 17) each time Py7 is run.
Then in lines 19-31, main() runs the various lint tools against the Python source code files given as CLI parameters. After checking and verifying the modules are available, main then iterates over the CLI parameters, which are each Python source code file selected for linting. Each file is then passed to run_lint_tets to lint the code.
check_modules()
The check_modules() function (Listing 3) uses a list of the modules, PY_MOD_LIST, which is defined as a global attribute; check_modules() uses a for loop to iterate over PY_MOD_LIST. The find_spec function in the importlib module checks to see if the module exists.
Listing 3
check_modules
01 def main():
02 print("")
03 version()
04 print("")
05
06 if len(sys.argv) == 2 and sys.argv[1] in ('-h', '--help'):
07 usage()
08 sys.exit(0)
09
10 if len(sys.argv) < 2:
11 print(":: ")
12 print(":: Error: No Python files given to check!")
13 print(":: ")
14 usage()
15 sys.exit(1)
16
17 check_modules() # check for and install required modules
18
19 print("::")
20 print(":: Beginning Py7 Lint")
21 print("::")
22 print(" ")
23 for i in range(1, len(sys.argv)):
24 print("\n::--- ... ---::\n")
25 run_lint_tests(sys.argv[i])
26 print(" ")
27 print("::")
28 print(":: Completed Py7 Lint")
29 print("::")
30 input("\nPress any key to continue...\n")
31 sys.exit(0)01 def check_modules():
02 print("#")
03 print("# Python Linter Tool Script ", __release__)
04 print("# ")
05 print("# Checking for required Python modules...")
06 print("#")
07 for package in PY_MOD_LIST:
08 print(" ")
09 has_mod = importlib.util.find_spec(package)
10 if has_mod:
11 print(f' #:>The {package} module exists.')
12 else:
13 print(f' #:>The {package} module absent.')
14 tmp_argv = sys.argv
15 sys.argv = ["pip", "install"] + [ package ]
16 try:
17 run_module("pip", run_name="__main__")
18 except SystemExit as exception:
19 print("exit code: ", exception.code)
20 if exception.code != 0 :
21 print(":: ")
22 print(f':: Error: The {package} module NOT installed; end tests!')
23 print(":: ")
24 sys.exit(2)
25 sys.argv = tmp_argv
26 print(" #:> ")
27 print(f' #:>The {package} module installed.')
28 print(" #:> ")
29 print("")
30 input("\nPress any key to continue...\n")
31 print("")
If a module is not found when using check_modules, the module is then installed using run_module() in the runpy module within a try statement. First, the system CLI arguments are stored, and then the module to be installed is set as an argument.
The run_module function then invokes the pip module with the __main__ function. The original Py7 tool simply executed pip as a sub-process, but that caused problems in later versions of Python.
The return code from the pip module __main__ function is checked with the exception object of the try statement. If the return code is anything except zero, then the Py7 tool reports an error and exits, because Py7 cannot run without all the tools installed.
run_lint_tests()
After the lint tools are verified as installed, main() runs each test on each Python source file. Using a for loop, each file listed as a CLI parameter is passed in a call to run_lint_tests() (Listing 4) on the Python source code file.
Listing 4
run_lint_tests()
01 def main():
02 print("")
03 version()
04 print("")
05
06 if len(sys.argv) == 2 and sys.argv[1] in ('-h', '--help'):
07 usage()
08 sys.exit(0)
09
10 if len(sys.argv) < 2:
11 print(":: ")
12 print(":: Error: No Python files given to check!")
13 print(":: ")
14 usage()
15 sys.exit(1)
16
17 check_modules() # check for and install required modules
18
19 print("::")
20 print(":: Beginning Py7 Lint")
21 print("::")
22 print(" ")
23 for i in range(1, len(sys.argv)):
24 print("\n::--- ... ---::\n")
25 run_lint_tests(sys.argv[i])
26 print(" ")
27 print("::")
28 print(":: Completed Py7 Lint")
29 print("::")
30 input("\nPress any key to continue...\n")
31 sys.exit(0)01 def check_modules():
02 print("#")
03 print("# Python Linter Tool Script ", __release__)
04 print("# ")
05 print("# Checking for required Python modules...")
06 print("#")
07 for package in PY_MOD_LIST:
08 print(" ")
09 has_mod = importlib.util.find_spec(package)
10 if has_mod:
11 print(f' #:>The {package} module exists.')
12 else:
13 print(f' #:>The {package} module absent.')
14 tmp_argv = sys.argv
15 sys.argv = ["pip", "install"] + [ package ]
16 try:
17 run_module("pip", run_name="__main__")
18 except SystemExit as exception:
19 print("exit code: ", exception.code)
20 if exception.code != 0 :
21 print(":: ")
22 print(f':: Error: The {package} module NOT installed; end tests!')
23 print(":: ")
24 sys.exit(2)
25 sys.argv = tmp_argv
26 print(" #:> ")
27 print(f' #:>The {package} module installed.')
28 print(" #:> ")
29 print("")
30 input("\nPress any key to continue...\n")
31 print("")01 def run_lint_tests(file): #25-LOC
02 for py_mod in PY_MOD_LIST:
03 has_file = os.path.isfile(file)
04 if not has_file:
05 print(":: ")
06 print(f':: Error: File {file} not found; end tests!')
07 print(":: ")
08 return
09 if py_mod == "mccabe":
10 cmd = py_mod + '--min ' + MCCABE_MIN + ' ' + file
11 else:
12 cmd = py_mod + ' ' + file
13 print(" ::>")
14 print(f' ::> {py_mod} on file: {file}')
15 print(" ::>")
16 result = run(cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True,
17 shell=True, check=False)
18 if len(result.stdout) == 0:
19 print(" ::> ")
20 print(" ::> [\nNo problems detected.", "\n ::> ]")
21 print(" ::> ")
22 else:
23 print(" ::> ")
24 print(" ::> [\n", result.stdout, "\n ::> ]")
25 print(" ::> ")
The run_lint_tests() function uses a for loop to iterate over PY_MOD_LIST and invokes each test on the Python source file, capturing the output that is reported to the user. If the Python source file does not exist, the function returns. For the McCabe lint check, the McCabe complexity's artificial CLI parameter is created using the Python script attribute MCCABE_MIN, which sets the minimum McCabe complexity threshold for an error in the check.
« Previous 1 2 3 4 Next »
Buy this article as PDF
(incl. VAT)
Buy Linux Magazine
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters
Support Our Work
Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.
News
-
CIQ Releases Compatibility Catalog for Rocky Linux
The company behind Rocky Linux is making an open catalog available to developers, hobbyists, and other contributors, so they can verify and publish compatibility with the CIQ lineup.
-
KDE Gets Some Resuscitation
KDE is bringing back two themes that vanished a few years ago, putting a bit more air under its wings.
-
Ubuntu 26.04 Beta Arrives with Some Surprises
Ubuntu 26.04 is almost here, but the beta version has been released, and it might surprise some people.
-
Ubuntu MATE Dev Leaving After 12 years
Martin Wimpress, the maintainer of Ubuntu MATE, is now searching for his successor. Are you the next in line?
-
Kali Linux Waxes Nostalgic with BackTrack Mode
For those who've used Kali Linux since its inception, the changes with the new release are sure to put a smile on your face.
-
Gnome 50 Smooths Out NVIDIA GPU Issues
Gamers rejoice, your favorite pastime just got better with Gnome 50 and NVIDIA GPUs.
-
System76 Retools Thelio Desktop
The new Thelio Mira has landed with improved performance, repairability, and front-facing ports alongside a high-quality tempered glass facade.
-
Some Linux Distros Skirt Age Verification Laws
After California introduced an age verification law recently, open source operating system developers have had to get creative with how they deal with it.
-
UN Creates Open Source Portal
In a quest to strengthen open source collaboration, the United Nations Office of Information and Communications Technology has created a new portal.
-
Latest Linux Kernel RC Contains Changes Galore
Linux kernel 7.0-rc3 includes more changes than have been made in a single release in recent history.
