Download ast_analyzer.py from usman-ai-dev/ai-code-maintainability-engine: direct link, hf CLI and curl.
- Browser
- Download file 4.58 kB
-
https://huggingface.co/spaces/usman-ai-dev/ai-code-maintainability-engine/resolve/main/ast_analyzer.py
- Command line
-
hf download hf://spaces/usman-ai-dev/ai-code-maintainability-engine/ast_analyzer.py
-
curl -L -o ast_analyzer.py https://huggingface.co/spaces/usman-ai-dev/ai-code-maintainability-engine/resolve/main/ast_analyzer.py
4.58 kB
| import ast | |
| import os | |
| def _get_max_nesting_depth(tree): | |
| NESTING_NODES = ( | |
| ast.If, | |
| ast.For, | |
| ast.While, | |
| ast.With, | |
| ast.Try, | |
| ast.FunctionDef, | |
| ast.AsyncFunctionDef, | |
| ast.ClassDef, | |
| ) | |
| def _walk_depth(node, current_depth): | |
| max_depth = current_depth | |
| for child in ast.iter_child_nodes(node): | |
| if isinstance(child, NESTING_NODES): | |
| child_depth = _walk_depth(child, current_depth + 1) | |
| max_depth = max(max_depth, child_depth) | |
| else: | |
| child_depth = _walk_depth(child, current_depth) | |
| max_depth = max(max_depth, child_depth) | |
| return max_depth | |
| return _walk_depth(tree, 0) | |
| def _get_cyclomatic_complexity(tree): | |
| complexity = 1 | |
| for node in ast.walk(tree): | |
| if isinstance(node, ( | |
| ast.If, | |
| ast.For, | |
| ast.While, | |
| ast.ExceptHandler, | |
| ast.With, | |
| ast.Assert, | |
| )): | |
| complexity += 1 | |
| if isinstance(node, ast.BoolOp): | |
| complexity += len(node.values) - 1 | |
| return complexity | |
| def _get_avg_function_length(tree): | |
| function_lengths = [] | |
| for node in ast.walk(tree): | |
| if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)): | |
| if hasattr(node, 'end_lineno') and hasattr(node, 'lineno'): | |
| length = node.end_lineno - node.lineno + 1 | |
| function_lengths.append(length) | |
| if not function_lengths: | |
| return 0 | |
| return sum(function_lengths) / len(function_lengths) | |
| def _check_recursion(tree): | |
| for node in ast.walk(tree): | |
| if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)): | |
| func_name = node.name | |
| for inner_node in ast.walk(node): | |
| if isinstance(inner_node, ast.Call): | |
| if isinstance(inner_node.func, ast.Name): | |
| if inner_node.func.id == func_name: | |
| return 1 | |
| return 0 | |
| def _count_global_variables(tree): | |
| global_count = 0 | |
| for node in ast.walk(tree): | |
| if isinstance(node, ast.Global): | |
| global_count += len(node.names) | |
| return global_count | |
| def extract_features(source): | |
| if os.path.isfile(source): | |
| with open(source, 'r', encoding='utf-8') as f: | |
| code = f.read() | |
| else: | |
| code = source | |
| try: | |
| tree = ast.parse(code) | |
| except SyntaxError as e: | |
| return { | |
| "error": True, | |
| "message": f"Syntax error in code: {e.msg}", | |
| "line": e.lineno, | |
| } | |
| num_functions = 0 | |
| num_loops = 0 | |
| num_if = 0 | |
| num_try_except = 0 | |
| num_return = 0 | |
| for node in ast.walk(tree): | |
| if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)): | |
| num_functions += 1 | |
| elif isinstance(node, (ast.For, ast.While)): | |
| num_loops += 1 | |
| elif isinstance(node, ast.If): | |
| num_if += 1 | |
| elif isinstance(node, ast.Try): | |
| num_try_except += 1 | |
| elif isinstance(node, ast.Return): | |
| num_return += 1 | |
| line_count = len(code.splitlines()) | |
| max_nesting_depth = _get_max_nesting_depth(tree) | |
| cyclomatic_complexity = _get_cyclomatic_complexity(tree) | |
| avg_function_length = _get_avg_function_length(tree) | |
| recursion_flag = _check_recursion(tree) | |
| global_variable_count = _count_global_variables(tree) | |
| features = { | |
| "num_functions": num_functions, | |
| "num_loops": num_loops, | |
| "num_if": num_if, | |
| "num_try_except": num_try_except, | |
| "num_return": num_return, | |
| "line_count": line_count, | |
| "max_nesting_depth": max_nesting_depth, | |
| "cyclomatic_complexity":cyclomatic_complexity, | |
| "avg_function_length": round(avg_function_length, 2), | |
| "recursion_flag": recursion_flag, | |
| "global_variable_count":global_variable_count, | |
| } | |
| return features | |
| if __name__ == "__main__": | |
| sample_code = "def sample():\n pass" | |
| result = extract_features(sample_code) | |
| print("=" * 50) | |
| print(" AST Feature Extraction Results") | |
| print("=" * 50) | |
| for feature, value in result.items(): | |
| print(f" {feature:<25} : {value}") | |
| print("=" * 50) | |