Skip to content

Commit 13fbeba

Browse files
authored
Merge branch 'main' into gpu-flag
2 parents 01b1f42 + 65d7754 commit 13fbeba

File tree

7 files changed

+1435
-741
lines changed

7 files changed

+1435
-741
lines changed

.github/workflows/claude.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ jobs:
4949
uses: anthropics/claude-code-action@v1
5050
with:
5151
use_foundry: "true"
52+
claude_args: '--allowedTools "Read,Edit,Write,Glob,Grep,Bash(git status*),Bash(git diff*),Bash(git add *),Bash(git commit *),Bash(git push*),Bash(git log*),Bash(uv run pre-commit *),Bash(uv run ruff *),Bash(uv run pytest *),Bash(uv run mypy *),Bash(uv run coverage *),Bash(gh pr comment*),Bash(gh pr view*),Bash(gh pr diff*)"'
5253
additional_permissions: |
5354
actions: read
5455
env:

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
repos:
22
- repo: https://github.com/astral-sh/ruff-pre-commit
3-
rev: v0.12.7
3+
rev: v0.15.0
44
hooks:
55
# Run the linter.
66
- id: ruff-check

CLAUDE.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ codeflash/
6262
- Use libcst, not ast - For Python, always use `libcst` for code parsing/modification to preserve formatting.
6363
- Code context extraction and replacement tests must always assert for full string equality, no substring matching.
6464
- Any new feature or bug fix that can be tested automatically must have test cases.
65+
- If changes affect existing test expectations, update the tests accordingly. Tests must always pass after changes.
66+
- NEVER use leading underscores for function names (e.g., `_helper`). Python has no true private functions. Always use public names.
6567

6668
## Code Style
6769

@@ -70,7 +72,7 @@ codeflash/
7072
- **Tooling**: Ruff for linting/formatting, mypy strict mode, pre-commit hooks
7173
- **Comments**: Minimal - only explain "why", not "what"
7274
- **Docstrings**: Do not add unless explicitly requested
73-
- **Naming**: Prefer public functions (no leading underscore) - Python doesn't have true private functions
75+
- **Naming**: NEVER use leading underscores (`_function_name`) - Python has no true private functions, use public names
7476
- **Paths**: Always use absolute paths, handle encoding explicitly (UTF-8)
7577

7678
## Git Commits & Pull Requests

codeflash/languages/python/support.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ def find_references(
321321

322322
function_pos = None
323323
for name in names:
324-
if name.type == "function" and name.name == function.name:
324+
if name.type == "function" and name.name == function.function_name:
325325
# Check for class parent if it's a method
326326
if function.class_name:
327327
parent = name.parent()

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,9 @@ dev = [
7878
"types-greenlet>=3.1.0.20241221,<4",
7979
"types-pexpect>=4.9.0.20241208,<5",
8080
"types-unidiff>=0.7.0.20240505,<0.8",
81-
"uv>=0.6.2",
8281
"pre-commit>=4.2.0,<5",
82+
"ty>=0.0.14",
83+
"uv>=0.9.29",
8384
]
8485
tests = [
8586
"black>=25.9.0",

tests/test_languages/test_python_support.py

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,3 +555,125 @@ def standalone():
555555

556556
standalone_funcs = [f for f in functions if f.class_name is None]
557557
assert len(standalone_funcs) == 1
558+
559+
560+
# === Tests for find_references method ===
561+
# These tests verify that PythonSupport correctly finds references to functions
562+
# using jedi, including the fix for using function.function_name instead of function.name.
563+
564+
565+
def test_find_references_simple_function(python_support, tmp_path):
566+
"""Test finding references to a simple function.
567+
568+
This test specifically exercises the code path that was fixed in the
569+
regression where function.name was used instead of function.function_name.
570+
"""
571+
from codeflash.models.function_types import FunctionToOptimize
572+
573+
# Create source file with function definition
574+
source_file = tmp_path / "utils.py"
575+
source_file.write_text("""def helper_function(x):
576+
return x * 2
577+
""")
578+
579+
# Create a file that imports and uses the function
580+
consumer_file = tmp_path / "consumer.py"
581+
consumer_file.write_text("""from utils import helper_function
582+
583+
def process(value):
584+
return helper_function(value) + 1
585+
""")
586+
587+
func = FunctionToOptimize(
588+
function_name="helper_function",
589+
file_path=source_file,
590+
starting_line=1,
591+
ending_line=2,
592+
)
593+
594+
refs = python_support.find_references(func, project_root=tmp_path)
595+
596+
assert len(refs) >= 1
597+
ref_files = {str(r.file_path) for r in refs}
598+
assert any("consumer.py" in f for f in ref_files)
599+
600+
601+
def test_find_references_class_method(python_support, tmp_path):
602+
"""Test finding references to a class method.
603+
604+
This verifies the class_name attribute is correctly used to disambiguate methods.
605+
"""
606+
from codeflash.models.function_types import FunctionParent, FunctionToOptimize
607+
608+
# Create source file with class and method
609+
source_file = tmp_path / "calculator.py"
610+
source_file.write_text("""class Calculator:
611+
def add(self, a, b):
612+
return a + b
613+
""")
614+
615+
# Create a file that uses the class method
616+
consumer_file = tmp_path / "main.py"
617+
consumer_file.write_text("""from calculator import Calculator
618+
619+
def compute():
620+
calc = Calculator()
621+
return calc.add(1, 2)
622+
""")
623+
624+
func = FunctionToOptimize(
625+
function_name="add",
626+
file_path=source_file,
627+
parents=[FunctionParent(name="Calculator", type="ClassDef")],
628+
starting_line=2,
629+
ending_line=3,
630+
is_method=True,
631+
)
632+
633+
refs = python_support.find_references(func, project_root=tmp_path)
634+
635+
assert len(refs) >= 1
636+
ref_files = {str(r.file_path) for r in refs}
637+
assert any("main.py" in f for f in ref_files)
638+
639+
640+
def test_find_references_no_references(python_support, tmp_path):
641+
"""Test that find_references returns empty list when no references exist."""
642+
from codeflash.models.function_types import FunctionToOptimize
643+
644+
source_file = tmp_path / "isolated.py"
645+
source_file.write_text("""def isolated_function():
646+
return 42
647+
""")
648+
649+
func = FunctionToOptimize(
650+
function_name="isolated_function",
651+
file_path=source_file,
652+
starting_line=1,
653+
ending_line=2,
654+
)
655+
656+
refs = python_support.find_references(func, project_root=tmp_path)
657+
658+
assert refs == []
659+
660+
661+
def test_find_references_nonexistent_function(python_support, tmp_path):
662+
"""Test that find_references handles nonexistent functions gracefully."""
663+
from codeflash.models.function_types import FunctionToOptimize
664+
665+
source_file = tmp_path / "source.py"
666+
source_file.write_text("""def existing_function():
667+
return 1
668+
""")
669+
670+
func = FunctionToOptimize(
671+
function_name="nonexistent_function",
672+
file_path=source_file,
673+
starting_line=1,
674+
ending_line=2,
675+
)
676+
677+
refs = python_support.find_references(func, project_root=tmp_path)
678+
679+
assert refs == []

0 commit comments

Comments
 (0)