Skip to content

Commit 626cec1

Browse files
committed
more helpful error message
1 parent 28125fc commit 626cec1

File tree

1 file changed

+60
-3
lines changed

1 file changed

+60
-3
lines changed

codeflash/discovery/functions_to_optimize.py

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from collections import defaultdict
99
from functools import cache
1010
from pathlib import Path
11-
from typing import TYPE_CHECKING, Any, Optional
11+
from typing import TYPE_CHECKING, Any, Optional, Tuple
1212

1313
import git
1414
import libcst as cst
@@ -201,7 +201,7 @@ def get_functions_to_optimize(
201201
elif file is not None:
202202
logger.info("!lsp|Finding all functions in the file '%s'…", file)
203203
console.rule()
204-
functions = find_all_functions_in_file(file)
204+
functions: dict[Path, list[FunctionToOptimize]] = find_all_functions_in_file(file)
205205
if only_get_this_function is not None:
206206
split_function = only_get_this_function.split(".")
207207
if len(split_function) > 2:
@@ -224,8 +224,16 @@ def get_functions_to_optimize(
224224
if found_function is None:
225225
if is_lsp:
226226
return functions, 0, None
227+
found = closest_matching_file_function_name(only_get_this_function, functions)
228+
if found is not None:
229+
file, found_function = found
230+
exit_with_message(
231+
f"Function {only_get_this_function} not found in file {file}\nor the function does not have a 'return' statement or is a property.\n"
232+
f"Did you mean {found_function.qualified_name} instead?"
233+
)
234+
227235
exit_with_message(
228-
f"Function {only_function_name} not found in file {file}\nor the function does not have a 'return' statement or is a property"
236+
f"Function {only_get_this_function} not found in file {file}\nor the function does not have a 'return' statement or is a property"
229237
)
230238
functions[file] = [found_function]
231239
else:
@@ -259,6 +267,55 @@ def get_functions_within_git_diff(uncommitted_changes: bool) -> dict[str, list[F
259267
return get_functions_within_lines(modified_lines)
260268

261269

270+
def closest_matching_file_function_name(
271+
qualified_fn_to_find: str, found_fns: dict[Path, list[FunctionToOptimize]]
272+
) -> Tuple[Path, FunctionToOptimize] | None:
273+
"""Find closest matching function name using Levenshtein distance.
274+
275+
Args:
276+
qualified_fn_to_find: Function name to find in format "Class.function" or "function"
277+
found_fns: Dictionary of file paths to list of functions
278+
279+
Returns:
280+
Tuple of (file_path, function) for closest match, or None if no matches found
281+
"""
282+
min_distance = 4
283+
closest_match = None
284+
closest_file = None
285+
286+
qualified_fn_to_find = qualified_fn_to_find.lower()
287+
288+
for file_path, functions in found_fns.items():
289+
for function in functions:
290+
# Compare either full qualified name or just function name
291+
fn_name = function.qualified_name.lower()
292+
dist = levenshtein_distance(qualified_fn_to_find, fn_name)
293+
294+
if dist < min_distance:
295+
min_distance = dist
296+
closest_match = function
297+
closest_file = file_path
298+
299+
if closest_match is not None:
300+
return closest_file, closest_match
301+
return None
302+
303+
304+
def levenshtein_distance(s1: str, s2: str):
305+
if len(s1) > len(s2):
306+
s1, s2 = s2, s1
307+
distances = range(len(s1) + 1)
308+
for index2, char2 in enumerate(s2):
309+
newDistances = [index2 + 1]
310+
for index1, char1 in enumerate(s1):
311+
if char1 == char2:
312+
newDistances.append(distances[index1])
313+
else:
314+
newDistances.append(1 + min((distances[index1], distances[index1 + 1], newDistances[-1])))
315+
distances = newDistances
316+
return distances[-1]
317+
318+
262319
def get_functions_inside_a_commit(commit_hash: str) -> dict[str, list[FunctionToOptimize]]:
263320
modified_lines: dict[str, list[int]] = get_git_diff(only_this_commit=commit_hash)
264321
return get_functions_within_lines(modified_lines)

0 commit comments

Comments
 (0)