Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Node } from "@babel/traverse";
import { JavascriptParser } from "./context/language/javascript-parser";
import { ChatCompletionMessageParam } from "groq-sdk/resources/chat/completions";
import { PythonParser } from "./context/language/python-parser";

export interface PRFile {
sha: string;
Expand Down Expand Up @@ -107,6 +108,7 @@ const EXTENSIONS_TO_PARSERS: Map<string, AbstractParser> = new Map([
["tsx", new JavascriptParser()],
["js", new JavascriptParser()],
["jsx", new JavascriptParser()],
["py", new PythonParser()],
]);

export const getParserForExtension = (filename: string) => {
Expand Down
70 changes: 70 additions & 0 deletions src/context/language/py-parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import ast
import sys
import json

def find_enclosing_context(file_content, line_start, line_end):
try:
tree = ast.parse(file_content)
except SyntaxError as e:
return {"error": f"Syntax error in the file: {e}"}

class ContextFinder(ast.NodeVisitor):
def __init__(self, line_start, line_end):
self.line_start = line_start
self.line_end = line_end
self.largest_context = None
self.largest_size = 0

def visit_FunctionDef(self, node):
self.check_node(node)
self.generic_visit(node)

def visit_ClassDef(self, node):
self.check_node(node)
self.generic_visit(node)

def check_node(self, node):
if hasattr(node, 'end_lineno') and node.lineno <= self.line_start and self.line_end <= node.end_lineno:
size = node.end_lineno - node.lineno
if size > self.largest_size:
self.largest_size = size
self.largest_context = node

finder = ContextFinder(line_start, line_end)
finder.visit(tree)

if finder.largest_context:
return {
"type": finder.largest_context.__class__.__name__,
"name": getattr(finder.largest_context, 'name', None),
"start_line": finder.largest_context.lineno,
"end_line": getattr(finder.largest_context, 'end_lineno', None)
}

return {"error": "No enclosing context found"}

def main():
if len(sys.argv) != 4:
print(json.dumps({"error": "Usage: python python_parser.py <file_path> <line_start> <line_end>"}))
return

file_path = sys.argv[1]
try:
line_start = int(sys.argv[2])
line_end = int(sys.argv[3])
except ValueError:
print(json.dumps({"error": "Line numbers must be integers"}))
return

try:
with open(file_path, 'r') as file:
file_content = file.read()
except FileNotFoundError:
print(json.dumps({"error": f"File not found: {file_path}"}))
return

context = find_enclosing_context(file_content, line_start, line_end)
print(json.dumps(context, indent=4))

if __name__ == "__main__":
main()
45 changes: 40 additions & 5 deletions src/context/language/python-parser.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,50 @@
import { AbstractParser, EnclosingContext } from "../../constants";
import * as path from "path";
import { execSync } from "child_process"; // Use to execute Python script
import * as fs from "fs";

export class PythonParser implements AbstractParser {
private pythonScriptPath: string;

constructor() {
this.pythonScriptPath = path.resolve(__dirname, "python_parser.py");
}

findEnclosingContext(
file: string,
lineStart: number,
lineEnd: number
): EnclosingContext {
// TODO: Implement this method for Python
return null;
): EnclosingContext | null {
try {
const result = execSync(
`python ${this.pythonScriptPath} "${file}" ${lineStart} ${lineEnd}`,
{ encoding: "utf8" }
);

const context = JSON.parse(result);

if (context.error) {
console.error("Error from Python script:", context.error);
return null;
}

return {
enclosingContext: context,
} as EnclosingContext;
} catch (error) {
console.error("Failed to execute Python script:", error.message);
return null;
}
}

dryRun(file: string): { valid: boolean; error: string } {
// TODO: Implement this method for Python
return { valid: false, error: "Not implemented yet" };
try {
fs.readFileSync(file, "utf8");

execSync(`python ${this.pythonScriptPath} "${file}" 1 1`);
return { valid: true, error: "" };
} catch (error) {
return { valid: false, error: error.message };
}
}
}