Skip to content

Commit 2364096

Browse files
authored
Merge pull request #1529 from codeflash-ai/codeflash/optimize-pr1524-2026-02-18T14.38.26
2 parents eedd73d + ae740d9 commit 2364096

1 file changed

Lines changed: 30 additions & 14 deletions

File tree

codeflash/languages/python/context/code_context_extractor.py

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import ast
44
import hashlib
55
import os
6-
from collections import defaultdict
6+
from collections import defaultdict, deque
77
from itertools import chain
88
from typing import TYPE_CHECKING
99

@@ -746,33 +746,49 @@ def collect_type_names_from_annotation(node: ast.expr | None) -> set[str]:
746746

747747
def extract_init_stub_from_class(class_name: str, module_source: str, module_tree: ast.Module) -> str | None:
748748
class_node = None
749-
for node in ast.walk(module_tree):
750-
if isinstance(node, ast.ClassDef) and node.name == class_name:
751-
class_node = node
749+
# Use a deque-based BFS to find the first matching ClassDef (preserves ast.walk order)
750+
q: deque[ast.AST] = deque([module_tree])
751+
while q:
752+
candidate = q.popleft()
753+
if isinstance(candidate, ast.ClassDef) and candidate.name == class_name:
754+
class_node = candidate
752755
break
756+
q.extend(ast.iter_child_nodes(candidate))
757+
753758
if class_node is None:
754759
return None
755760

756761
lines = module_source.splitlines()
757762
relevant_nodes: list[ast.FunctionDef | ast.AsyncFunctionDef] = []
758763
for item in class_node.body:
759764
if isinstance(item, (ast.FunctionDef, ast.AsyncFunctionDef)):
760-
if item.name in ("__init__", "__post_init__") or any(
761-
(isinstance(d, ast.Name) and d.id == "property")
762-
or (isinstance(d, ast.Attribute) and d.attr == "property")
763-
for d in item.decorator_list
764-
):
765+
is_relevant = False
766+
if item.name in ("__init__", "__post_init__"):
767+
is_relevant = True
768+
else:
769+
# Check decorators explicitly to avoid generator overhead
770+
for d in item.decorator_list:
771+
if (isinstance(d, ast.Name) and d.id == "property") or (
772+
isinstance(d, ast.Attribute) and d.attr == "property"
773+
):
774+
is_relevant = True
775+
break
776+
if is_relevant:
765777
relevant_nodes.append(item)
766778

767779
if not relevant_nodes:
768780
return None
769781

770782
snippets: list[str] = []
771-
for node in relevant_nodes:
772-
start = node.lineno
773-
if node.decorator_list:
774-
start = min(d.lineno for d in node.decorator_list)
775-
snippets.append("\n".join(lines[start - 1 : node.end_lineno]))
783+
for fn_node in relevant_nodes:
784+
start = fn_node.lineno
785+
if fn_node.decorator_list:
786+
# Compute minimum decorator lineno with an explicit loop (avoids generator/min overhead)
787+
m = start
788+
for d in fn_node.decorator_list:
789+
m = min(m, d.lineno)
790+
start = m
791+
snippets.append("\n".join(lines[start - 1 : fn_node.end_lineno]))
776792

777793
return f"class {class_name}:\n" + "\n".join(snippets)
778794

0 commit comments

Comments
 (0)