@@ -496,17 +496,22 @@ def has_tool_binary(self, venv_root: str, tool: str) -> bool:
496496 )
497497 if not os .path .isdir (bindir ):
498498 return False
499+ raw = str (tool or "" ).strip ()
500+ if not raw :
501+ return False
502+ lower = raw .lower ()
503+ variants = {lower }
504+ if "_" in lower :
505+ variants .add (lower .replace ("_" , "-" ))
506+ variants .add (lower .replace ("_" , "" ))
507+ if "-" in lower :
508+ variants .add (lower .replace ("-" , "_" ))
509+ variants .add (lower .replace ("-" , "" ))
510+ variants .add (f"{ lower } 3" )
511+
499512 names : list [str ] = []
500- t = tool .strip ().lower ()
501- if t == "pyinstaller" :
502- names = ["pyinstaller" , "pyinstaller.exe" , "pyinstaller-script.py" ]
503- elif t == "nuitka" :
504- names = ["nuitka" , "nuitka3" , "nuitka.exe" , "nuitka-script.py" ]
505- elif t == "cx_freeze" :
506- names = ["cxfreeze" , "cxfreeze.exe" , "cxfreeze-script.py" ]
507- else :
508- # generic: try tool, tool.exe, and tool-script.py
509- names = [t , f"{ t } .exe" , f"{ t } -script.py" ]
513+ for name in sorted (variants ):
514+ names .extend ([name , f"{ name } .exe" , f"{ name } -script.py" ])
510515 for n in names :
511516 p = os .path .join (bindir , n )
512517 if os .path .isfile (p ):
@@ -518,6 +523,39 @@ def has_tool_binary(self, venv_root: str, tool: str) -> bool:
518523 except Exception :
519524 return False
520525
526+ def _discover_engine_required_python_tools (self ) -> list [str ]:
527+ """Discover python tools required by available engines dynamically."""
528+ tools : list [str ] = []
529+ try :
530+ import EngineLoader as engines_loader
531+
532+ for engine_id in list (engines_loader .available_engines ()):
533+ try :
534+ engine = engines_loader .create (engine_id )
535+ except Exception :
536+ engine = None
537+ if engine is None :
538+ continue
539+ req = getattr (engine , "required_tools" , {"python" : [], "system" : []})
540+ if not isinstance (req , dict ):
541+ continue
542+ for item in req .get ("python" , []) or []:
543+ name = str (item or "" ).strip ()
544+ if name :
545+ tools .append (name )
546+ except Exception :
547+ pass
548+
549+ unique : list [str ] = []
550+ seen : set [str ] = set ()
551+ for tool in tools :
552+ key = tool .lower ()
553+ if key in seen :
554+ continue
555+ seen .add (key )
556+ unique .append (tool )
557+ return unique
558+
521559 def is_tool_installed (self , venv_root : str , tool : str ) -> bool :
522560 """Non-blocking check for tool presence in venv.
523561 Uses has_tool_binary() only (no subprocess run). If uncertain, returns False
@@ -1374,7 +1412,13 @@ def _after_binding(ok_bind: bool):
13741412 "Scripts" if platform .system () == "Windows" else "bin" ,
13751413 "pip" ,
13761414 )
1377- self ._venv_check_pkgs = ["pyinstaller" , "nuitka" , "cx_freeze" ]
1415+ self ._venv_check_pkgs = self ._discover_engine_required_python_tools ()
1416+ if not self ._venv_check_pkgs :
1417+ self ._safe_log (
1418+ "ℹ️ Aucun outil Python requis détecté depuis les engines." ,
1419+ "ℹ️ No required Python tools detected from engines." ,
1420+ )
1421+ return
13781422 self ._venv_check_index = 0
13791423 self ._venv_check_pip_exe = pip_exe
13801424 self ._venv_check_path = venv_path
@@ -1384,7 +1428,9 @@ def _after_binding(ok_bind: bool):
13841428 self ._bind_cancel_for_dialog (
13851429 self .venv_check_progress , "vérification des outils du venv"
13861430 )
1387- self .venv_check_progress .set_message ("Vérification de PyInstaller..." )
1431+ self .venv_check_progress .set_message (
1432+ f"Vérification de { self ._venv_check_pkgs [0 ]} ..."
1433+ )
13881434 self .venv_check_progress .set_progress (0 , len (self ._venv_check_pkgs ))
13891435 self .venv_check_progress .show ()
13901436 self ._check_next_venv_pkg ()
@@ -1692,8 +1738,7 @@ def _score_venv(self, venv_path: str, workspace_dir: str) -> tuple[int, str]:
16921738
16931739 Scoring criteria:
16941740 - Has requirements.txt satisfied: +100
1695- - Has pyinstaller: +50
1696- - Has nuitka: +50
1741+ - Has required engine python tools: +50 each
16971742 - Has pip/setuptools/wheel: +30
16981743 - Is valid venv: +10
16991744 - Has binding verified: +20
@@ -1727,14 +1772,10 @@ def _score_venv(self, venv_path: str, workspace_dir: str) -> tuple[int, str]:
17271772 reasons .append ("requirements_unknown" )
17281773
17291774 # Check for key tools
1730- tools_to_check = [
1731- ("pyinstaller" , 50 ),
1732- ("nuitka" , 50 ),
1733- ("cx_freeze" , 50 ),
1734- ]
1735- for tool , tool_score in tools_to_check :
1775+ tools_to_check = self ._discover_engine_required_python_tools ()
1776+ for tool in tools_to_check :
17361777 if self .has_tool_binary (venv_path , tool ):
1737- score += tool_score
1778+ score += 50
17381779 reasons .append (f"has_{ tool } " )
17391780
17401781 # Check for pip/setuptools/wheel
@@ -1940,7 +1981,7 @@ def create_venv_if_needed(self, path: str, prefer_manager: bool = True):
19401981 self ._arm_process_timeout (process , 600_000 , "venv creation" )
19411982 except Exception as e :
19421983 self ._safe_log (
1943- f"❌ Échec de création du venv ou installation de PyInstaller : { e } "
1984+ f"❌ Échec de création du venv ou installation des outils : { e } "
19441985 )
19451986
19461987 def _on_venv_output (self , process , error = False ):
@@ -3270,7 +3311,7 @@ def setup_workspace(self, workspace_dir: str, check_tools: bool = True) -> bool:
32703311
32713312 Args:
32723313 workspace_dir: Path to the workspace directory
3273- check_tools: Whether to check and install tools (pyinstaller, nuitka, cx_freeze)
3314+ check_tools: Whether to check and install tools required by discovered engines
32743315 after venv creation. Defaults to True.
32753316
32763317 Returns:
0 commit comments