prelington commited on
Commit
482a3e4
·
verified ·
1 Parent(s): ff17dd4

Create code_analyzer.py

Browse files
Files changed (1) hide show
  1. code_analyzer.py +224 -0
code_analyzer.py ADDED
@@ -0,0 +1,224 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ PyPilot Code Analyzer - Advanced static analysis and quality metrics
3
+ """
4
+ import ast
5
+ import astor
6
+ import radon
7
+ from radon import metrics, complexity
8
+ from radon.visitors import ComplexityVisitor
9
+ import lizard
10
+ import tempfile
11
+ import subprocess
12
+ import os
13
+
14
+ class PyPilotCodeAnalyzer:
15
+ def __init__(self):
16
+ self.analysis_results = {}
17
+
18
+ def comprehensive_analysis(self, code_string):
19
+ """Perform comprehensive code analysis"""
20
+ analysis = {}
21
+
22
+ try:
23
+ # Parse AST
24
+ tree = ast.parse(code_string)
25
+ analysis['ast_info'] = self.analyze_ast(tree)
26
+
27
+ # Code metrics
28
+ analysis['metrics'] = self.calculate_metrics(code_string)
29
+
30
+ # Complexity analysis
31
+ analysis['complexity'] = self.analyze_complexity(code_string)
32
+
33
+ # Security checks
34
+ analysis['security'] = self.security_scan(code_string)
35
+
36
+ # Code quality
37
+ analysis['quality'] = self.quality_assessment(code_string)
38
+
39
+ except Exception as e:
40
+ analysis['error'] = str(e)
41
+
42
+ return analysis
43
+
44
+ def analyze_ast(self, tree):
45
+ """Analyze Abstract Syntax Tree"""
46
+ ast_info = {
47
+ 'imports': [],
48
+ 'functions': [],
49
+ 'classes': [],
50
+ 'variables': [],
51
+ 'structure': {}
52
+ }
53
+
54
+ for node in ast.walk(tree):
55
+ if isinstance(node, ast.Import):
56
+ for alias in node.names:
57
+ ast_info['imports'].append(alias.name)
58
+ elif isinstance(node, ast.ImportFrom):
59
+ ast_info['imports'].append(f"from {node.module}")
60
+ elif isinstance(node, ast.FunctionDef):
61
+ ast_info['functions'].append({
62
+ 'name': node.name,
63
+ 'args': [arg.arg for arg in node.args.args],
64
+ 'lineno': node.lineno
65
+ })
66
+ elif isinstance(node, ast.ClassDef):
67
+ ast_info['classes'].append({
68
+ 'name': node.name,
69
+ 'bases': [base.id for base in node.bases if hasattr(base, 'id')],
70
+ 'lineno': node.lineno
71
+ })
72
+ elif isinstance(node, ast.Assign):
73
+ for target in node.targets:
74
+ if hasattr(target, 'id'):
75
+ ast_info['variables'].append(target.id)
76
+
77
+ return ast_info
78
+
79
+ def calculate_metrics(self, code_string):
80
+ """Calculate comprehensive code metrics"""
81
+ with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
82
+ f.write(code_string)
83
+ temp_file = f.name
84
+
85
+ try:
86
+ # Use lizard for advanced metrics
87
+ analysis = lizard.analyze_file(temp_file)
88
+
89
+ metrics = {
90
+ 'lines_of_code': analysis.nloc,
91
+ 'token_count': analysis.token_count,
92
+ 'function_count': len(analysis.function_list),
93
+ 'average_complexity': analysis.average_cyclomatic_complexity,
94
+ 'maintainability_index': analysis.maintainability_index,
95
+ }
96
+
97
+ # Function-level metrics
98
+ functions_metrics = []
99
+ for func in analysis.function_list:
100
+ functions_metrics.append({
101
+ 'name': func.name,
102
+ 'complexity': func.cyclomatic_complexity,
103
+ 'lines': func.length,
104
+ 'parameters': func.parameter_count
105
+ })
106
+
107
+ metrics['functions'] = functions_metrics
108
+
109
+ finally:
110
+ os.unlink(temp_file)
111
+
112
+ return metrics
113
+
114
+ def analyze_complexity(self, code_string):
115
+ """Analyze code complexity using radon"""
116
+ try:
117
+ cc = complexity.cc_visit(code_string)
118
+ complexity_data = []
119
+
120
+ for block in cc:
121
+ complexity_data.append({
122
+ 'name': block.name,
123
+ 'complexity': block.complexity,
124
+ 'type': block.type,
125
+ 'lineno': block.lineno
126
+ })
127
+
128
+ mi = metrics.mi_visit(code_string, True)
129
+
130
+ return {
131
+ 'cyclomatic_complexity': complexity_data,
132
+ 'maintainability_index': mi,
133
+ 'halstead_metrics': metrics.h_visit(code_string)
134
+ }
135
+ except Exception as e:
136
+ return {'error': str(e)}
137
+
138
+ def security_scan(self, code_string):
139
+ """Basic security vulnerability scan"""
140
+ vulnerabilities = []
141
+
142
+ security_patterns = [
143
+ ('eval', 'Use of eval() function'),
144
+ ('exec', 'Use of exec() function'),
145
+ ('pickle.loads', 'Unsafe deserialization'),
146
+ ('os.system', 'Potential command injection'),
147
+ ('subprocess.call', 'Potential command injection'),
148
+ ]
149
+
150
+ for pattern, description in security_patterns:
151
+ if pattern in code_string:
152
+ vulnerabilities.append({
153
+ 'type': 'security',
154
+ 'description': description,
155
+ 'severity': 'high'
156
+ })
157
+
158
+ return vulnerabilities
159
+
160
+ def quality_assessment(self, code_string):
161
+ """Assess code quality"""
162
+ quality_score = 100
163
+
164
+ # Check for common issues
165
+ issues = []
166
+
167
+ if len(code_string) > 1000:
168
+ issues.append("File is too long")
169
+ quality_score -= 10
170
+
171
+ if code_string.count('\n') > 50:
172
+ issues.append("Too many lines")
173
+ quality_score -= 5
174
+
175
+ # Check for commented code
176
+ if code_string.count('#') > code_string.count('\n') * 0.3:
177
+ issues.append("Too many comments")
178
+ quality_score -= 5
179
+
180
+ return {
181
+ 'quality_score': max(quality_score, 0),
182
+ 'issues': issues,
183
+ 'recommendations': self.generate_recommendations(issues)
184
+ }
185
+
186
+ def generate_recommendations(self, issues):
187
+ """Generate improvement recommendations"""
188
+ recommendations = []
189
+
190
+ issue_solutions = {
191
+ "File is too long": "Consider breaking into smaller functions or modules",
192
+ "Too many lines": "Refactor into smaller, focused functions",
193
+ "Too many comments": "Ensure comments are meaningful and not redundant"
194
+ }
195
+
196
+ for issue in issues:
197
+ if issue in issue_solutions:
198
+ recommendations.append(issue_solutions[issue])
199
+
200
+ return recommendations
201
+
202
+ if __name__ == "__main__":
203
+ analyzer = PyPilotCodeAnalyzer()
204
+
205
+ # Test with sample code
206
+ sample_code = """
207
+ def calculate_factorial(n):
208
+ if n == 0:
209
+ return 1
210
+ else:
211
+ return n * calculate_factorial(n-1)
212
+
213
+ def main():
214
+ print(calculate_factorial(5))
215
+
216
+ if __name__ == "__main__":
217
+ main()
218
+ """
219
+
220
+ results = analyzer.comprehensive_analysis(sample_code)
221
+ print("🔍 Code Analysis Results:")
222
+ print(f"Functions: {results['ast_info']['functions']}")
223
+ print(f"Metrics: {results['metrics']}")
224
+ print(f"Quality Score: {results['quality']['quality_score']}")