11"""Provide core utilities and workflows for this module."""
22
33import hashlib
4- import json
54import os
65import platform
76import shutil
87import sys
9- from typing import Any
108
119from PySide6 .QtCore import QProcess , QTimer
1210
@@ -49,6 +47,7 @@ def __init__(self, parent_widget):
4947 self ._venv_check_pkgs = []
5048 self ._venv_check_index = 0
5149 self ._venv_check_pip_exe = None
50+ self ._venv_check_pip_args = []
5251 self ._venv_check_path = None
5352 self ._venv_check_use_python = False
5453
@@ -312,14 +311,6 @@ def is_tool_installed(self, venv_root: str, tool: str) -> bool:
312311 """
313312 return self .has_tool_binary (venv_root , tool )
314313
315- def is_tool_installed_system (self , tool : str ) -> bool :
316- """Return whether the related condition is satisfied."""
317- try :
318- missing = self ._missing_in_system_python ([tool ])
319- return len (missing ) == 0
320- except Exception :
321- return False
322-
323314 def is_tool_installed_async (self , venv_root : str , tool : str , callback ) -> None :
324315 """Asynchronous check using 'pip show <tool>' via QProcess, then callback(bool).
325316 Safe for UI: does not block. On any error, returns False.
@@ -355,7 +346,10 @@ def ensure_tools_installed(self, venv_root: str, tools: list[str]) -> None:
355346 self ._reset_cancel_state ()
356347 self ._venv_check_pkgs = list (tools )
357348 self ._venv_check_index = 0
358- self ._venv_check_pip_exe = self .pip_path (venv_root )
349+
350+ pip_exe , pip_args = deps_analyser ._find_pip_executable (venv_path = venv_root )
351+ self ._venv_check_pip_exe = pip_exe
352+ self ._venv_check_pip_args = pip_args
359353 self ._venv_check_path = venv_root
360354 self ._venv_check_use_python = False
361355
@@ -384,7 +378,10 @@ def ensure_tools_installed_system(self, tools: list[str]) -> None:
384378 self ._reset_cancel_state ()
385379 self ._venv_check_pkgs = list (tools )
386380 self ._venv_check_index = 0
387- self ._venv_check_pip_exe = sys .executable
381+
382+ pip_exe , pip_args = deps_analyser ._find_pip_executable (venv_path = None , workspace_dir = None )
383+ self ._venv_check_pip_exe = pip_exe
384+ self ._venv_check_pip_args = pip_args
388385 self ._venv_check_path = (
389386 getattr (self .parent , "workspace_dir" , None ) or os .getcwd ()
390387 )
@@ -668,13 +665,6 @@ def is_valid_venv(self, venv_root: str) -> bool:
668665 return ok
669666
670667 # ---------- System Python suggestion ----------
671- def _normalize_dist_name (self , name : str ) -> str :
672- """Execute _normalize_dist_name logic for this component."""
673- try :
674- return name .strip ().lower ().replace ("_" , "-" )
675- except Exception :
676- return str (name ).strip ().lower ()
677-
678668 def _collect_declared_dependencies (
679669 self , workspace_dir : str
680670 ) -> tuple [list [str ], bool ]:
@@ -688,40 +678,17 @@ def _collect_declared_dependencies(
688678 return [], False
689679
690680 def _missing_in_system_python (self , packages : list [str ]) -> list [str ]:
691- """Execute _missing_in_system_python logic for this component."""
692- try :
693- from importlib .metadata import PackageNotFoundError , distribution
694-
695- missing = []
696- for pkg in packages :
697- if not pkg :
698- continue
699- name = str (pkg ).strip ()
700- if not name :
701- continue
702- normalized = self ._normalize_dist_name (name )
703- try :
704- distribution (name )
705- continue
706- except PackageNotFoundError :
707- pass
708- except Exception :
709- pass
710- if normalized != name :
711- try :
712- distribution (normalized )
713- continue
714- except PackageNotFoundError :
715- pass
716- except Exception :
717- pass
718- missing .append (name )
719- return missing
720- except Exception :
721- return packages
681+ """Check for missing packages in system Python using deps_analyser."""
682+ missing = []
683+ for pkg in packages :
684+ if not pkg :
685+ continue
686+ if not deps_analyser ._check_module_installed (str (pkg )):
687+ missing .append (str (pkg ))
688+ return missing
722689
723690 def _can_use_system_python (self ) -> tuple [bool , list [str ], bool ]:
724- """Return whether this operation can run safely."""
691+ """Return whether this operation can run safely using system Python ."""
725692 workspace_dir = getattr (self .parent , "workspace_dir" , None )
726693 if not workspace_dir :
727694 return False , [], False
@@ -734,8 +701,9 @@ def _can_use_system_python(self) -> tuple[bool, list[str], bool]:
734701 missing = self ._missing_in_system_python (sorted (set (deps )))
735702 return (len (missing ) == 0 ), missing , has_source
736703
737-
738- # ---------- Existing venv: check and install tools ----------
704+ def is_tool_installed_system (self , tool : str ) -> bool :
705+ """Check if a tool is installed in system Python via deps_analyser."""
706+ return deps_analyser ._check_module_installed (tool )
739707 def check_tools_in_venv (self , venv_path : str ):
740708 """Execute check_tools_in_venv logic for this component."""
741709 try :
@@ -758,11 +726,8 @@ def _after_binding(ok_bind: bool):
758726 venv_path , "Python/pip do not point to the selected venv"
759727 )
760728 return
761- pip_exe = os .path .join (
762- venv_path ,
763- "Scripts" if platform .system () == "Windows" else "bin" ,
764- "pip" ,
765- )
729+
730+ pip_exe , pip_args = deps_analyser ._find_pip_executable (venv_path = venv_path )
766731 self ._venv_check_pkgs = self ._discover_engine_required_python_tools ()
767732 if not self ._venv_check_pkgs :
768733 self ._safe_log (
@@ -772,6 +737,7 @@ def _after_binding(ok_bind: bool):
772737 return
773738 self ._venv_check_index = 0
774739 self ._venv_check_pip_exe = pip_exe
740+ self ._venv_check_pip_args = pip_args
775741 self ._venv_check_path = venv_path
776742 self ._venv_check_use_python = False
777743
@@ -829,10 +795,9 @@ def _check_next_venv_pkg(self):
829795 process = QProcess (self .parent )
830796 self ._venv_check_process = process
831797 process .setProgram (self ._venv_check_pip_exe )
832- if self ._venv_check_use_python :
833- process .setArguments (["-m" , "pip" , "show" , pkg ])
834- else :
835- process .setArguments (["show" , pkg ])
798+ # Use stored pip args (e.g. ['-m', 'pip']) if available
799+ args = list (getattr (self , "_venv_check_pip_args" , []))
800+ process .setArguments (args + ["show" , pkg ])
836801 process .setWorkingDirectory (self ._venv_check_path )
837802 process .finished .connect (
838803 lambda code , status : self ._on_venv_pkg_checked (process , code , status , pkg )
@@ -899,14 +864,13 @@ def _on_venv_pkg_checked(self, process, code, status, pkg):
899864 process2 = QProcess (self .parent )
900865 self ._venv_check_install_process = process2
901866 process2 .setProgram (self ._venv_check_pip_exe )
902- if self ._venv_check_use_python :
903- process2 .setArguments (
904- ["-m" , "pip" , "install" ] + self ._pip_break_system_args () + [pkg ]
905- )
906- else :
907- process2 .setArguments (
908- ["install" ] + self ._pip_break_system_args () + [pkg ]
909- )
867+
868+ # Use stored pip args (e.g. ['-m', 'pip']) if available
869+ args = list (getattr (self , "_venv_check_pip_args" , []))
870+ process2 .setArguments (
871+ args + ["install" ] + self ._pip_break_system_args () + [pkg ]
872+ )
873+
910874 process2 .setWorkingDirectory (self ._venv_check_path )
911875 process2 .readyReadStandardOutput .connect (
912876 lambda : self ._on_venv_check_output (process2 )
0 commit comments