Plugins#

DataLab prend en charge une architecture de plugin robuste, permettant aux utilisateurs d’étendre les fonctionnalités de l’application sans modifier son noyau. Les plugins peuvent introduire de nouveaux outils de traitement, des formats d’importation/exportation de données ou des éléments d’interface graphique personnalisés, le tout intégré de manière transparente dans la plateforme.

Qu’est-ce qu’un plugin ?#

Un plugin est un module Python qui est automatiquement chargé par DataLab au démarrage. Il peut définir de nouvelles fonctionnalités ou modifier des fonctionnalités existantes.

Pour être reconnu comme un plugin, le fichier doit :

  • Être un module Python dont le nom commence par datalab_ (par exemple datalab_myplugin.py),

  • Contenir une classe qui hérite de datalab.plugins.PluginBase,

  • Inclure un attribut de classe nommé PLUGIN_INFO, qui doit être une instance de datalab.plugins.PluginInfo,

  • Implémenter la méthode create_actions.

Cet objet PLUGIN_INFO est utilisé par DataLab pour récupérer des métadonnées telles que le nom du plugin, le type et l’intégration dans le menu.

Note

Seuls les fichiers Python dont les noms commencent par datalab_ seront analysés pour les plugins.

DataLab prend en charge trois catégories de plugins, chacune ayant son propre objectif et mécanisme d’enregistrement :

  • Plugins de traitement et de visualisation Ajoutent des actions personnalisées pour le traitement des signaux ou des images. Cela peut inclure de nouvelles fonctions de calcul, des outils de visualisation de données ou des boîtes de dialogue interactives. Intégré dans un sous-menu dédié du menu « Plugins ».

  • Plugins d’entrée/sortie Définissent de nouveaux formats de fichiers (lecture et/ou écriture) gérés de manière transparente par le framework d’entrée/sortie de DataLab. Ces plugins étendent la compatibilité avec des formats de données personnalisés ou tiers.

  • Plugins HDF5 Plugins spéciaux qui prennent en charge les fichiers HDF5 avec des structures d’arbre spécifiques au domaine. Ceux-ci permettent à DataLab d’interpréter des signaux ou des images organisés de manière non standard.

Où est positionné un plugin ?#

Les plugins sont automatiquement découverts au démarrage à partir de plusieurs emplacements :

  • Le répertoire des plugins utilisateur : Typiquement ~/.DataLab/plugins sur Linux/macOS ou C:/Users/YourName/.DataLab/plugins sur Windows.

  • Un répertoire de plugin personnalisé : Configurable dans les préférences de DataLab.

  • Le répertoire de distribution autonome : Si vous utilisez une version gelée (autonome), le dossier plugins situé à côté de l’exécutable est analysé.

  • Le dossier interne datalab/plugins (non recommandé pour les plugins utilisateur) : Cet emplacement est réservé aux plugins intégrés ou fournis et ne doit pas être modifié manuellement.

Gestion des plugins dans DataLab#

Le menu Plugins propose deux actions dédiées :

  • Configurer les plugins… Ouvre la boîte de dialogue de configuration des plugins, où vous pouvez activer ou désactiver les plugins individuellement. Après enregistrement des modifications, DataLab peut recharger immédiatement les plugins sans redémarrer l’application.

  • Recharger les plugins Recharge les modules de plugins depuis le disque sans redémarrer DataLab.

Lors du rechargement des plugins, DataLab effectue les étapes suivantes :

  1. Désenregistrer les plugins actuellement actifs,

  2. Effacer les actions de plugins des panneaux signal et image,

  3. Redécouvrir et recharger les modules de plugins,

  4. Réenregistrer les plugins activés,

  5. Recréer les actions des plugins et rafraîchir les menus.

Ce flux permet un développement itératif des plugins pendant que DataLab est en cours d’exécution.

Note

L’état d’activation/désactivation des plugins est conservé dans les paramètres de DataLab. Les plugins désactivés restent listés dans la boîte de dialogue de configuration et peuvent être réactivés plus tard. Le réglage global des plugins tiers dans les préférences est lui aussi appliqué immédiatement : le désactiver supprime les actions des plugins et grise le menu Plugins ainsi que l’indicateur d’état, tandis que le réactiver recharge automatiquement les plugins.

Rechargement à chaud pour le développement de plugins#

