Skip to content

Commit 6e7189e

Browse files
committed
bcasl: corriger ouverture du loader et eviter les doubles lancements
- fixe l'import de dialogue BCASL avec fallback robuste - garantit une connexion unique du bouton BC en mode IDE - ajoute un fallback de decouverte des plugins pour eviter les tabs vides
1 parent db655ea commit 6e7189e

3 files changed

Lines changed: 121 additions & 2 deletions

File tree

Core/IdeLikeGui/connections.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,28 @@ def _open_theme_dialog(self) -> None:
418418
_apply_activity_buttons_theme(self)
419419

420420

421+
def _open_bcasl_loader(self) -> None:
422+
"""Open BCASL dialog with a resilient runtime import path."""
423+
try:
424+
from importlib import import_module
425+
426+
mod = import_module("bcasl.Loader")
427+
fn = getattr(mod, "open_bc_loader_dialog", None)
428+
if callable(fn):
429+
fn(self)
430+
return
431+
except Exception:
432+
pass
433+
try:
434+
import bcasl
435+
436+
fn2 = getattr(bcasl, "open_api_loader_dialog", None)
437+
if callable(fn2):
438+
fn2(self)
439+
except Exception:
440+
pass
441+
442+
421443
def _apply_activity_buttons_theme(self) -> None:
422444
"""Ensure activity-bar tool buttons follow current app theme."""
423445
try:
@@ -493,6 +515,15 @@ def _connect_ide_like_signals(self) -> None:
493515
self.btn_nuitka_icon.clicked.connect(self.select_nuitka_icon)
494516
except Exception:
495517
pass
518+
try:
519+
if getattr(self, "btn_bc_loader", None):
520+
try:
521+
self.btn_bc_loader.clicked.disconnect()
522+
except Exception:
523+
pass
524+
self.btn_bc_loader.clicked.connect(lambda: _open_bcasl_loader(self))
525+
except Exception:
526+
pass
496527

497528
_bind_status_updates(self)
498529

Core/UiConnection.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -554,9 +554,29 @@ def _connect_text(widget, handler) -> None:
554554

555555
if self.btn_bc_loader:
556556
try:
557-
from bcasl import open_bc_loader_dialog
557+
from importlib import import_module
558558

559-
self.btn_bc_loader.clicked.connect(lambda: open_bc_loader_dialog(self))
559+
def _open_bc():
560+
try:
561+
# Preferred rich BCASL dialog (plugin config tabs).
562+
mod = import_module("bcasl.Loader")
563+
fn = getattr(mod, "open_bc_loader_dialog", None)
564+
if callable(fn):
565+
fn(self)
566+
return
567+
except Exception:
568+
pass
569+
try:
570+
# Fallback to exported API loader.
571+
import bcasl
572+
573+
fn2 = getattr(bcasl, "open_api_loader_dialog", None)
574+
if callable(fn2):
575+
fn2(self)
576+
except Exception:
577+
pass
578+
579+
self.btn_bc_loader.clicked.connect(_open_bc)
560580
except Exception:
561581
pass
562582

bcasl/Loader.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,74 @@ def _discover_bcasl_plugins(
193193
continue
194194
except Exception:
195195
pass
196+
197+
# Fallback robuste: import package par package et collecte des classes @bc_register
198+
# si le chargement standard n'a rien retourné.
199+
if plugins:
200+
return plugins
201+
try:
202+
import importlib.util as _ilu
203+
import sys as _sys
204+
205+
for pkg_dir in sorted(Plugins_dir.iterdir(), key=lambda p: p.name):
206+
try:
207+
if not pkg_dir.is_dir():
208+
continue
209+
init_py = pkg_dir / "__init__.py"
210+
if not init_py.exists():
211+
continue
212+
mod_name = f"bcasl_fallback_{pkg_dir.name}"
213+
spec = _ilu.spec_from_file_location(
214+
mod_name, str(init_py), submodule_search_locations=[str(pkg_dir)]
215+
)
216+
if spec is None or spec.loader is None:
217+
continue
218+
module = _ilu.module_from_spec(spec)
219+
_sys.modules[mod_name] = module
220+
spec.loader.exec_module(module) # type: ignore[attr-defined]
221+
222+
# Support ancien style: bcasl_register(manager)
223+
try:
224+
reg = getattr(module, "bcasl_register", None)
225+
if callable(reg):
226+
mgr = BCASL(
227+
workspace_root,
228+
config=cfg,
229+
sandbox=False,
230+
plugin_timeout_s=0.0,
231+
)
232+
reg(mgr)
233+
for pid, rec in getattr(mgr, "_registry", {}).items():
234+
try:
235+
plugins[str(pid)] = rec.plugin
236+
except Exception:
237+
continue
238+
except Exception:
239+
pass
240+
241+
# Support style décorateur: classes marquées @bc_register
242+
for attr_name in dir(module):
243+
try:
244+
attr = getattr(module, attr_name, None)
245+
if attr is None or not isinstance(attr, type):
246+
continue
247+
if not getattr(attr, "__bcasl_plugin__", False):
248+
continue
249+
inst = getattr(attr, "_bcasl_instance_", None)
250+
if inst is None:
251+
try:
252+
inst = attr()
253+
except Exception:
254+
continue
255+
pid = getattr(getattr(inst, "meta", None), "id", None)
256+
if isinstance(pid, str) and pid and pid not in plugins:
257+
plugins[pid] = inst
258+
except Exception:
259+
continue
260+
except Exception:
261+
continue
262+
except Exception:
263+
pass
196264
return plugins
197265

198266

0 commit comments

Comments
 (0)