Skip to content
Snippets Groups Projects
Unverified Commit a7e2aec4 authored by Anton Joubert's avatar Anton Joubert
Browse files

Update state machine diagrams

Added a script and Makefile target to generate the
state machine diagrams.  New diagrams included.
parent 6254a441
No related branches found
No related tags found
No related merge requests found
...@@ -17,7 +17,7 @@ SHELL = /bin/bash ...@@ -17,7 +17,7 @@ SHELL = /bin/bash
# #
DOCKER_REGISTRY_USER:=tango-example DOCKER_REGISTRY_USER:=tango-example
PROJECT = lmcbaseclasses PROJECT = lmcbaseclasses
IMAGE_FOR_DIAGRAMS = nexus.engageska-portugal.pt/ska-docker/ska-python-buildenv:9.3.2.1
# #
# include makefile to pick up the standard Make targets, e.g., 'make build' # include makefile to pick up the standard Make targets, e.g., 'make build'
# build, 'make push' docker push procedure, etc. The other Make targets # build, 'make push' docker push procedure, etc. The other Make targets
...@@ -40,10 +40,21 @@ lint: ## lint lmcbaseclasses Python code ...@@ -40,10 +40,21 @@ lint: ## lint lmcbaseclasses Python code
pylint --output-format=pylint2junit.JunitReporter src/ska > build/reports/linting.xml pylint --output-format=pylint2junit.JunitReporter src/ska > build/reports/linting.xml
test-in-docker: build ## Build the docker image and run tests inside it. test-in-docker: build ## Build the docker image and run tests inside it.
@docker run $(IMAGE):$(VERSION) make test @docker run --rm $(IMAGE):$(VERSION) make test
lint-in-docker: build ## Build the docker image and run lint inside it. lint-in-docker: build ## Build the docker image and run lint inside it.
@docker run $(IMAGE):$(VERSION) make lint @docker run --rm $(IMAGE):$(VERSION) make lint
generate-diagrams-in-docker: ## Build the docker image and generate state machine diagrams inside it.
@docker run --rm -v $(PWD):/diagrams $(IMAGE_FOR_DIAGRAMS) bash -c "cd /diagrams && make generate-diagrams-in-docker-internals"
generate-diagrams-in-docker-internals: ## Generate state machine diagrams (within a container!)
test -f /.dockerenv # ensure running in docker container
apt-get update
apt-get install --yes graphviz graphviz-dev gsfonts pkg-config
python3 -m pip install pygraphviz
cd /diagrams/docs/source && python3 draw_state_machines.py
ls -lo /diagrams/docs/source/images/
help: ## show this help. help: ## show this help.
@grep -hE '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' @grep -hE '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
......
...@@ -44,9 +44,6 @@ Diagrams of the admin mode state machine are shown below. ...@@ -44,9 +44,6 @@ Diagrams of the admin mode state machine are shown below.
Diagram of the admin mode state machine, as designed Diagram of the admin mode state machine, as designed
..
COMMENTED OUT FOR NOW
.. figure:: images/AdminModeStateMachine_autogenerated.png .. figure:: images/AdminModeStateMachine_autogenerated.png
:alt: Diagram of the admin mode state machine, as implemented :alt: Diagram of the admin mode state machine, as implemented
...@@ -82,7 +79,7 @@ The operational state state machine allows for: ...@@ -82,7 +79,7 @@ The operational state state machine allows for:
STANDBY and OFF. STANDBY and OFF.
* transition between OFF and ON. * transition between OFF and ON.
.. figure:: images/OperationalStateStateMachine_decoupled.png .. figure:: images/OperationStateMachine_decoupled.png
:alt: Diagram of the operational state state machine, as designed, :alt: Diagram of the operational state state machine, as designed,
ignoring coupling with admin mode ignoring coupling with admin mode
...@@ -110,18 +107,16 @@ separately. ...@@ -110,18 +107,16 @@ separately.
Diagrams of the operational state state machine are shown below. Diagrams of the operational state state machine are shown below.
.. figure:: images/OperationalStateStateMachine_coupled.png .. figure:: images/OperationStateMachine_coupled.png
:alt: Diagram of the operational state state machine, as designed, :alt: Diagram of the operational state state machine, as designed,
showing coupling with admin mode showing coupling with admin mode
Diagram of the operational state (opState) state machine, as Diagram of the operational state (opState) state machine, as
designed, showing coupling with admin mode designed, showing coupling with admin mode
.. .. figure:: images/OperationStateMachine_autogenerated.png
COMMENTED OUT FOR NOW
.. figure:: images/OperationalStateStateMachine_coupled_autogenerated.png
:width: 80% :width: 80%
:alt: Diagram of the admin operational state state machine, as implemented :alt: Diagram of the operational state state machine, as implemented
Diagram of the operational state state machine, automatically Diagram of the operational state state machine, automatically
generated from the implementation. The equivalence of this diagram generated from the implementation. The equivalence of this diagram
......
"""
This module draws diagrams of the state machines.
Usage:
~/ska-src/lmc-base-classes$ docker run --rm -ti -v $PWD:/app continuumio/miniconda3 bash
(base) root@293f3b699c9b:/opt/project/src/ska/base# history
$ conda install --yes pygraphviz
$ pip install transitions
$ apt-get update && apt-get install gsfonts
$ cd /app/docs/source
$ python draw_state_machines.py
(Or see the top level Makefile)
"""
import importlib
import sys
from unittest import mock
from transitions.extensions import GraphMachine
# local import, so we can run this without installing the whole package
sys.path.append("../../src/ska/base")
import state_machine
def patch_in_graph_machine():
with mock.patch("transitions.Machine", GraphMachine):
mod = sys.modules["state_machine"]
importlib.reload(mod)
def draw(machine_class):
machine_name = machine_class.__name__
graphing_options = {
"title": f"\n{machine_name}",
"show_conditions": True,
"show_state_attributes": True,
"show_auto_transitions": False,
}
machine = machine_class(None, **graphing_options)
machine.get_graph().draw(f"images/{machine_name}_autogenerated.png", prog='dot')
if __name__ == "__main__":
patch_in_graph_machine()
draw(state_machine.OperationStateMachine)
draw(state_machine.AdminModeStateMachine)
draw(state_machine.ObservationStateMachine)
docs/source/images/AdminModeStateMachine_autogenerated.png