La fonctionnalité de rechargement à chaud est conçue pour accélérer le cycle de développement des plugins. Voici le workflow recommandé :

  1. Démarrer DataLab normalement.

  2. Créer ou modifier votre fichier plugin (par exemple datalab_myplugin.py) dans l’un des répertoires de plugins (par exemple ~/.DataLab/plugins).

  3. Dans DataLab, utiliser Plugins > Recharger les plugins pour prendre en compte les modifications instantanément.

  4. Tester les actions du plugin directement dans l’application en cours d’exécution.

  5. Itérer : modifier le fichier, recharger, tester — sans redémarrer DataLab.

Pour activer ou désactiver sélectivement des plugins pendant le développement, utiliser Plugins > Configurer les plugins…. La boîte de dialogue liste tous les plugins découverts avec leur nom, version, description et chemin de fichier. L’activation/désactivation d’un plugin prend effet immédiatement après la fermeture de la boîte de dialogue.

Aides de l’API plugin#

Les plugins qui héritent de datalab.plugins.PluginBase ont un accès direct à des aides utiles :

  • self.signalpanel et self.imagepanel : accès aux API de panneaux et aux gestionnaires d’actions,

  • self.proxy : une instance de datalab.control.proxy.LocalProxy pour créer des objets et lancer des traitements,

  • show_warning, show_error, show_info, ask_yesno : méthodes pratiques pour les boîtes de dialogue,

  • edit_new_signal_parameters et edit_new_image_parameters : aides pour les boîtes de dialogue de paramètres d’objet.

Ces aides simplifient le code des plugins et le maintiennent cohérent avec le comportement de DataLab.

Comment développer un plugin ?#

La méthode recommandée pour développer un plugin est de dériver d’un exemple existant et de l’adapter à vos besoins. Vous pouvez explorer le code source dans le dossier datalab/plugins ou vous référer aux exemples fournis par la communauté.

Note

