@@ -125,6 +125,7 @@ def __init__(
125125 self .max_function_count = max_function_count
126126 self .config = config
127127 self .project_root = project_root
128+ self .project_root_str = str (project_root ) + os .sep if project_root else ""
128129 console .rule (f"Project Root: { self .project_root } " , style = "bold blue" )
129130 self .ignored_functions = {"<listcomp>" , "<genexpr>" , "<dictcomp>" , "<setcomp>" , "<lambda>" , "<module>" }
130131
@@ -327,19 +328,20 @@ def tracer_logic(self, frame: FrameType, event: str) -> None:
327328 if code .co_name in self .ignored_functions :
328329 return
329330
330- # Now resolve file path only if we need it
331+ # Resolve file path and check validity (cached)
331332 co_filename = code .co_filename
332333 if co_filename in self .path_cache :
333- file_name = self .path_cache [co_filename ]
334+ file_name , is_valid = self .path_cache [co_filename ]
335+ if not is_valid :
336+ return
334337 else :
335- file_name = Path (co_filename ).resolve ()
336- self .path_cache [co_filename ] = file_name
337- # TODO : It currently doesn't log the last return call from the first function
338-
339- if not file_name .is_relative_to (self .project_root ):
340- return
341- if not file_name .exists ():
342- return
338+ resolved = os .path .realpath (co_filename )
339+ # startswith is cheaper than Path.is_relative_to, os.path.exists avoids Path construction
340+ is_valid = resolved .startswith (self .project_root_str ) and os .path .exists (resolved ) # noqa: PTH110
341+ self .path_cache [co_filename ] = (resolved , is_valid )
342+ if not is_valid :
343+ return
344+ file_name = resolved
343345 if self .functions and code .co_name not in self .functions :
344346 return
345347 class_name = None
@@ -376,10 +378,11 @@ def tracer_logic(self, frame: FrameType, event: str) -> None:
376378 if function_qualified_name in self .ignored_qualified_functions :
377379 return
378380 if function_qualified_name not in self .function_count :
379- # seeing this function for the first time
381+ # seeing this function for the first time — Path construction only happens here
380382 self .function_count [function_qualified_name ] = 1
383+ file_path = Path (file_name )
381384 file_valid = filter_files_optimized (
382- file_path = file_name ,
385+ file_path = file_path ,
383386 tests_root = Path (self .config ["tests_root" ]),
384387 ignore_paths = [Path (p ) for p in self .config ["ignore_paths" ]],
385388 module_root = Path (self .config ["module_root" ]),
@@ -391,8 +394,8 @@ def tracer_logic(self, frame: FrameType, event: str) -> None:
391394 self .function_modules .append (
392395 FunctionModules (
393396 function_name = code .co_name ,
394- file_name = file_name ,
395- module_name = module_name_from_file_path (file_name , project_root_path = self .project_root ),
397+ file_name = file_path ,
398+ module_name = module_name_from_file_path (file_path , project_root_path = self .project_root ),
396399 class_name = class_name ,
397400 line_no = code .co_firstlineno ,
398401 )
@@ -432,16 +435,7 @@ def tracer_logic(self, frame: FrameType, event: str) -> None:
432435
433436 cur .execute (
434437 "INSERT INTO function_calls VALUES(?, ?, ?, ?, ?, ?, ?, ?)" ,
435- (
436- event ,
437- code .co_name ,
438- class_name ,
439- str (file_name ),
440- frame .f_lineno ,
441- frame .f_back .__hash__ (),
442- t_ns ,
443- local_vars ,
444- ),
438+ (event , code .co_name , class_name , file_name , frame .f_lineno , frame .f_back .__hash__ (), t_ns , local_vars ),
445439 )
446440 self .trace_count += 1
447441 self .next_insert -= 1
0 commit comments