Ejemplo: Servicios de Gaphor#

En este ejemplo estamos haciendo algo un poco menos trivial. En Gaphor, los servicios se definen como puntos de entrada. Cada servicio es una clase, y toma parámetros con nombres que coinciden con otros servicios. Esto permite que los servicios dependan de otros servicios.

Es algo parecido a esto:

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

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

Carguemos primero los puntos de entrada.

from gaphor.entrypoint import load_entry_points

entry_points = load_entry_points("gaphor.services")

entry_points
/home/docs/checkouts/readthedocs.org/user_builds/gaphor-es/envs/latest/lib/python3.11/site-packages/gaphor/diagram/text.py:6: PyGIWarning: Pango was imported without specifying a version first. Use gi.require_version('Pango', '1.0') before import to ensure that the right version gets loaded.
  from gi.repository import Pango, PangoCairo
/home/docs/checkouts/readthedocs.org/user_builds/gaphor-es/envs/latest/lib/python3.11/site-packages/gaphor/diagram/text.py:6: PyGIWarning: PangoCairo was imported without specifying a version first. Use gi.require_version('PangoCairo', '1.0') before import to ensure that the right version gets loaded.
  from gi.repository import Pango, PangoCairo
{'auto_layout': gaphor.plugins.autolayout.pydot.AutoLayoutService,
 'component_registry': gaphor.services.componentregistry.ComponentRegistry,
 'console_window': gaphor.plugins.console.consolewindow.ConsoleWindow,
 'copy': gaphor.ui.copyservice.CopyService,
 'diagram_export': gaphor.plugins.diagramexport.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,
 'main_window': gaphor.ui.mainwindow.MainWindow,
 'model_browser': gaphor.ui.modelbrowser.ModelBrowser,
 'modeling_language': gaphor.services.modelinglanguage.ModelingLanguageService,
 'properties': gaphor.services.properties.Properties,
 'recent_files': gaphor.ui.recentfiles.RecentFiles,
 'sanitizer': gaphor.UML.sanitizerservice.SanitizerService,
 'toolbox': gaphor.ui.toolbox.Toolbox,
 'tools_menu': gaphor.ui.menufragment.MenuFragment,
 'undo_manager': gaphor.services.undomanager.UndoManager,
 'xmi_export': gaphor.plugins.xmiexport.XMIExport}

Ahora vamos a crear un componente en nuestro modelo para cada servicio.

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 1c536296-12db-11ee-9a2e-0242ac110002>,
 'component_registry': <gaphor.UML.uml.Component element 1c536610-12db-11ee-9a2e-0242ac110002>,
 'console_window': <gaphor.UML.uml.Component element 1c536796-12db-11ee-9a2e-0242ac110002>,
 'copy': <gaphor.UML.uml.Component element 1c536908-12db-11ee-9a2e-0242ac110002>,
 'diagram_export': <gaphor.UML.uml.Component element 1c536a52-12db-11ee-9a2e-0242ac110002>,
 'diagrams': <gaphor.UML.uml.Component element 1c536bce-12db-11ee-9a2e-0242ac110002>,
 'element_dispatcher': <gaphor.UML.uml.Component element 1c536ce6-12db-11ee-9a2e-0242ac110002>,
 'element_editor': <gaphor.UML.uml.Component element 1c536e30-12db-11ee-9a2e-0242ac110002>,
 'element_factory': <gaphor.UML.uml.Component element 1c536fd4-12db-11ee-9a2e-0242ac110002>,
 'event_manager': <gaphor.UML.uml.Component element 1c5370e2-12db-11ee-9a2e-0242ac110002>,
 'export_menu': <gaphor.UML.uml.Component element 1c5371e6-12db-11ee-9a2e-0242ac110002>,
 'file_manager': <gaphor.UML.uml.Component element 1c5372ea-12db-11ee-9a2e-0242ac110002>,
 'main_window': <gaphor.UML.uml.Component element 1c5373e4-12db-11ee-9a2e-0242ac110002>,
 'model_browser': <gaphor.UML.uml.Component element 1c5374d4-12db-11ee-9a2e-0242ac110002>,
 'modeling_language': <gaphor.UML.uml.Component element 1c5375c4-12db-11ee-9a2e-0242ac110002>,
 'properties': <gaphor.UML.uml.Component element 1c5376b4-12db-11ee-9a2e-0242ac110002>,
 'recent_files': <gaphor.UML.uml.Component element 1c53779a-12db-11ee-9a2e-0242ac110002>,
 'sanitizer': <gaphor.UML.uml.Component element 1c53788a-12db-11ee-9a2e-0242ac110002>,
 'toolbox': <gaphor.UML.uml.Component element 1c537970-12db-11ee-9a2e-0242ac110002>,
 'tools_menu': <gaphor.UML.uml.Component element 1c537a6a-12db-11ee-9a2e-0242ac110002>,
 'undo_manager': <gaphor.UML.uml.Component element 1c537b50-12db-11ee-9a2e-0242ac110002>,
 'xmi_export': <gaphor.UML.uml.Component element 1c537c40-12db-11ee-9a2e-0242ac110002>}

Con todos los componentes mapeados, podemos crear dependencias entre esos componentes, basándonos en los nombres de los parámetros del constructor.

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]

Con todos los elementos en el modelo, podemos crear un diagrama. Vamos a soltar los componentes y las dependencias en el diagrama y dejar que el diseño automático haga su magia.

Para que la dependencia se vea bien, tenemos que añadir una hoja de estilo. Si crea un diagrama nuevo a través de la interfaz gráfica de usuario, este elemento se añade automáticamente.

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

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

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

El último paso consiste en maquetar y dibujar el diagrama.

from gaphor.extensions.ipython import auto_layout, draw

auto_layout(diagram)

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

Eso es todo. Como puede ver en el diagrama, muchos servicios dependen de EventManager.