Für diejenigen unter euch, die wie ich diese Einschätzung teilen, habe ich ein Skript geschrieben, dass das aktuelle Verzeichnis nach Python-Modulen mit diesem Code Smell durchsucht und die entsprechenden Dateinamen mit Zeilennummern ausgibt:
Code: Alles auswählen
#! /usr/bin/env python
"""Find for- and while-loops with else clauses."""
from ast import For, Module, While, parse, walk
from logging import getLogger
from pathlib import Path
from typing import Iterator
import os
LOGGER = getLogger(__file__)
def loops(module: Module) -> Iterator[For | While]:
"""Yield loop nodes of the given module."""
for node in walk(module):
if isinstance(node, (For, While)):
yield node
def load_module(filename: Path) -> Module:
"""Load an AST Module from the given file."""
with filename.open('r') as file:
return parse(file.read())
def iter_files(root: Path) -> Iterator[Path]:
"""Recursively iterate over all files in the root directory."""
for base_dir, _, files in os.walk(root):
base_dir = Path(base_dir)
for file in files:
yield base_dir / file
def python_modules(root: Path) -> Iterator[tuple[Path, Module]]:
"""Recursively yield file names and Python modules
loaded from files within the given root directory.
"""
for filename in filter(lambda f: f.suffix == '.py', iter_files(root)):
try:
module = load_module(filename)
except PermissionError:
LOGGER.error('Insufficient permissions to read: %s', filename)
except SyntaxError:
LOGGER.error('Invalid syntax in: %s', filename)
else:
yield filename, module
def main():
"""Run the program."""
for filename, module in python_modules(Path.cwd()):
for loop_with_else in filter(lambda loop: loop.orelse, loops(module)):
print(filename, loop_with_else.lineno, sep=': ')
if __name__ == '__main__':
main()