La plupart des fonctionnalités de traitement des signaux et des images de DataLab ont été externalisées dans une bibliothèque dédiée appelée Sigima (https://sigima.readthedocs.io/fr/latest/). Lors du développement de plugins DataLab, vous importerez et utiliserez généralement de nombreuses fonctions et fonctionnalités de Sigima pour effectuer des tâches de traitement, d’analyse et de visualisation des données. Sigima fournit un ensemble complet d’outils pour la manipulation des données scientifiques qui peut être exploité directement dans vos plugins.

Pour développer dans votre environnement Python habituel (par exemple, avec un IDE comme Spyder), vous pouvez :

  1. Installer DataLab dans votre environnement Python, en utilisant l’une des méthodes suivantes :

  2. Ou ajoutez manuellement le package `datalab` à votre chemin Python :

    • Téléchargez le code source depuis la page PyPI,

    • Décompressez l’archive,

    • Ajoutez le répertoire datalab à votre PYTHONPATH (par exemple, en utilisant le Gestionnaire PYTHONPATH dans Spyder).

Note

Même si vous avez installé datalab dans votre environnement, vous ne pouvez pas exécuter l’application DataLab complète directement depuis un IDE. Vous devez lancer DataLab via la ligne de commande ou en utilisant le raccourci créé par l’installateur pour tester correctement votre plugin.

Exemple : plugin de traitement#

Voici un exemple minimal d’un plugin qui imprime un message lorsqu’il est activé :

# Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.

"""
Test Data Plugin for DataLab
----------------------------

This plugin is an example of DataLab plugin. It provides test data samples
and some actions to test DataLab functionalities.
"""

from __future__ import annotations

import sigima.tests.data as test_data
from sigima.io.image import ImageIORegistry
from sigima.io.signal import SignalIORegistry
from sigima.tests import helpers

from datalab.config import _
from datalab.plugins import PluginBase, PluginInfo
from datalab.utils.qthelpers import create_progress_bar

# ------------------------------------------------------------------------------
# All computation functions must be defined as global functions, otherwise
# they cannot be pickled and sent to the worker process
# ------------------------------------------------------------------------------


class PluginTestData(PluginBase):
    """DataLab Test Data Plugin"""

    PLUGIN_INFO = PluginInfo(
        name=_("Test data"),
        version="1.0.0",
        description=_("Testing DataLab functionalities"),
    )

    def load_test_objs(
        self, registry_class: type[SignalIORegistry | ImageIORegistry], title: str
    ) -> None:
        """Load all test objects from a given registry class

        Args:
            registry_class: Registry class (SignalIORegistry or ImageIORegistry)
            title: Progress bar title

        Returns:
            List of (filename, object) tuples
        """
        test_objs = list(helpers.read_test_objects(registry_class))
        with create_progress_bar(self.signalpanel, title, max_=len(test_objs)) as prog:
            for i_obj, (_fname, obj) in enumerate(test_objs):
                prog.setValue(i_obj + 1)
                if prog.wasCanceled():
                    break
                if obj is not None:
                    self.proxy.add_object(obj)

    # Signal processing features ------------------------------------------------
    def create_paracetamol_signal(self) -> None:
        """Create paracetamol signal"""
        obj = test_data.create_paracetamol_signal()
        self.proxy.add_object(obj)

    # Image processing features ------------------------------------------------
    def create_peak_image(self) -> None:
        """Create 2D peak image"""
        obj = self.imagepanel.new_object(add_to_panel=False)
        if obj is not None:
            param = test_data.PeakDataParam.create(size=max(obj.data.shape))
            self.imagepanel.processor.update_param_defaults(param)
            if param.edit(self.main):
                obj.data, _coords = test_data.get_peak2d_data(param)
                self.proxy.add_object(obj)

    def create_sincos_image(self) -> None:
        """Create 2D sin cos image"""
        newparam = self.edit_new_image_parameters(hide_type=True)
        if newparam is not None:
            obj = test_data.create_sincos_image(newparam)
            self.proxy.add_object(obj)

    def create_noisy_gaussian_image(self) -> None:
        """Create 2D noisy gauss image"""
        newparam = self.edit_new_image_parameters(hide_height=True, hide_type=True)
        if newparam is not None:
            obj = test_data.create_noisy_gaussian_image(newparam, add_annotations=False)
            self.proxy.add_object(obj)

    def create_multigaussian_image(self) -> None:
        """Create 2D multi gauss image"""
        newparam = self.edit_new_image_parameters(hide_height=True, hide_type=True)
        if newparam is not None:
            obj = test_data.create_multigaussian_image(newparam)
            self.proxy.add_object(obj)

    def create_2dstep_image(self) -> None:
        """Create 2D step image"""
        newparam = self.edit_new_image_parameters(hide_type=True)
        if newparam is not None:
            obj = test_data.create_2dstep_image(newparam)
            self.proxy.add_object(obj)

    def create_ring_image(self) -> None:
        """Create 2D ring image"""
        param = test_data.RingParam(_("Ring"))
        if param.edit(self.main):
            obj = test_data.create_ring_image(param)
            self.proxy.add_object(obj)

    def create_annotated_image(self) -> None:
        """Create annotated image"""
        obj = test_data.create_annotated_image()
        self.proxy.add_object(obj)

    def create_grid_gaussian_image(self) -> None:
        """Create image with a grid of gaussian spots"""
        param = test_data.GridOfGaussianImages(_("Grid of Gaussian Images"))
        if param.edit(self.main):
            obj = test_data.create_grid_of_gaussian_images(param)
            self.proxy.add_object(obj)

    def _load_all_test_signals(self) -> None:
        """Load all test signals."""
        self.load_test_objs(SignalIORegistry, _("Load all test signals"))

    def _load_all_test_images(self) -> None:
        """Load all test images."""
        self.load_test_objs(ImageIORegistry, _("Load all test images"))

    # Plugin menu entries ------------------------------------------------------
    def create_actions(self) -> None:
        """Create actions"""
        # Signal Panel ----------------------------------------------------------
        sah = self.signalpanel.acthandler
        with sah.new_menu(_("Test data")):
            sah.new_action(
                _("Load spectrum of paracetamol"),
                triggered=self.create_paracetamol_signal,
                select_condition="always",
            )
            _title = _("Load all test signals")
            sah.new_action(
                _("Load all test signals"),
                triggered=self._load_all_test_signals,
                select_condition="always",
                separator=True,
            )
        # Image Panel -----------------------------------------------------------
        iah = self.imagepanel.acthandler
        with iah.new_menu(_("Test data")):
            iah.new_action(
                _("Create image with peaks"),
                triggered=self.create_peak_image,
                select_condition="always",
                separator=True,
            )
            iah.new_action(
                _("Create 2D sin cos image"),
                triggered=self.create_sincos_image,
                select_condition="always",
            )
            iah.new_action(
                _("Create 2D noisy gaussian image"),
                triggered=self.create_noisy_gaussian_image,
                select_condition="always",
            )
            iah.new_action(
                _("Create 2D multi gaussian image"),
                triggered=self.create_multigaussian_image,
                select_condition="always",
            )
            iah.new_action(
                _("Create annotated image"),
                triggered=self.create_annotated_image,
                select_condition="always",
            )
            iah.new_action(
                _("Create 2D step image"),
                triggered=self.create_2dstep_image,
                select_condition="always",
            )
            iah.new_action(
                _("Create ring image"),
                triggered=self.create_ring_image,
                select_condition="always",
            )
            iah.new_action(
                _("Create image with a grid of gaussian spots"),
                triggered=self.create_grid_gaussian_image,
                select_condition="always",
            )
            _title = _("Load all test images")
            iah.new_action(
                _("Load all test images"),
                triggered=self._load_all_test_images,
                select_condition="always",
                separator=True,
            )

Exemple : plugin d’entrée/sortie#

Voici un exemple simple d’un plugin qui ajoute de nouveaux formats de fichiers à DataLab.

# Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.

"""
Image file formats Plugin for DataLab
-------------------------------------

This plugin is an example of DataLab plugin.
It provides image file formats from cameras, scanners, and other acquisition devices.
"""

import struct

import numpy as np
from sigima.io.base import FormatInfo
from sigima.io.image.base import SingleImageFormatBase

# ==============================================================================
# Thales Pixium FXD file format
# ==============================================================================


class FXDFile:
    """Class implementing Thales Pixium FXD Image file reading feature

    Args:
        fname (str): path to FXD file
        debug (bool): debug mode
    """

    HEADER = "<llllllffl"

    def __init__(self, fname: str = None, debug: bool = False) -> None:
        self.__debug = debug
        self.file_format = None  # long
        self.nbcols = None  # long
        self.nbrows = None  # long
        self.nbframes = None  # long
        self.pixeltype = None  # long
        self.quantlevels = None  # long
        self.maxlevel = None  # float
        self.minlevel = None  # float
        self.comment_length = None  # long
        self.fname = None
        self.data = None
        if fname is not None:
            self.load(fname)

    def __repr__(self) -> str:
        """Return a string representation of the object"""
        info = (
            ("Image width", f"{self.nbcols:d}"),
            ("Image Height", f"{self.nbrows:d}"),
            ("Frame number", f"{self.nbframes:d}"),
            ("File format", f"{self.file_format:d}"),
            ("Pixel type", f"{self.pixeltype:d}"),
            ("Quantlevels", f"{self.quantlevels:d}"),
            ("Min. level", f"{self.minlevel:f}"),
            ("Max. level", f"{self.maxlevel:f}"),
            ("Comment length", f"{self.comment_length:d}"),
        )
        desc_len = max(len(d) for d in list(zip(*info))[0]) + 3
        res = ""
        for description, value in info:
            res += ("{:" + str(desc_len) + "}{}\n").format(description + ": ", value)

        res = object.__repr__(self) + "\n" + res
        return res

    def load(self, fname: str) -> None:
        """Load header and image pixel data

        Args:
            fname (str): path to FXD file
        """
        with open(fname, "rb") as data_file:
            header_s = struct.Struct(self.HEADER)
            record = data_file.read(9 * 4)
            unpacked_rec = header_s.unpack(record)
            (
                self.file_format,
                self.nbcols,
                self.nbrows,
                self.nbframes,
                self.pixeltype,
                self.quantlevels,
                self.maxlevel,
                self.minlevel,
                self.comment_length,
            ) = unpacked_rec
            if self.__debug:
                print(unpacked_rec)
                print(self)
            data_file.seek(128 + self.comment_length)
            if self.pixeltype == 0:
                size, dtype = 4, np.float32
            elif self.pixeltype == 1:
                size, dtype = 2, np.uint16
            elif self.pixeltype == 2:
                size, dtype = 1, np.uint8
            else:
                raise NotImplementedError(f"Unsupported pixel type: {self.pixeltype}")
            block = data_file.read(self.nbrows * self.nbcols * size)
        data = np.frombuffer(block, dtype=dtype)
        self.data = data.reshape(self.nbrows, self.nbcols)


class FXDImageFormat(SingleImageFormatBase):
    """Object representing Thales Pixium (FXD) image file type"""

    FORMAT_INFO = FormatInfo(
        name="Thales Pixium",
        extensions="*.fxd",
        readable=True,
        writeable=False,
    )

    @staticmethod
    def read_data(filename: str) -> np.ndarray:
        """Read data and return it

        Args:
            filename (str): path to FXD file

        Returns:
            np.ndarray: image data
        """
        fxd_file = FXDFile(filename)
        return fxd_file.data


# ==============================================================================
# Dürr NDT XYZ file format
# ==============================================================================


class XYZImageFormat(SingleImageFormatBase):
    """Object representing Dürr NDT XYZ image file type"""

    FORMAT_INFO = FormatInfo(
        name="Dürr NDT",
        extensions="*.xyz",
        readable=True,
        writeable=True,
    )

    @staticmethod
    def read_data(filename: str) -> np.ndarray:
        """Read data and return it

        Args:
            filename (str): path to XYZ file

        Returns:
            np.ndarray: image data
        """
        with open(filename, "rb") as fdesc:
            cols = int(np.fromfile(fdesc, dtype=np.uint16, count=1)[0])
            rows = int(np.fromfile(fdesc, dtype=np.uint16, count=1)[0])
            arr = np.fromfile(fdesc, dtype=np.uint16, count=cols * rows)
            arr = arr.reshape((rows, cols))
        return np.fliplr(arr)

    @staticmethod
    def write_data(filename: str, data: np.ndarray) -> None:
        """Write data to file

        Args:
            filename: File name
            data: Image array data
        """
        data = np.fliplr(data)
        with open(filename, "wb") as fdesc:
            fdesc.write(np.array(data.shape[1], dtype=np.uint16).tobytes())
            fdesc.write(np.array(data.shape[0], dtype=np.uint16).tobytes())
            fdesc.write(data.tobytes())

Exemples de modèles utilisés par la suite de tests#

DataLab fournit aussi des modèles de plugins utilisés par les tests d’intégration dans datalab/tests/features/plugins/templates. Ils servent de références de développement pour :

  • une structure de plugin valide de base,

  • des menus de plugin imbriqués,

  • des plugins avec actions de boîtes de dialogue,

  • des plugins avec de nombreuses actions,

  • des plugins avec de longues descriptions.

Les tests fonctionnels correspondants sont dans datalab/tests/features/plugins/test_plugins.py et couvrent le cycle de vie des plugins, le rechargement à chaud, la gestion des erreurs, les noms en doublon et le filtrage de configuration.

Autres exemples#

D’autres exemples de plugins peuvent être trouvés dans le répertoire plugins/examples du code source de DataLab (explorez ici sur GitHub).

Migration de la v0.20 à la v1.0#

Si vous avez des plugins existants écrits pour DataLab v0.20, veuillez consulter le guide de migration pour des instructions détaillées sur la mise à jour de vos plugins pour fonctionner avec DataLab v1.0.

API publique#

Système de plugins de DataLab#

Le système de plugins de DataLab fournit un moyen d’étendre l’application avec de nouvelles fonctionnalités.

Les plugins sont des modules Python qui reposent sur deux classes :

  • PluginInfo, qui stocke des informations sur le plugin

  • PluginBase, qui est la classe de base pour tous les plugins

Les plugins peuvent également étendre les fonctionnalités d’entrée/sortie de DataLab en fournissant de nouveaux formats d’image ou de signal. Pour ce faire, ils doivent fournir une sous-classe de ImageFormatBase ou SignalFormatBase, dans laquelle les informations de format sont définies à l’aide de la classe FormatInfo.

class datalab.plugins.PluginRegistry(name, bases, attrs)[source]#

Métaclasse pour l’enregistrement des plugins

classmethod get_plugin_classes() list[type[PluginBase]][source]#

Retourne les classes de plugins

classmethod get_plugins() list[PluginBase][source]#

Retourne les instances de plugins

classmethod get_plugin(name_or_class: str | type[PluginBase]) PluginBase | None[source]#

Retourne l’instance de plugin

classmethod register_plugin(plugin: PluginBase)[source]#

Enregistrer le plugin

classmethod unregister_plugin(plugin: PluginBase)[source]#

Désenregistrer le plugin

classmethod unregister_all_plugins()[source]#

Désenregistrer tous les plugins

classmethod clear_plugin_classes() None[source]#

Clear registered plugin classes.

This is mainly useful when reloading plugin modules at runtime.

classmethod add_discovery_error(tb_text: str) None[source]#

Record an error traceback that occurred during plugin discovery.

Paramètres:

tb_text – Formatted traceback string

classmethod get_discovery_errors() list[str][source]#

Return error tracebacks collected during plugin discovery.

Renvoie:

List of formatted traceback strings (may be empty)

classmethod clear_discovery_errors() None[source]#

Clear recorded discovery errors.

classmethod add_failed_plugin(name: str, filepath: str, tb_text: str) None[source]#

Record a plugin that failed to load or instantiate.

Paramètres:
  • name – Module or plugin class name

  • filepath – File path of the plugin module

  • tb_text – Formatted traceback string

classmethod get_failed_plugins() list[FailedPluginInfo][source]#

Return structured info about plugins that failed to load.

Renvoie:

List of FailedPluginInfo objects (may be empty)

classmethod clear_failed_plugins() None[source]#

Clear recorded failed plugin info.

classmethod get_plugin_info(html: bool = True) str[source]#

Retourne les informations sur les plugins (noms, versions, descriptions) au format html

Paramètres:

html – retourner du texte formaté en html (par défaut : True)

class datalab.plugins.FailedPluginInfo(name: str, filepath: str, traceback: str)[source]#

Information about a plugin that failed to load or instantiate.

class datalab.plugins.PluginInfo(name: str = None, version: str = '0.0.0', description: str = '', icon: str = None)[source]#

Informations sur le plugin

class datalab.plugins.PluginBaseMeta(name, bases, namespace, /, **kwargs)[source]#

Métaclasse mixte pour éviter les conflits

class datalab.plugins.PluginBase[source]#

Classe de base du plugin

property signalpanel: SignalPanel#

Retourne le panneau de signal

property imagepanel: ImagePanel#

Retourne le panneau d’image

show_warning(message: str)[source]#

Afficher un message d’avertissement

show_error(message: str)[source]#

Afficher un message d’erreur

show_info(message: str)[source]#

Afficher un message d’information

ask_yesno(message: str, title: str | None = None, cancelable: bool = False) bool[source]#

Poser une question oui/non

edit_new_signal_parameters(title: str | None = None, size: int | None = None) NewSignalParam[source]#

Créer et éditer un nouveau jeu de paramètres de signal

Paramètres:
  • title – titre du nouveau signal

  • size – taille du nouveau signal (par défaut : None, obtenue à partir du signal actuel)

Renvoie:

Nouveau jeu de paramètres de signal (ou None si annulé)

edit_new_image_parameters(title: str | None = None, shape: tuple[int, int] | None = None, hide_height: bool = False, hide_width: bool = False, hide_type: bool = True, hide_dtype: bool = False) NewImageParam | None[source]#

Créer et éditer un nouveau jeu de paramètres d’image

Paramètres:
  • title – titre de la nouvelle image

  • shape – dimensions de la nouvelle image (par défaut : None, obtenues à partir de l’image actuelle)

  • hide_height – masquer le paramètre de la hauteur de l’image (par défaut : False)

  • hide_width – masquer le paramètre de la largeur de l’image (par défaut : False)

  • hide_type – masquer le paramètre de type d’image (par défaut : True)

  • hide_dtype – masquer le paramètre de type de données d’image (par défaut : False)

Renvoie:

Nouveau jeu de paramètres d’image (ou None si annulé)

is_registered()[source]#

Retourne True si le plugin est enregistré

register(main: main.DLMainWindow) None[source]#

Enregistrer le plugin

unregister()[source]#

Désenregistrer le plugin

register_hooks()[source]#

Enregistrer les hooks du plugin

unregister_hooks()[source]#

Désenregistrer les hooks du plugin

abstractmethod create_actions()[source]#

Créer des actions

datalab.plugins.discover_plugins() list[type[PluginBase]][source]#

Découvrir les plugins en utilisant la convention de nommage

This function reloads or imports all modules matching the DataLab plugin naming scheme ("{MOD_NAME}_*"). Plugin classes are then registered automatically via the PluginRegistry metaclass.

Import errors for individual plugins are captured and logged so that one broken plugin does not prevent the others from loading. Error tracebacks are accumulated in PluginRegistry class attributes so that callers (e.g. the main window) can replay them into the internal console once it is ready.

Renvoie:

List of imported/reloaded plugin modules

datalab.plugins.reload_plugin_modules() None[source]#

Reload plugin modules and reset plugin classes.

This helper is intended for hot-reloading plugins at runtime. It:

  • Updates the plugin search path

  • Clears the plugin class registry

  • Reloads or imports all modules matching the plugin naming convention

datalab.plugins.discover_v020_plugins() list[tuple[str, str]][source]#

Découvrir les plugins v0.20 (avec le préfixe cdl_) sans les importer

Renvoie:

Liste des tuples (nom_du_plugin, chemin_du_répertoire) pour les plugins v0.20 découverts

datalab.plugins.get_available_plugins() list[PluginBase][source]#

Instancier et obtenir les plugins disponibles

Renvoie:

Liste des plugins disponibles (en tant qu’instances)