Skip to content

Commit e1e8efd

Browse files
committed
start cleaning up, write tests
1 parent 2764aff commit e1e8efd

16 files changed

+79
-2014
lines changed

codeflash/code_utils/code_extractor.py

Lines changed: 46 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,22 @@
1010

1111
import jedi
1212
import libcst as cst
13+
import radon.visitors
1314
from libcst.codemod import CodemodContext
1415
from libcst.codemod.visitors import AddImportsVisitor, GatherImportsVisitor, RemoveImportsVisitor
1516
from libcst.helpers import calculate_module_and_package
17+
from radon.complexity import cc_visit
1618

1719
# from codeflash.benchmarking.pytest_new_process_trace_benchmarks import project_root
1820
from codeflash.cli_cmds.console import logger
1921
from codeflash.code_utils.config_consts import MAX_CONTEXT_LEN_IMPACT, TIME_LIMIT_FOR_OPT_IMPACT
20-
from codeflash.models.models import CodePosition, FunctionParent
22+
from codeflash.models.models import CodePosition, FunctionParent, ImpactMetrics
2123

2224
if TYPE_CHECKING:
2325
from libcst.helpers import ModuleNameAndPackage
2426

2527
from codeflash.discovery.functions_to_optimize import FunctionToOptimize
26-
from codeflash.models.models import FunctionSource, ImpactMetrics
28+
from codeflash.models.models import FunctionSource
2729

2830

