# parser.py import ast def get_category(node): """ Determine the category of an AST node based on its type. """ if isinstance(node, (ast.Import, ast.ImportFrom)): return 'import' elif isinstance(node, (ast.Assign, ast.AnnAssign, ast.AugAssign)): return 'assignment' elif isinstance(node, ast.FunctionDef): return 'function' elif isinstance(node, ast.AsyncFunctionDef): return 'async_function' elif isinstance(node, ast.ClassDef): return 'class' elif isinstance(node, ast.Expr): return 'expression' else: return 'other' def parse_python_file(file_path): """ Parse a Python file and return a list of its parts with categories, source code, and locations. Args: file_path (str): Path to the Python file to parse. Returns: list: A list of dictionaries, each containing 'category', 'source', and 'location'. """ with open(file_path, 'r') as file: code = file.read() lines = code.splitlines(keepends=True) tree = ast.parse(code) parts = [] prev_end = 0 for stmt in tree.body: start_line = stmt.lineno end_line = getattr(stmt, 'end_lineno', start_line) if start_line > prev_end + 1: spacer_lines = lines[prev_end:start_line - 1] parts.append({ 'category': 'spacer', 'source': ''.join(spacer_lines), 'location': (prev_end + 1, start_line - 1) }) stmt_lines = lines[start_line - 1:end_line] parts.append({ 'category': get_category(stmt), 'source': ''.join(stmt_lines), 'location': (start_line, end_line) }) prev_end = end_line if prev_end < len(lines): remaining_lines = lines[prev_end:] parts.append({ 'category': 'spacer', 'source': ''.join(remaining_lines), 'location': (prev_end + 1, len(lines) + 1) }) return parts