Example: Gaphor services#
In this example we’re doing something a little less trivial. In Gaphor, services are defined as entry points. Each service is a class, and takes parameters with names that match other services. This allows services to depend on other services.
It looks something like this:
# entry point name: my_service
class MyService:
...
# entry point name: my_other_service
class MyOtherService:
def __init__(self, my_service):
...
Let’s first load the entry points.
from gaphor.entrypoint import load_entry_points
entry_points = load_entry_points("gaphor.services")
entry_points
Settings schema not found and settings won't be saved, run `poe install-schemas`
/home/docs/checkouts/readthedocs.org/user_builds/gaphor/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/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
{'align': gaphor.plugins.align.align.AlignService,
'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}
Now let’s create a component in our model for every 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
{'align': <gaphor.UML.uml.Component element b9359586-8fb6-11ee-8a38-0242ac110002>,
'auto_layout': <gaphor.UML.uml.Component element b93598b0-8fb6-11ee-8a38-0242ac110002>,
'component_registry': <gaphor.UML.uml.Component element b9359a2c-8fb6-11ee-8a38-0242ac110002>,
'console_window': <gaphor.UML.uml.Component element b9359b94-8fb6-11ee-8a38-0242ac110002>,
'copy': <gaphor.UML.uml.Component element b9359cd4-8fb6-11ee-8a38-0242ac110002>,
'diagram_export': <gaphor.UML.uml.Component element b9359df6-8fb6-11ee-8a38-0242ac110002>,
'diagrams': <gaphor.UML.uml.Component element b9359f0e-8fb6-11ee-8a38-0242ac110002>,
'element_dispatcher': <gaphor.UML.uml.Component element b935a044-8fb6-11ee-8a38-0242ac110002>,
'element_editor': <gaphor.UML.uml.Component element b935a1a2-8fb6-11ee-8a38-0242ac110002>,
'element_factory': <gaphor.UML.uml.Component element b935a2a6-8fb6-11ee-8a38-0242ac110002>,
'event_manager': <gaphor.UML.uml.Component element b935a3a0-8fb6-11ee-8a38-0242ac110002>,
'export_menu': <gaphor.UML.uml.Component element b935a49a-8fb6-11ee-8a38-0242ac110002>,
'file_manager': <gaphor.UML.uml.Component element b935a58a-8fb6-11ee-8a38-0242ac110002>,
'main_window': <gaphor.UML.uml.Component element b935a670-8fb6-11ee-8a38-0242ac110002>,
'model_browser': <gaphor.UML.uml.Component element b935a756-8fb6-11ee-8a38-0242ac110002>,
'modeling_language': <gaphor.UML.uml.Component element b935a83c-8fb6-11ee-8a38-0242ac110002>,
'properties': <gaphor.UML.uml.Component element b935a918-8fb6-11ee-8a38-0242ac110002>,
'recent_files': <gaphor.UML.uml.Component element b935a9fe-8fb6-11ee-8a38-0242ac110002>,
'sanitizer': <gaphor.UML.uml.Component element b935aada-8fb6-11ee-8a38-0242ac110002>,
'toolbox': <gaphor.UML.uml.Component element b935abc0-8fb6-11ee-8a38-0242ac110002>,
'tools_menu': <gaphor.UML.uml.Component element b935aca6-8fb6-11ee-8a38-0242ac110002>,
'undo_manager': <gaphor.UML.uml.Component element b935ae68-8fb6-11ee-8a38-0242ac110002>,
'xmi_export': <gaphor.UML.uml.Component element b935b002-8fb6-11ee-8a38-0242ac110002>}
With all components mapped, we can create dependencies between those components, based on the constructor parameter names.
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]
With all elements in the model, we can create a diagram. Let’s drop the components and dependencies on the diagram and let auto-layout do its magic.
To make the dependency look good, we have to add a style sheet. If you create a new diagram via the GUI, this element is automatically added.
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)
Last step is to layout and draw the diagram.
from gaphor.extensions.ipython import auto_layout, draw
auto_layout(diagram)
draw(diagram, format="svg")
That’s all. As you can see from the diagram, a lot of services rely on
EventManager
.