| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950 |
- #!/usr/bin/env python3
- import ast
- import concurrent.futures
- import pathlib
- import sys
- EXCLUDE_DIRS = {".git", "venv", ".venv"}
- def find_python_files(root="."):
- for path in pathlib.Path(root).rglob("*.py"):
- if any(part in EXCLUDE_DIRS for part in path.parts):
- continue
- yield path
- def check_file(path):
- try:
- source = path.read_text(encoding="utf-8")
- ast.parse(source, filename=str(path))
- return path, None
- except SyntaxError as error:
- location = f"line {error.lineno}, col {error.offset}"
- return path, f"{location}: {error.msg}"
- except UnicodeDecodeError as error:
- return path, f"encoding error: {error}"
- def main():
- files = sorted(find_python_files())
- if not files:
- print("No Python files found.")
- return 0
- status = 0
- with concurrent.futures.ThreadPoolExecutor() as executor:
- results = executor.map(check_file, files)
- for path, error in results:
- if error:
- print(f"Syntax error in: {path}")
- print(f" {error}")
- status = 1
- print(f"Checked {len(files)} Python file(s).")
- return status
- if __name__ == "__main__":
- sys.exit(main())
|