62.1 KiB

docs/source/images/ObservationStateMachine_autogenerated.png

210 KiB | W: | H:

docs/source/images/ObservationStateMachine_autogenerated.png

233 KiB | W: | H:

docs/source/images/ObservationStateMachine_autogenerated.png
docs/source/images/ObservationStateMachine_autogenerated.png
docs/source/images/ObservationStateMachine_autogenerated.png
docs/source/images/ObservationStateMachine_autogenerated.png
  • 2-up
  • Swipe
  • Onion skin
docs/source/images/OperationStateMachine_autogenerated.png

245 KiB

...@@ -17,13 +17,15 @@ class OperationStateMachine(Machine): ...@@ -17,13 +17,15 @@ class OperationStateMachine(Machine):
administratively disabled. administratively disabled.
""" """
def __init__(self, callback=None): def __init__(self, callback=None, **extra_kwargs):
""" """
Initialises the state model. Initialises the state model.
:param callback: A callback to be called when a transition :param callback: A callback to be called when a transition
implies a change to op state implies a change to op state
:type callback: callable :type callback: callable
:param extra_kwargs: Additional keywords arguments to pass to super class
initialiser (useful for graphing)
""" """
self._callback = callback self._callback = callback
...@@ -203,6 +205,7 @@ class OperationStateMachine(Machine): ...@@ -203,6 +205,7 @@ class OperationStateMachine(Machine):
initial="UNINITIALISED", initial="UNINITIALISED",
transitions=transitions, transitions=transitions,
after_state_change=self._state_changed, after_state_change=self._state_changed,
**extra_kwargs,
) )
def _state_changed(self): def _state_changed(self):
...@@ -219,13 +222,15 @@ class AdminModeStateMachine(Machine): ...@@ -219,13 +222,15 @@ class AdminModeStateMachine(Machine):
The state machine governing admin modes The state machine governing admin modes
""" """
def __init__(self, callback=None): def __init__(self, callback=None, **extra_kwargs):
""" """
Initialises the admin mode state machine model. Initialises the admin mode state machine model.
:param callback: A callback to be called whenever there is a transition :param callback: A callback to be called whenever there is a transition
to a new admin mode value to a new admin mode value
:type callback: callable :type callback: callable
:param extra_kwargs: Additional keywords arguments to pass to super class
initialiser (useful for graphing)
""" """
self._callback = callback self._callback = callback
...@@ -263,6 +268,7 @@ class AdminModeStateMachine(Machine): ...@@ -263,6 +268,7 @@ class AdminModeStateMachine(Machine):
initial="MAINTENANCE", initial="MAINTENANCE",
transitions=transitions, transitions=transitions,
after_state_change=self._state_changed, after_state_change=self._state_changed,
**extra_kwargs,
) )
self._state_changed() self._state_changed()
...@@ -281,12 +287,14 @@ class ObservationStateMachine(Machine): ...@@ -281,12 +287,14 @@ class ObservationStateMachine(Machine):
ADR-8. ADR-8.
""" """
def __init__(self, callback=None): def __init__(self, callback=None, **extra_kwargs):
""" """
Initialises the model. Initialises the model.
:param callback: A callback to be called when the state changes :param callback: A callback to be called when the state changes
:type callback: callable :type callback: callable
:param extra_kwargs: Additional keywords arguments to pass to super class
initialiser (useful for graphing)
""" """
self._callback = callback self._callback = callback
...@@ -442,6 +450,7 @@ class ObservationStateMachine(Machine): ...@@ -442,6 +450,7 @@ class ObservationStateMachine(Machine):
initial="EMPTY", initial="EMPTY",
transitions=transitions, transitions=transitions,
after_state_change=self._state_changed, after_state_change=self._state_changed,
**extra_kwargs,
) )
self._state_changed() self._state_changed()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment