|
|
""" |
|
|
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']}") |