99from PySide6 .QtCore import QProcess , QTimer
1010
1111import Core .deps_analyser .analyser as deps_analyser
12+ import Core .SysDependencyManager as sys_deps
1213
1314
1415class VenvManager :
@@ -45,6 +46,7 @@ def __init__(self, parent_widget):
4546
4647 # For tool check/installation
4748 self ._venv_check_pkgs = []
49+ self ._venv_check_sys_pkgs = []
4850 self ._venv_check_index = 0
4951 self ._venv_check_pip_exe = None
5052 self ._venv_check_pip_args = []
@@ -199,20 +201,21 @@ def resolve_project_venv(self) -> str | None:
199201 return None
200202
201203 def pip_path (self , venv_root : str ) -> str :
202- """Execute pip_path logic for this component."""
203- return os .path .join (
204- venv_root , "Scripts" if platform .system () == "Windows" else "bin" , "pip"
205- )
204+ """Get the absolute path to the pip executable using deps_analyser."""
205+ pip_exe , _ = deps_analyser ._find_pip_executable (venv_path = venv_root )
206+ return pip_exe
206207
207208 def python_path (self , venv_root : str ) -> str :
208- """Execute python_path logic for this component."""
209+ """Get the absolute path to the python executable using deps_analyser."""
210+ pip_exe , pip_args = deps_analyser ._find_pip_executable (venv_path = venv_root )
211+ if "-m" in pip_args and "pip" in pip_args :
212+ return pip_exe
213+ # Fallback to internal detection if pip_exe is directly the pip binary
209214 base = os .path .join (
210215 venv_root , "Scripts" if platform .system () == "Windows" else "bin"
211216 )
212217 if platform .system () == "Windows" :
213- cand = os .path .join (base , "python.exe" )
214- return cand
215- # Linux/macOS: prefer 'python', fallback to 'python3'
218+ return os .path .join (base , "python.exe" )
216219 cand1 = os .path .join (base , "python" )
217220 cand2 = os .path .join (base , "python3" )
218221 return cand1 if os .path .isfile (cand1 ) else cand2
@@ -271,9 +274,10 @@ def has_tool_binary(self, venv_root: str, tool: str) -> bool:
271274 except Exception :
272275 return False
273276
274- def _discover_engine_required_python_tools (self ) -> list [str ]:
275- """Discover python tools required by available engines dynamically."""
276- tools : list [str ] = []
277+ def _discover_engine_requirements (self ) -> dict [str , list [str ]]:
278+ """Discover tools required by available engines dynamically."""
279+ python_tools : list [str ] = []
280+ system_tools : list [str ] = []
277281 try :
278282 import Core .engine as engines_loader
279283
@@ -290,19 +294,22 @@ def _discover_engine_required_python_tools(self) -> list[str]:
290294 for item in req .get ("python" , []) or []:
291295 name = str (item or "" ).strip ()
292296 if name :
293- tools .append (name )
297+ python_tools .append (name )
298+ for item in req .get ("system" , []) or []:
299+ name = str (item or "" ).strip ()
300+ if name :
301+ system_tools .append (name )
294302 except Exception :
295303 pass
296304
297- unique : list [str ] = []
298- seen : set [str ] = set ()
299- for tool in tools :
300- key = tool .lower ()
301- if key in seen :
302- continue
303- seen .add (key )
304- unique .append (tool )
305- return unique
305+ return {
306+ "python" : sorted (set (python_tools ), key = str .lower ),
307+ "system" : sorted (set (system_tools ), key = str .lower ),
308+ }
309+
310+ def _discover_engine_required_python_tools (self ) -> list [str ]:
311+ """Discover python tools required by available engines dynamically (legacy helper)."""
312+ return self ._discover_engine_requirements ().get ("python" , [])
306313
307314 def is_tool_installed (self , venv_root : str , tool : str ) -> bool :
308315 """Non-blocking check for tool presence in venv.
@@ -316,7 +323,7 @@ def is_tool_installed_async(self, venv_root: str, tool: str, callback) -> None:
316323 Safe for UI: does not block. On any error, returns False.
317324 """
318325 try :
319- pip_exe = self . pip_path ( venv_root )
326+ pip_exe , pip_args = deps_analyser . _find_pip_executable ( venv_path = venv_root )
320327 if not pip_exe or not os .path .isfile (pip_exe ):
321328 callback (False )
322329 return
@@ -331,7 +338,7 @@ def _done(code, _status):
331338
332339 proc .finished .connect (_done )
333340 proc .setProgram (pip_exe )
334- proc .setArguments (["show" , tool ])
341+ proc .setArguments (pip_args + ["show" , tool ])
335342 proc .setWorkingDirectory (venv_root )
336343 proc .start ()
337344 except Exception :
@@ -705,7 +712,7 @@ def is_tool_installed_system(self, tool: str) -> bool:
705712 """Check if a tool is installed in system Python via deps_analyser."""
706713 return deps_analyser ._check_module_installed (tool )
707714 def check_tools_in_venv (self , venv_path : str ):
708- """Execute check_tools_in_venv logic for this component ."""
715+ """Check both python and system requirements for the current workspace ."""
709716 try :
710717 self ._reset_cancel_state ()
711718 ok , reason = self .validate_venv_strict (venv_path )
@@ -727,14 +734,33 @@ def _after_binding(ok_bind: bool):
727734 )
728735 return
729736
730- pip_exe , pip_args = deps_analyser ._find_pip_executable (venv_path = venv_path )
731- self ._venv_check_pkgs = self ._discover_engine_required_python_tools ()
732- if not self ._venv_check_pkgs :
737+ reqs = self ._discover_engine_requirements ()
738+ python_tools = reqs .get ("python" , [])
739+ system_tools = reqs .get ("system" , [])
740+
741+ # 1. Check system tools first (fast, usually non-blocking)
742+ if system_tools :
743+ missing_sys = [t for t in system_tools if not sys_deps .check_system_packages ([t ])]
744+ if missing_sys :
745+ self ._safe_log (
746+ f"[WARNING] Outils systeme manquants : { ', ' .join (missing_sys )} " ,
747+ f"[WARNING] Missing system tools: { ', ' .join (missing_sys )} " ,
748+ )
749+ # On pourrait proposer l'installation, mais on laisse les engines gérer
750+ # ou on affiche juste l'avertissement.
751+ else :
752+ self ._safe_log ("[OK] Outils systeme verifies." )
753+
754+ # 2. Proceed with python tools in venv
755+ if not python_tools :
733756 self ._safe_log (
734757 "[INFO] Aucun outil Python requis detecte depuis les engines." ,
735758 "[INFO] No required Python tools detected from engines." ,
736759 )
737760 return
761+
762+ pip_exe , pip_args = deps_analyser ._find_pip_executable (venv_path = venv_path )
763+ self ._venv_check_pkgs = python_tools
738764 self ._venv_check_index = 0
739765 self ._venv_check_pip_exe = pip_exe
740766 self ._venv_check_pip_args = pip_args
0 commit comments