huang_de_jun commited on
Commit
f44fd20
·
1 Parent(s): 70be908

feat: poc for code complexity analyser

Browse files
Files changed (6) hide show
  1. .gitignore +50 -0
  2. .python-version +1 -0
  3. README.md +94 -1
  4. app.py +271 -0
  5. pyproject.toml +9 -0
  6. uv.lock +0 -0
.gitignore ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ develop-eggs/
9
+ dist/
10
+ downloads/
11
+ eggs/
12
+ .eggs/
13
+ lib/
14
+ lib64/
15
+ parts/
16
+ sdist/
17
+ var/
18
+ wheels/
19
+ *.egg-info/
20
+ .installed.cfg
21
+ *.egg
22
+
23
+ # Virtual Environment
24
+ venv/
25
+ env/
26
+ ENV/
27
+ .venv
28
+
29
+ # IDE
30
+ .vscode/
31
+ .idea/
32
+ *.swp
33
+ *.swo
34
+ *~
35
+
36
+ # OS
37
+ .DS_Store
38
+ Thumbs.db
39
+
40
+ # Logs
41
+ *.log
42
+
43
+ # Testing
44
+ .pytest_cache/
45
+ .coverage
46
+ htmlcov/
47
+
48
+ # Gradio
49
+ gradio_cached_examples/
50
+ flagged/
.python-version ADDED
@@ -0,0 +1 @@
 
 
1
+ 3.13
README.md CHANGED
@@ -11,4 +11,97 @@ license: mit
11
  short_description: An MCP Server to analyse Python code complexity
12
  ---
13
 
14
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  short_description: An MCP Server to analyse Python code complexity
12
  ---
13
 
