66from pathlib import Path
77from typing import List
88import fitz
9+ from import_deps import ModuleSet
10+ from graphlib import TopologicalSorter , CycleError
911import yaml
1012
1113from agent .class_types import AgentConfig
@@ -190,8 +192,46 @@ def _find_files_to_edit(base_dir: str, src_dir: str, test_dir: str) -> list[str]
190192 return files
191193
192194
193- def get_target_edit_files (target_dir : str , src_dir : str , test_dir : str ) -> list [str ]:
195+ def ignore_cycles (graph : dict ):
196+ ts = TopologicalSorter (graph )
197+ try :
198+ return list (set (ts .static_order ()))
199+ except CycleError as e :
200+ # print(f"Cycle detected: {e.args[1]}")
201+ # You can either break the cycle by modifying the graph or handle it as needed.
202+ # For now, let's just remove the first node in the cycle and try again.
203+ cycle_nodes = e .args [1 ]
204+ node_to_remove = cycle_nodes [0 ]
205+ # print(f"Removing node {node_to_remove} to resolve cycle.")
206+ graph .pop (node_to_remove , None )
207+ return ignore_cycles (graph )
208+
209+
210+ def topological_sort_based_on_dependencies (pkg_paths : list [str ]) -> list [str ]:
211+ """Topological sort based on dependencies."""
212+ module_set = ModuleSet ([str (p ) for p in pkg_paths ])
213+
214+ import_dependencies = {}
215+ for path in sorted (module_set .by_path .keys ()):
216+ module_name = "." .join (module_set .by_path [path ].fqn )
217+ mod = module_set .by_name [module_name ]
218+ imports = module_set .get_imports (mod )
219+ import_dependencies [path ] = set ([str (x ) for x in imports ])
220+
221+ import_dependencies_files = ignore_cycles (import_dependencies )
222+
223+ return import_dependencies_files
224+
225+
226+ def get_target_edit_files (
227+ local_repo : git .Repo ,
228+ src_dir : str ,
229+ test_dir : str ,
230+ latest_commit : str ,
231+ reference_commit : str ,
232+ ) -> list [str ]:
194233 """Find the files with functions with the pass statement."""
234+ target_dir = local_repo .working_dir
195235 files = _find_files_to_edit (target_dir , src_dir , test_dir )
196236 filtered_files = []
197237 for file_path in files :
@@ -202,13 +242,33 @@ def get_target_edit_files(target_dir: str, src_dir: str, test_dir: str) -> list[
202242 if " pass" in content :
203243 filtered_files .append (file_path )
204244
245+ # Change to reference commit to get the correct dependencies
246+ local_repo .git .checkout (reference_commit )
247+
248+ topological_sort_files = topological_sort_based_on_dependencies (filtered_files )
249+ if len (topological_sort_files ) != len (filtered_files ):
250+ if len (topological_sort_files ) < len (filtered_files ):
251+ # Find the missing elements
252+ missing_files = set (filtered_files ) - set (topological_sort_files )
253+ # Add the missing files to the end of the list
254+ topological_sort_files = topological_sort_files + list (missing_files )
255+ else :
256+ raise ValueError (
257+ "topological_sort_files should not be longer than filtered_files"
258+ )
259+ assert len (topological_sort_files ) == len (
260+ filtered_files
261+ ), "all files should be included"
262+
263+ # change to latest commit
264+ local_repo .git .checkout (latest_commit )
265+
205266 # Remove the base_dir prefix
206- filtered_files = [
207- file .replace (target_dir , "" ).lstrip ("/" ) for file in filtered_files
267+ topological_sort_files = [
268+ file .replace (target_dir , "" ).lstrip ("/" ) for file in topological_sort_files
208269 ]
209- # Only keep python files
210270
211- return filtered_files
271+ return topological_sort_files
212272
213273
214274def get_message (
0 commit comments