Exemple : Services Gaphor

Dans cet exemple, nous faisons quelque chose d’un peu moins trivial. Dans Gaphor, les services sont définis comme des points d’entrée entry points. Chaque service est une classe et prend des paramètres dont les noms correspondent à ceux d’autres services. Cela permet aux services de dépendre d’autres services.

Il se présente comme suit :

# entry point name: my_service
class MyService:
    ...

# entry point name: my_other_service
class MyOtherService:
    def __init__(self, my_service):
        ...

Commençons par charger les points d’entrée.

from gaphor.entrypoint import load_entry_points

entry_points = load_entry_points("gaphor.services")

entry_points
{'auto_layout': gaphor.plugins.autolayout.pydot.AutoLayoutService,
 'component_registry': gaphor.services.componentregistry.ComponentRegistry,
 'console_window': gaphor.plugins.console.consolewindow.ConsoleWindow,
 'diagram_align': gaphor.ui.diagramalign.DiagramAlign,
 'diagram_export': gaphor.plugins.diagramexport.export.DiagramExport,
 'diagrams': gaphor.ui.diagrams.Diagrams,
 'element_dispatcher': gaphor.core.modeling.elementdispatcher.ElementDispatcher,
 'element_editor': gaphor.ui.elementeditor.ElementEditor,
 'element_factory': gaphor.core.modeling.elementfactory.ElementFactory,
 'event_manager': gaphor.core.eventmanager.EventManager,
 'export_menu': gaphor.ui.menufragment.MenuFragment,
 'file_manager': gaphor.ui.filemanager.FileManager,
 'html_report': gaphor.plugins.htmlreport.report.HtmlReportExport,
 'main_window': gaphor.ui.mainwindow.MainWindow,
 'model_browser': gaphor.ui.modelbrowser.ModelBrowser,
 'model_changed': gaphor.ui.modelchanged.ModelChanged,
 'modeling_language': gaphor.services.modelinglanguage.ModelingLanguageService,
 'properties': gaphor.services.properties.Properties,
 'recent_files': gaphor.ui.recentfiles.RecentFiles,
 'recovery': gaphor.storage.recovery.Recovery,
 'sanitizer': gaphor.UML.sanitizerservice.SanitizerService,
 'toolbox': gaphor.ui.toolbox.Toolbox,
 'tools_menu': gaphor.ui.menufragment.MenuFragment,
 'undo_actions': gaphor.ui.undoactions.UndoActions,
 'undo_manager': gaphor.services.undomanager.UndoManager}

Créons maintenant un composant dans notre modèle pour chaque service.

from gaphor import UML
from gaphor.core.modeling import ElementFactory

element_factory = ElementFactory()

def create_component(name):
    c = element_factory.create(UML.Component)
    c.name = name
    return c

components = {name: create_component(name) for name in entry_points}
components
{'auto_layout': <gaphor.UML.uml.Component element d9d92206-6710-11f1-b8ca-6ac0e6dacdf2>,
 'component_registry': <gaphor.UML.uml.Component element d9d9288c-6710-11f1-b8ca-6ac0e6dacdf2>,
 'console_window': <gaphor.UML.uml.Component element d9d92b7a-6710-11f1-b8ca-6ac0e6dacdf2>,
 'diagram_align': <gaphor.UML.uml.Component element d9d92dc8-6710-11f1-b8ca-6ac0e6dacdf2>,
 'diagram_export': <gaphor.UML.uml.Component element d9d93020-6710-11f1-b8ca-6ac0e6dacdf2>,
 'diagrams': <gaphor.UML.uml.Component element d9d93250-6710-11f1-b8ca-6ac0e6dacdf2>,
 'element_dispatcher': <gaphor.UML.uml.Component element d9d9346c-6710-11f1-b8ca-6ac0e6dacdf2>,
 'element_editor': <gaphor.UML.uml.Component element d9d9366a-6710-11f1-b8ca-6ac0e6dacdf2>,
 'element_factory': <gaphor.UML.uml.Component element d9d9387c-6710-11f1-b8ca-6ac0e6dacdf2>,
 'event_manager': <gaphor.UML.uml.Component element d9d93a70-6710-11f1-b8ca-6ac0e6dacdf2>,
 'export_menu': <gaphor.UML.uml.Component element d9d93c6e-6710-11f1-b8ca-6ac0e6dacdf2>,
 'file_manager': <gaphor.UML.uml.Component element d9d93e80-6710-11f1-b8ca-6ac0e6dacdf2>,
 'html_report': <gaphor.UML.uml.Component element d9d94088-6710-11f1-b8ca-6ac0e6dacdf2>,
 'main_window': <gaphor.UML.uml.Component element d9d94286-6710-11f1-b8ca-6ac0e6dacdf2>,
 'model_browser': <gaphor.UML.uml.Component element d9d94484-6710-11f1-b8ca-6ac0e6dacdf2>,
 'model_changed': <gaphor.UML.uml.Component element d9d94678-6710-11f1-b8ca-6ac0e6dacdf2>,
 'modeling_language': <gaphor.UML.uml.Component element d9d94876-6710-11f1-b8ca-6ac0e6dacdf2>,
 'properties': <gaphor.UML.uml.Component element d9d94a74-6710-11f1-b8ca-6ac0e6dacdf2>,
 'recent_files': <gaphor.UML.uml.Component element d9d94d30-6710-11f1-b8ca-6ac0e6dacdf2>,
 'recovery': <gaphor.UML.uml.Component element d9d94ff6-6710-11f1-b8ca-6ac0e6dacdf2>,
 'sanitizer': <gaphor.UML.uml.Component element d9d95212-6710-11f1-b8ca-6ac0e6dacdf2>,
 'toolbox': <gaphor.UML.uml.Component element d9d95410-6710-11f1-b8ca-6ac0e6dacdf2>,
 'tools_menu': <gaphor.UML.uml.Component element d9d9562c-6710-11f1-b8ca-6ac0e6dacdf2>,
 'undo_actions': <gaphor.UML.uml.Component element d9d95834-6710-11f1-b8ca-6ac0e6dacdf2>,
 'undo_manager': <gaphor.UML.uml.Component element d9d95a28-6710-11f1-b8ca-6ac0e6dacdf2>}

Une fois tous les composants mappés, nous pouvons créer des dépendances entre ces composants, sur la base des noms des paramètres du constructeur.

import inspect

for name, cls in entry_points.items():
    for param_name in inspect.signature(cls).parameters:
        if param_name not in components:
            continue

        dep = element_factory.create(UML.Usage)
        dep.client = components[name]
        dep.supplier = components[param_name]

Avec tous les éléments du modèle, nous pouvons créer un diagramme. Déposons les composants et les dépendances sur le diagramme et laissons la mise en page automatique faire sa magie.

Pour que la dépendance ait une bonne apparence, nous devons ajouter une feuille de style. Si vous créez un nouveau diagramme via l’interface graphique, cet élément est automatiquement ajouté.

from gaphor.core.modeling import StyleSheet
from gaphor.diagram.drop import drop

element_factory.create(StyleSheet)
diagram = element_factory.create(UML.Diagram)

for element in element_factory.lselect():
    drop(element, diagram, x=0, y=0)

La dernière étape consiste à mettre en page et à dessiner le diagramme.

from gaphor.extensions.ipython import auto_layout, draw

auto_layout(diagram)

draw(diagram, format="svg")
_images/38a427e1e1757886d8dbe68601f33791443b66d62cbd65d377dfaddfc73692b9.svg

C’est tout. Comme vous pouvez le voir sur le diagramme, beaucoup de services s’appuient sur EventManager.