14
+ # Code Complexity Analyzer MCP Server
15
+
16
+ **Category**: Enterprise MCP Server
17
+ **Tags**: `building-mcp-track-enterprise`
18
+
19
+ ## Overview
20
+
21
+ An MCP server that analyzes Python code complexity and provides actionable insights about code quality, maintainability, and potential refactoring opportunities.
22
+
23
+ ## Features
24
+
25
+ ### 1. Cyclomatic Complexity Analysis
26
+ - Calculates cyclomatic complexity metric
27
+ - Provides complexity level assessment (Low/Moderate/High/Critical)
28
+ - Offers specific refactoring recommendations
29
+
30
+ ### 2. Code Metrics
31
+ - Lines of Code (LOC)
32
+ - Source Lines of Code (SLOC)
33
+ - Comment lines and ratio
34
+ - Function and class counts
35
+ - Comment-to-code ratio analysis
36
+
37
+ ### 3. Code Smell Detection
38
+ - Long functions (>50 lines)
39
+ - Too many parameters (>5)
40
+ - Deep nesting (>4 levels)
41
+ - Duplicate code detection
42
+
43
+ ### 4. Comprehensive Analysis
44
+ - Combined report with all metrics
45
+ - Markdown-formatted output
46
+ - Clear recommendations
47
+
48
+ ## Installation
49
+
50
+ ```bash
51
+ pip install "gradio[mcp]"
52
+ ```
53
+
54
+ ## Usage
55
+
56
+ ### Running the MCP Server
57
+
58
+ ```bash
59
+ python server.py
60
+ ```
61
+
62
+ The server will start on `http://0.0.0.0:7860` with MCP protocol enabled.
63
+
64
+ ### MCP Tools Available
65
+
66
+ 1. `full_code_analysis` - Complete code analysis with all metrics
67
+ 2. `calculate_cyclomatic_complexity` - Complexity calculation only
68
+ 3. `analyze_code_metrics` - Code metrics only
69
+ 4. `detect_code_smells` - Code smell detection only
70
+
71
+ ### Example Usage
72
+
73
+ ```python
74
+ # Example code to analyze
75
+ code = """
76
+ def complex_function(a, b, c, d, e, f):
77
+ if a > 0:
78
+ if b > 0:
79
+ if c > 0:
80
+ if d > 0:
81
+ if e > 0:
82
+ return a + b + c + d + e + f
83
+ return 0
84
+ """
85
+ ```
86
+
87
+ ## Why This Matters
88
+
89
+ - **For Teams**: Maintain code quality standards across projects
90
+ - **For Developers**: Get immediate feedback on code complexity
91
+ - **For Code Reviews**: Automated complexity assessment
92
+ - **For Legacy Code**: Identify refactoring priorities
93
+
94
+ ## Technical Details
95
+
96
+ - Built with Gradio MCP server capabilities
97
+ - AST-based Python code analysis
98
+ - Real-time complexity calculation
99
+ - No external dependencies for analysis
100
+
101
+ ## Future Enhancements
102
+
103
+ - Support for more programming languages
104
+ - Integration with CI/CD pipelines
105
+ - Historical complexity tracking
106
+ - Custom complexity thresholds
107
+ - Team-wide analytics dashboard
app.py ADDED
@@ -0,0 +1,271 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Code Complexity Analyzer MCP Server
3
+
4
+ This MCP server analyzes Python code complexity and provides insights
5
+ about code quality, maintainability, and potential refactoring opportunities.
6
+
7
+ Tags: building-mcp-track-enterprise
8
+ """
9
+
10
+ import ast
11
+ import re
12
+ from typing import Dict, List, Tuple
13
+ import gradio as gr
14
+
15
+
16
+ def calculate_cyclomatic_complexity(code: str) -> Dict[str, any]:
17
+ """
18
+ Calculate cyclomatic complexity of Python code.
19
+
20
+ Args:
21
+ code: Python source code as a string
22
+
23
+ Returns:
24
+ Dictionary with complexity metrics
25
+ """
26
+ try:
27
+ tree = ast.parse(code)
28
+ except SyntaxError as e:
29
+ return {"error": f"Syntax error in code: {str(e)}"}
30
+
31
+ complexity = 1 # Base complexity
32
+
33
+ # Count decision points that increase complexity
34
+ for node in ast.walk(tree):
35
+ if isinstance(node, (ast.If, ast.While, ast.For, ast.ExceptHandler)):
36
+ complexity += 1
37
+ elif isinstance(node, ast.BoolOp):
38
+ complexity += len(node.values) - 1
39
+ elif isinstance(node, (ast.ListComp, ast.DictComp, ast.SetComp, ast.GeneratorExp)):
40
+ complexity += 1
41
+
42
+ # Determine complexity level
43
+ if complexity <= 10:
44
+ level = "Low (Simple)"
45
+ recommendation = "Code is easy to understand and maintain."
46
+ elif complexity <= 20:
47
+ level = "Moderate"
48
+ recommendation = "Consider breaking into smaller functions."
49
+ elif complexity <= 50:
50
+ level = "High"
51
+ recommendation = "Refactoring strongly recommended. Break into smaller, focused functions."
52
+ else:
53
+ level = "Very High (Critical)"
54
+ recommendation = "Immediate refactoring required. Code is difficult to test and maintain."
55
+
56
+ return {
57
+ "cyclomatic_complexity": complexity,
58
+ "complexity_level": level,
59
+ "recommendation": recommendation
60
+ }
61
+
62
+
63
+ def analyze_code_metrics(code: str) -> Dict[str, any]:
64
+ """
65
+ Analyze various code metrics including LOC, functions, classes, etc.
66
+
67
+ Args:
68
+ code: Python source code as a string
69
+
70
+ Returns:
71
+ Dictionary with code metrics
72
+ """
73
+ try:
74
+ tree = ast.parse(code)
75
+ except SyntaxError as e:
76
+ return {"error": f"Syntax error in code: {str(e)}"}
77
+
78
+ lines = code.split('\n')
79
+ loc = len(lines)
80
+
81
+ # Count non-empty, non-comment lines
82
+ sloc = sum(1 for line in lines if line.strip() and not line.strip().startswith('#'))
83
+
84
+ # Count comments
85
+ comments = sum(1 for line in lines if line.strip().startswith('#'))
86
+
87
+ # Count functions and classes
88
+ functions = sum(1 for node in ast.walk(tree) if isinstance(node, ast.FunctionDef))
89
+ classes = sum(1 for node in ast.walk(tree) if isinstance(node, ast.ClassDef))
90
+
91
+ # Calculate comment ratio
92
+ comment_ratio = (comments / sloc * 100) if sloc > 0 else 0
93
+
94
+ return {
95
+ "lines_of_code": loc,
96
+ "source_lines_of_code": sloc,
97
+ "comment_lines": comments,
98
+ "comment_ratio_percent": round(comment_ratio, 2),
99
+ "functions": functions,
100
+ "classes": classes
101
+ }
102
+
103
+
104
+ def detect_code_smells(code: str) -> List[str]:
105
+ """
106
+ Detect common code smells in Python code.
107
+
108
+ Args:
109
+ code: Python source code as a string
110
+
111
+ Returns:
112
+ List of detected code smells
113
+ """
114
+ smells = []
115
+
116
+ try:
117
+ tree = ast.parse(code)
118
+ except SyntaxError:
119
+ return ["Syntax error prevents analysis"]
120
+
121
+ # Check for long functions (>50 lines)
122
+ for node in ast.walk(tree):
123
+ if isinstance(node, ast.FunctionDef):
124
+ if hasattr(node, 'end_lineno') and hasattr(node, 'lineno'):
125
+ func_lines = node.end_lineno - node.lineno
126
+ if func_lines > 50:
127
+ smells.append(f"Long function '{node.name}' ({func_lines} lines)")
128
+
129
+ # Check for too many parameters
130
+ if isinstance(node, ast.FunctionDef):
131
+ param_count = len(node.args.args)
132
+ if param_count > 5:
133
+ smells.append(f"Function '{node.name}' has too many parameters ({param_count})")
134
+
135
+ # Check for deeply nested code (>4 levels)
136
+ if isinstance(node, (ast.If, ast.For, ast.While)):
137
+ depth = sum(1 for parent in ast.walk(tree)
138
+ if isinstance(parent, (ast.If, ast.For, ast.While)))
139
+ if depth > 4:
140
+ smells.append("Deeply nested code blocks detected")
141
+ break
142
+
143
+ # Check for duplicate code patterns (simple check)
144
+ lines = [line.strip() for line in code.split('\n') if line.strip()]
145
+ if len(lines) != len(set(lines)):
146
+ duplicate_count = len(lines) - len(set(lines))
147
+ if duplicate_count > 3:
148
+ smells.append(f"Possible duplicate code: {duplicate_count} duplicate lines")
149
+
150
+ if not smells:
151
+ smells.append("No obvious code smells detected!")
152
+
153
+ return smells
154
+
155
+
156
+ def full_code_analysis(code: str) -> str:
157
+ """
158
+ Perform complete code analysis combining all metrics.
159
+
160
+ Args:
161
+ code: Python source code as a string
162
+
163
+ Returns:
164
+ Formatted analysis report
165
+ """
166
+ if not code.strip():
167
+ return "Please provide Python code to analyze."
168
+
169
+ complexity = calculate_cyclomatic_complexity(code)
170
+ metrics = analyze_code_metrics(code)
171
+ smells = detect_code_smells(code)
172
+
173
+ # Build report
174
+ report = "# Code Analysis Report\n\n"
175
+
176
+ # Complexity section
177
+ report += "## Complexity Analysis\n"
178
+ if "error" in complexity:
179
+ report += f"Error: {complexity['error']}\n\n"
180
+ else:
181
+ report += f"- **Cyclomatic Complexity**: {complexity['cyclomatic_complexity']}\n"
182
+ report += f"- **Complexity Level**: {complexity['complexity_level']}\n"
183
+ report += f"- **Recommendation**: {complexity['recommendation']}\n\n"
184
+
185
+ # Metrics section
186
+ report += "## Code Metrics\n"
187
+ if "error" in metrics:
188
+ report += f"Error: {metrics['error']}\n\n"
189
+ else:
190
+ report += f"- **Total Lines**: {metrics['lines_of_code']}\n"
191
+ report += f"- **Source Lines**: {metrics['source_lines_of_code']}\n"
192
+ report += f"- **Comment Lines**: {metrics['comment_lines']}\n"
193
+ report += f"- **Comment Ratio**: {metrics['comment_ratio_percent']}%\n"
194
+ report += f"- **Functions**: {metrics['functions']}\n"
195
+ report += f"- **Classes**: {metrics['classes']}\n\n"
196
+
197
+ # Code smells section
198
+ report += "## Code Smells Detected\n"
199
+ for smell in smells:
200
+ report += f"- {smell}\n"
201
+
202
+ return report
203
+
204
+
205
+ # Create Gradio interface
206
+ with gr.Blocks(title="Code Complexity Analyzer MCP Server") as demo:
207
+ gr.Markdown("""
208
+ # Code Complexity Analyzer MCP Server
209
+
210
+ Analyze Python code complexity and quality metrics. This MCP server provides:
211
+ - Cyclomatic complexity calculation
212
+ - Code metrics (LOC, comments, functions, classes)
213
+ - Code smell detection
214
+ - Refactoring recommendations
215
+
216
+ **Category**: Enterprise MCP Server
217
+ **Tags**: building-mcp-track-enterprise
218
+ """)
219
+
220
+ with gr.Tab("Full Analysis"):
221
+ code_input = gr.Code(
222
+ label="Python Code",
223
+ language="python",
224
+ lines=20,
225
+ value="# Paste your Python code here\ndef example():\n pass"
226
+ )
227
+ analyze_btn = gr.Button("Analyze Code", variant="primary")
228
+ analysis_output = gr.Markdown(label="Analysis Report")
229
+
230
+ analyze_btn.click(
231
+ fn=full_code_analysis,
232
+ inputs=code_input,
233
+ outputs=analysis_output
234
+ )
235
+
236
+ with gr.Tab("Complexity Only"):
237
+ complexity_input = gr.Code(label="Python Code", language="python", lines=15)
238
+ complexity_btn = gr.Button("Calculate Complexity")
239
+ complexity_output = gr.JSON(label="Complexity Metrics")
240
+
241
+ complexity_btn.click(
242
+ fn=calculate_cyclomatic_complexity,
243
+ inputs=complexity_input,
244
+ outputs=complexity_output
245
+ )
246
+
247
+ with gr.Tab("Code Metrics"):
248
+ metrics_input = gr.Code(label="Python Code", language="python", lines=15)
249
+ metrics_btn = gr.Button("Analyze Metrics")
250
+ metrics_output = gr.JSON(label="Code Metrics")
251
+
252
+ metrics_btn.click(
253
+ fn=analyze_code_metrics,
254
+ inputs=metrics_input,
255
+ outputs=metrics_output
256
+ )
257
+
258
+ with gr.Tab("Code Smells"):
259
+ smells_input = gr.Code(label="Python Code", language="python", lines=15)
260
+ smells_btn = gr.Button("Detect Code Smells")
261
+ smells_output = gr.JSON(label="Detected Code Smells")
262
+
263
+ smells_btn.click(
264
+ fn=detect_code_smells,
265
+ inputs=smells_input,
266
+ outputs=smells_output
267
+ )
268
+
269
+
270
+ if __name__ == "__main__":
271
+ demo.launch(mcp_server=True, server_name="0.0.0.0", server_port=7860)
pyproject.toml ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ [project]
2
+ name = "code-complexity-analyzer"
3
+ version = "0.1.0"
4
+ description = "Add your description here"
5
+ readme = "README.md"
6
+ requires-python = ">=3.13"
7
+ dependencies = [
8
+ "gradio[mcp]>=5.49.1",
9
+ ]
uv.lock ADDED
The diff for this file is too large to render. See raw diff