| """ |
| PyPilot Code Analyzer - Advanced static analysis and quality metrics |
| """ |
| import ast |
| import astor |
| import radon |
| from radon import metrics, complexity |
| from radon.visitors import ComplexityVisitor |
| import lizard |
| import tempfile |
| import subprocess |
| import os |
|
|
| class PyPilotCodeAnalyzer: |
| def __init__(self): |
| self.analysis_results = {} |
| |
| def comprehensive_analysis(self, code_string): |
| """Perform comprehensive code analysis""" |
| analysis = {} |
| |
| try: |
| |
| tree = ast.parse(code_string) |
| analysis['ast_info'] = self.analyze_ast(tree) |
| |
| |
| analysis['metrics'] = self.calculate_metrics(code_string) |
| |
| |
| analysis['complexity'] = self.analyze_complexity(code_string) |
| |
| |
| analysis['security'] = self.security_scan(code_string) |
| |
| |
| analysis['quality'] = self.quality_assessment(code_string) |
| |
| except Exception as e: |
| analysis['error'] = str(e) |
| |
| return analysis |
| |
| def analyze_ast(self, tree): |
| """Analyze Abstract Syntax Tree""" |
| ast_info = { |
| 'imports': [], |
| 'functions': [], |
| 'classes': [], |
| 'variables': [], |
| 'structure': {} |
| } |
| |
| for node in ast.walk(tree): |
| if isinstance(node, ast.Import): |
| for alias in node.names: |
| ast_info['imports'].append(alias.name) |
| elif isinstance(node, ast.ImportFrom): |
| ast_info['imports'].append(f"from {node.module}") |
| elif isinstance(node, ast.FunctionDef): |
| ast_info['functions'].append({ |
| 'name': node.name, |
| 'args': [arg.arg for arg in node.args.args], |
| 'lineno': node.lineno |
| }) |
| elif isinstance(node, ast.ClassDef): |
| ast_info['classes'].append({ |
| 'name': node.name, |
| 'bases': [base.id for base in node.bases if hasattr(base, 'id')], |
| 'lineno': node.lineno |
| }) |
| elif isinstance(node, ast.Assign): |
| for target in node.targets: |
| if hasattr(target, 'id'): |
| ast_info['variables'].append(target.id) |
| |
| return ast_info |
| |
| def calculate_metrics(self, code_string): |
| """Calculate comprehensive code metrics""" |
| with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f: |
| f.write(code_string) |
| temp_file = f.name |
| |
| try: |
| |
| analysis = lizard.analyze_file(temp_file) |
| |
| metrics = { |
| 'lines_of_code': analysis.nloc, |
| 'token_count': analysis.token_count, |
| 'function_count': len(analysis.function_list), |
| 'average_complexity': analysis.average_cyclomatic_complexity, |
| 'maintainability_index': analysis.maintainability_index, |
| } |
| |
| |
| functions_metrics = [] |
| for func in analysis.function_list: |
| functions_metrics.append({ |
| 'name': func.name, |
| 'complexity': func.cyclomatic_complexity, |
| 'lines': func.length, |
| 'parameters': func.parameter_count |
| }) |
| |
| metrics['functions'] = functions_metrics |
| |
| finally: |
| os.unlink(temp_file) |
| |
| return metrics |
| |
| def analyze_complexity(self, code_string): |
| """Analyze code complexity using radon""" |
| try: |
| cc = complexity.cc_visit(code_string) |
| complexity_data = [] |
| |
| for block in cc: |
| complexity_data.append({ |
| 'name': block.name, |
| 'complexity': block.complexity, |
| 'type': block.type, |
| 'lineno': block.lineno |
| }) |
| |
| mi = metrics.mi_visit(code_string, True) |
| |
| return { |
| 'cyclomatic_complexity': complexity_data, |
| 'maintainability_index': mi, |
| 'halstead_metrics': metrics.h_visit(code_string) |
| } |
| except Exception as e: |
| return {'error': str(e)} |
| |
| def security_scan(self, code_string): |
| """Basic security vulnerability scan""" |
| vulnerabilities = [] |
| |
| security_patterns = [ |
| ('eval', 'Use of eval() function'), |
| ('exec', 'Use of exec() function'), |
| ('pickle.loads', 'Unsafe deserialization'), |
| ('os.system', 'Potential command injection'), |
| ('subprocess.call', 'Potential command injection'), |
| ] |
| |
| for pattern, description in security_patterns: |
| if pattern in code_string: |
| vulnerabilities.append({ |
| 'type': 'security', |
| 'description': description, |
| 'severity': 'high' |
| }) |
| |
| return vulnerabilities |
| |
| def quality_assessment(self, code_string): |
| """Assess code quality""" |
| quality_score = 100 |
| |
| |
| issues = [] |
| |
| if len(code_string) > 1000: |
| issues.append("File is too long") |
| quality_score -= 10 |
| |
| if code_string.count('\n') > 50: |
| issues.append("Too many lines") |
| quality_score -= 5 |
| |
| |
| if code_string.count('#') > code_string.count('\n') * 0.3: |
| issues.append("Too many comments") |
| quality_score -= 5 |
| |
| return { |
| 'quality_score': max(quality_score, 0), |
| 'issues': issues, |
| 'recommendations': self.generate_recommendations(issues) |
| } |
| |
| def generate_recommendations(self, issues): |
| """Generate improvement recommendations""" |
| recommendations = [] |
| |
| issue_solutions = { |
| "File is too long": "Consider breaking into smaller functions or modules", |
| "Too many lines": "Refactor into smaller, focused functions", |
| "Too many comments": "Ensure comments are meaningful and not redundant" |
| } |
| |
| for issue in issues: |
| if issue in issue_solutions: |
| recommendations.append(issue_solutions[issue]) |
| |
| return recommendations |
|
|
| if __name__ == "__main__": |
| analyzer = PyPilotCodeAnalyzer() |
| |
| |
| sample_code = """ |
| def calculate_factorial(n): |
| if n == 0: |
| return 1 |
| else: |
| return n * calculate_factorial(n-1) |
| |
| def main(): |
| print(calculate_factorial(5)) |
| |
| if __name__ == "__main__": |
| main() |
| """ |
| |
| results = analyzer.comprehensive_analysis(sample_code) |
| print("🔍 Code Analysis Results:") |
| print(f"Functions: {results['ast_info']['functions']}") |
| print(f"Metrics: {results['metrics']}") |
| print(f"Quality Score: {results['quality']['quality_score']}") |