Skip to main content
Glama
project_analysis.py5.44 kB
import os import ast import re from pathlib import Path from typing import List, Dict, Tuple class ProjectAnalyzer: def __init__(self, project_root: str): self.project_root = Path(project_root) self.issues = [] self.file_stats = {} def analyze_file(self, filepath: Path) -> Dict: try: with open(filepath, 'r', encoding='utf-8') as f: content = f.read() lines = f.readlines() except: return {'error': 'Could not read file'} file_issues = [] # 1. 行长度检查 for i, line in enumerate(lines, 1): if len(line.rstrip()) > 100: file_issues.append(f'第{i}行过长: {len(line.rstrip())}字符') # 2. 异常处理检查 try: tree = ast.parse(content) for node in ast.walk(tree): if isinstance(node, ast.ExceptHandler): if node.type is None: file_issues.append(f'第{node.lineno}行使用裸except语句') elif isinstance(node.type, ast.Name) and node.type.id == 'Exception': file_issues.append(f'第{node.lineno}行捕获过于宽泛的异常') except: file_issues.append('语法错误,无法解析AST') # 3. 函数复杂度检查 try: tree = ast.parse(content) for node in ast.walk(tree): if isinstance(node, ast.FunctionDef): complexity = 1 for child in ast.walk(node): if isinstance(child, (ast.If, ast.For, ast.While, ast.With, ast.ExceptHandler)): complexity += 1 if complexity > 10: file_issues.append(f'函数 {node.name} 圈复杂度过高: {complexity}') except: pass return { 'path': str(filepath), 'lines': len(lines), 'issues': file_issues, 'issue_count': len(file_issues) } def analyze_project(self) -> Dict: total_files = 0 total_lines = 0 total_issues = 0 # 遍历Python文件 for root, dirs, files in os.walk(self.project_root): # 跳过虚拟环境和缓存目录 dirs[:] = [d for d in dirs if d not in ['__pycache__', '.git', 'venv', 'mcp-env']] for file in files: if file.endswith('.py'): filepath = Path(root) / file total_files += 1 # 分析文件 result = self.analyze_file(filepath) if 'error' not in result: total_lines += result['lines'] total_issues += result['issue_count'] # 保存详细信息 relative_path = str(filepath.relative_to(self.project_root)) self.file_stats[relative_path] = result # 添加到总问题列表 for issue in result['issues']: self.issues.append(f"{relative_path}: {issue}") return { 'total_files': total_files, 'total_lines': total_lines, 'total_issues': total_issues, 'files_with_issues': len([f for f in self.file_stats.values() if f['issue_count'] > 0]) } def generate_report(self) -> str: # 分析项目 stats = self.analyze_project() report = [] report.append("=" * 60) report.append("项目代码质量分析报告") report.append("=" * 60) report.append(f"总文件数: {stats['total_files']}") report.append(f"总代码行数: {stats['total_lines']}") report.append(f"总问题数: {stats['total_issues']}") report.append(f"有问题的文件数: {stats['files_with_issues']}") report.append(f"平均每文件问题数: {stats['total_issues']/stats['total_files']:.1f}") report.append("") # 按问题数排序显示文件 sorted_files = sorted( self.file_stats.items(), key=lambda x: x[1]['issue_count'], reverse=True ) report.append("文件问题排行榜 (前10个):") report.append("-" * 40) for i, (filename, stats) in enumerate(sorted_files[:10], 1): report.append(f"{i:2d}. {filename} ({stats['issue_count']}个问题, {stats['lines']}行)") report.append("") report.append("详细问题列表:") report.append("-" * 40) # 显示前50个问题 for i, issue in enumerate(self.issues[:50], 1): report.append(f"{i:3d}. {issue}") if len(self.issues) > 50: report.append(f"... 还有{len(self.issues)-50}个问题未显示") return "\n".join(report) if __name__ == "__main__": analyzer = ProjectAnalyzer("src") report = analyzer.generate_report() print(report) # 保存报告到文件 with open("project_quality_report.txt", "w", encoding="utf-8") as f: f.write(report)

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/kscz0000/Zhiwen-Assistant-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server