2931
class GlobalAssignmentCollector(cst.CSTVisitor):
@@ -1092,13 +1094,11 @@ def find_occurances(
10921094
fn_call_context += f"{fn_definition}\n"
10931095
context_len += len(fn_definition)
10941096
fn_call_context += "```\n"
1095-
opt_impact_metrics = {"calling_fn_defs": fn_call_context}
1096-
# radon metrics = get_radon_metrics(sour)
10971097
return fn_call_context
10981098

10991099

11001100
def find_specific_function_in_file(
1101-
source_code: str, filepath: Union[str, Path], qualified_name: str
1101+
source_code: str, filepath: Union[str, Path], target_function: str, target_class: str | None
11021102
) -> Optional[tuple[int, int]]:
11031103
"""Find a specific function definition in a Python file and return its location.
11041104
@@ -1107,17 +1107,13 @@ def find_specific_function_in_file(
11071107
Args:
11081108
source_code: Source code string
11091109
filepath: Path to the Python file
1110-
qualified_name: Qualified Name of the function to find, classname.functionname
1110+
target_function: Function Name of the function to find
1111+
target_class: Class name of the function to find
11111112
11121113
Returns:
11131114
Tuple of (line_number, column_offset) if found, None otherwise
11141115
11151116
"""
1116-
qualified_name_split = qualified_name.rsplit(".", maxsplit=1)
1117-
if len(qualified_name_split) == 1:
1118-
target_function, target_class = qualified_name_split[0], None
1119-
else:
1120-
target_function, target_class = qualified_name_split[1], qualified_name_split[0]
11211117
script = jedi.Script(code=source_code, path=filepath)
11221118
names = script.get_names(all_scopes=True, definitions=True)
11231119
for name in names:
@@ -1134,16 +1130,16 @@ def find_specific_function_in_file(
11341130
return None # Function not found
11351131

11361132

1137-
def get_fn_references_jedi(source_code: str, file_path: Path, qualified_name: str, project_root: Path) -> list[Path]:
1138-
print(file_path, qualified_name, project_root)
1139-
# Create a Jedi Script object
1140-
function_position: CodePosition = find_specific_function_in_file(source_code, file_path, qualified_name)
1133+
def get_fn_references_jedi(
1134+
source_code: str, file_path: Path, project_root: Path, target_function: str, target_class: str | None
1135+
) -> list[Path]:
1136+
function_position: CodePosition = find_specific_function_in_file(
1137+
source_code, file_path, target_function, target_class
1138+
)
11411139
try:
11421140
script = jedi.Script(code=source_code, path=file_path, project=jedi.Project(path=project_root))
1143-
11441141
# Get references to the function
11451142
references = script.get_references(line=function_position.line_no, column=function_position.col_no)
1146-
11471143
# Collect unique file paths where references are found
11481144
reference_files = set()
11491145
for ref in references:
@@ -1153,9 +1149,7 @@ def get_fn_references_jedi(source_code: str, file_path: Path, qualified_name: st
11531149
# Skip the definition itself
11541150
if not (ref_path == file_path and ref.line == function_position.line_no):
11551151
reference_files.add(ref_path)
1156-
11571152
return sorted(reference_files)
1158-
11591153
except Exception as e:
11601154
print(f"Error during Jedi analysis: {e}")
11611155
return []
@@ -1164,9 +1158,36 @@ def get_fn_references_jedi(source_code: str, file_path: Path, qualified_name: st
11641158
def get_opt_impact_metrics(
11651159
source_code: str, file_path: Path, qualified_name: str, project_root: Path, tests_root: Path
11661160
) -> ImpactMetrics:
1167-
# radon lib for complexity metrics
1168-
# print(file_path, qualified_name, project_root, tests_root)
1169-
matches = get_fn_references_jedi(
1170-
source_code, file_path, qualified_name, project_root
1171-
) # jedi is not perfect, it doesn't capture aliased references
1172-
return find_occurances(qualified_name, str(file_path), matches, project_root, tests_root)
1161+
metrics = ImpactMetrics()
1162+
try:
1163+
qualified_name_split = qualified_name.rsplit(".", maxsplit=1)
1164+
if len(qualified_name_split) == 1:
1165+
target_function, target_class = qualified_name_split[0], None
1166+
else:
1167+
target_function, target_class = qualified_name_split[1], qualified_name_split[0]
1168+
matches = get_fn_references_jedi(
1169+
source_code, file_path, project_root, target_function, target_class
1170+
) # jedi is not perfect, it doesn't capture aliased references
1171+
cyclomatic_complexity_results = cc_visit(source_code)
1172+
match_found = False
1173+
for result in cyclomatic_complexity_results:
1174+
if match_found:
1175+
break
1176+
if isinstance(result, radon.visitors.Function) and not target_class:
1177+
if result.name == target_function:
1178+
metrics.cyclomatic_complexity = result.complexity
1179+
metrics.cyclomatic_complexity_rating = result.letter
1180+
match_found = True
1181+
elif isinstance(result, radon.visitors.Class) and target_class: # noqa: SIM102
1182+
if result.name == target_class:
1183+
for method in result.methods:
1184+
if match_found:
1185+
break
1186+
if method.name == target_function:
1187+
metrics.cyclomatic_complexity = method.complexity
1188+
metrics.cyclomatic_complexity_rating = method.letter
1189+
match_found = True
1190+
metrics.calling_fns = find_occurances(qualified_name, str(file_path), matches, project_root, tests_root)
1191+
except Exception as e:
1192+
logger.debug(f"Investigate {e}")
1193+
return metrics

codeflash/code_utils/config_consts.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,4 @@
3636
TOTAL_LOOPING_TIME_EFFECTIVE = TOTAL_LOOPING_TIME_LSP if _IS_LSP_ENABLED else TOTAL_LOOPING_TIME
3737

3838
MAX_CONTEXT_LEN_IMPACT = 1000
39-
TIME_LIMIT_FOR_OPT_IMPACT = 5 # in sec
39+
TIME_LIMIT_FOR_OPT_IMPACT = 10 # in sec

codeflash/models/models.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,9 @@
3333

3434
@dataclass
3535
class ImpactMetrics:
36-
complexity_score: int
37-
occurances: int
38-
loop_occurances: int
39-
presence_of_decorators: bool
36+
cyclomatic_complexity: Optional[int] = None
37+
cyclomatic_complexity_rating: Optional[str] = None
38+
calling_fns: Optional[str] = None
4039

4140

4241
@dataclass(frozen=True)

codeflash/optimization/function_optimizer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1474,7 +1474,7 @@ def process_review(
14741474
self.function_to_optimize.qualified_name,
14751475
self.project_root,
14761476
self.test_cfg.tests_root,
1477-
) # need module root, tests root only
1477+
)
14781478
if raise_pr and not staging_review:
14791479
data["git_remote"] = self.args.git_remote
14801480
check_create_pr(**data)

example_usage.py

Lines changed: 0 additions & 131 deletions
This file was deleted.

0 commit comments

Comments
 (0)