netsleuth/scripts/add_docstrings.py

57 lines
1.8 KiB
Python
Executable file

#!/usr/bin/env python3
"""Скрипт для поиска функций без docstrings."""
import ast
import sys
from pathlib import Path
class DocstringChecker(ast.NodeVisitor):
def __init__(self, filename: str):
self.filename = filename
self.missing = []
def visit_FunctionDef(self, node):
if not ast.get_docstring(node):
# Пропускаем приватные функции и дюндеры
if not node.name.startswith('_') or node.name in ('__init__', '__enter__', '__exit__'):
# Проверяем только публичные функции
if not node.name.startswith('_'):
self.missing.append((node.lineno, node.name))
self.generic_visit(node)
def visit_AsyncFunctionDef(self, node):
self.visit_FunctionDef(node)
def check_file(filepath: Path) -> list[tuple[int, str]]:
try:
source = filepath.read_text(encoding='utf-8')
tree = ast.parse(source)
checker = DocstringChecker(str(filepath))
checker.visit(tree)
return checker.missing
except Exception as e:
print(f"Error parsing {filepath}: {e}", file=sys.stderr)
return []
def main():
src_dir = Path('src/netsleuth')
total_missing = 0
for py_file in src_dir.glob('*.py'):
missing = check_file(py_file)
if missing:
print(f"\n{py_file.relative_to(Path.cwd())}:")
for lineno, funcname in missing:
print(f" Line {lineno}: {funcname}()")
total_missing += 1
print(f"\n{'='*50}")
print(f"Total functions missing docstrings: {total_missing}")
return 0 if total_missing == 0 else 1
if __name__ == '__main__':
sys.exit(main())