Приклад: послуги Gaphor¶
У цьому прикладі ми робимо дещо менш тривіальне. У Gaphor сервіси визначаються як [точки входу] (https://packaging.python.org/en/latest/specifications/entry-points/). Кожен сервіс є класом і отримує параметри з іменами, які збігаються з іменами інших сервісів. Це дозволяє сервісам залежати від інших сервісів.
Виглядає це приблизно так:
# entry point name: my_service
class MyService:
...
# entry point name: my_other_service
class MyOtherService:
def __init__(self, my_service):
...
Давайте спочатку завантажимо точки входу.
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}
Тепер давайте створимо компонент у нашій моделі для кожної служби.
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 d0cc215c-4651-11f1-9dc3-8e026b8228db>,
'component_registry': <gaphor.UML.uml.Component element d0cc24d6-4651-11f1-9dc3-8e026b8228db>,
'console_window': <gaphor.UML.uml.Component element d0cc2634-4651-11f1-9dc3-8e026b8228db>,
'diagram_align': <gaphor.UML.uml.Component element d0cc271a-4651-11f1-9dc3-8e026b8228db>,
'diagram_export': <gaphor.UML.uml.Component element d0cc27d8-4651-11f1-9dc3-8e026b8228db>,
'diagrams': <gaphor.UML.uml.Component element d0cc288c-4651-11f1-9dc3-8e026b8228db>,
'element_dispatcher': <gaphor.UML.uml.Component element d0cc2968-4651-11f1-9dc3-8e026b8228db>,
'element_editor': <gaphor.UML.uml.Component element d0cc2a1c-4651-11f1-9dc3-8e026b8228db>,
'element_factory': <gaphor.UML.uml.Component element d0cc2abc-4651-11f1-9dc3-8e026b8228db>,
'event_manager': <gaphor.UML.uml.Component element d0cc2b66-4651-11f1-9dc3-8e026b8228db>,
'export_menu': <gaphor.UML.uml.Component element d0cc2c10-4651-11f1-9dc3-8e026b8228db>,
'file_manager': <gaphor.UML.uml.Component element d0cc2cd8-4651-11f1-9dc3-8e026b8228db>,
'html_report': <gaphor.UML.uml.Component element d0cc2d82-4651-11f1-9dc3-8e026b8228db>,
'main_window': <gaphor.UML.uml.Component element d0cc2e22-4651-11f1-9dc3-8e026b8228db>,
'model_browser': <gaphor.UML.uml.Component element d0cc2ec2-4651-11f1-9dc3-8e026b8228db>,
'model_changed': <gaphor.UML.uml.Component element d0cc2f62-4651-11f1-9dc3-8e026b8228db>,
'modeling_language': <gaphor.UML.uml.Component element d0cc3002-4651-11f1-9dc3-8e026b8228db>,
'properties': <gaphor.UML.uml.Component element d0cc30ac-4651-11f1-9dc3-8e026b8228db>,
'recent_files': <gaphor.UML.uml.Component element d0cc314c-4651-11f1-9dc3-8e026b8228db>,
'recovery': <gaphor.UML.uml.Component element d0cc31ec-4651-11f1-9dc3-8e026b8228db>,
'sanitizer': <gaphor.UML.uml.Component element d0cc328c-4651-11f1-9dc3-8e026b8228db>,
'toolbox': <gaphor.UML.uml.Component element d0cc332c-4651-11f1-9dc3-8e026b8228db>,
'tools_menu': <gaphor.UML.uml.Component element d0cc33e0-4651-11f1-9dc3-8e026b8228db>,
'undo_actions': <gaphor.UML.uml.Component element d0cc349e-4651-11f1-9dc3-8e026b8228db>,
'undo_manager': <gaphor.UML.uml.Component element d0cc3548-4651-11f1-9dc3-8e026b8228db>}
Коли всі компоненти зіставлені, ми можемо створювати залежності між цими компонентами на основі імен параметрів конструктора.
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]
З усіма елементами моделі ми можемо створити діаграму. Давайте відкинемо компоненти та залежності на діаграмі та дозволимо автоматичному компонуванню зробити свою магію.
Щоб залежність виглядала добре, нам потрібно додати таблицю стилів. Якщо ви створюєте нову діаграму через GUI, цей елемент додається автоматично.
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)
Останнім кроком є макет і малювання діаграми.
from gaphor.extensions.ipython import auto_layout, draw
auto_layout(diagram)
draw(diagram, format="svg")
Ось і все. Як ви можете бачити на діаграмі, багато служб покладаються на EventManager.