Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • workflow/processview
1 result
Show changes
Commits on Source (8)
from __future__ import annotations
import time
import numpy
import threading
from silx.gui import qt
from typing import Optional
from processview.gui.processmanager import ProcessManagerWindow
from processview.core.superviseprocess import SuperviseProcess
from processview.core.dataset import Dataset
......@@ -9,7 +13,7 @@ from processview.gui.processmanager import ProcessManager
import datetime
class _DummyScan(Dataset):
class _DummyDataset(Dataset):
def __init__(self, name):
super().__init__()
self.__name = name
......@@ -49,12 +53,66 @@ window.show()
p1 = SuperviseProcess(name="process1")
p2 = SuperviseProcess(name="process2")
scan_1 = _DummyScan("scan1")
scan_2 = _DummyScan("scan2 with a very long name ... really long")
p3 = SuperviseProcess(name="process3")
manager = ProcessManager()
manager.notify_dataset_state(dataset=scan_1, state=DatasetState.PENDING, process=p1)
manager.notify_dataset_state(dataset=scan_2, state=DatasetState.SUCCEED, process=p1)
manager.notify_dataset_state(dataset=scan_2, state=DatasetState.FAILED, process=p2)
class RecursiveThread(threading.Thread):
def __init__(self, execute_each: int):
self.running = True
self.execute_each = execute_each
super().__init__()
def run(self):
"""Method implementing thread loop that updates the plot"""
while self.running:
time.sleep(self.execute_each)
self.process()
def process(self):
raise NotImplementedError()
def stop(self):
"""Stop the update thread"""
self.running = False
self.join(2)
class CreateNewDataset(RecursiveThread):
"""Thread creating a new dataset each n seconds"""
def process(self):
dataset = _DummyDataset(f"scan {numpy.random.randint(0, 999999)}")
manager.notify_dataset_state(
dataset=dataset, state=DatasetState.PENDING, process=p1
)
class UpdateDataset(RecursiveThread):
"""Thread that will update randomly one of the existing dataset"""
def process(self):
datasets = manager.get_datasets()
if len(datasets) == 0:
return
dataset_to_update = numpy.random.choice(datasets)
state = numpy.random.choice(DatasetState)
process = numpy.random.choice(manager.get_processes())
manager.notify_dataset_state(
dataset=dataset_to_update,
state=state,
process=process,
)
create_new_dataset_thread = CreateNewDataset(execute_each=3)
create_new_dataset_thread.start()
update_dataset_thread = UpdateDataset(execute_each=1)
update_dataset_thread.start()
app.exec_()
create_new_dataset_thread.stop()
update_dataset_thread.stop()
# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# ###########################################################################*/
__authors__ = ["H. Payno"]
__license__ = "MIT"
__date__ = "03/11/2020"
from __future__ import annotations
from processview.utils.singleton import singleton
from processview.core.dataset import Dataset
......@@ -62,7 +34,7 @@ class ProcessManager:
def __init__(self):
self._processes = {}
self._dataset_process_states = {}
self._dataset_process_states: dict[int, dict[str, tuple]] = {}
"""key is processID, Value is a tuple of
(dataset state, details)"""
self._processID = 0
......@@ -154,7 +126,6 @@ class ProcessManager:
"""
:return: tuple of processes currently registered
:rtype: tuple
"""
processes = []
for _, p in self._processes.items():
......@@ -182,10 +153,15 @@ class ProcessManager:
"""
dataset_id = self._find_dataset_id(dataset)
for process_id in self._dataset_process_states:
if dataset_id in self._dataset_process_states[process_id]:
self._dataset_process_states[process_id].pop(dataset_id)
def notify_dataset_state(self, dataset, process, state, details=None) -> None:
self._dataset_process_states[process_id].pop(dataset_id, None)
def notify_dataset_state(
self,
dataset: Dataset | DatasetIdentifier,
process,
state: DatasetState,
details=None,
) -> None:
"""
Update dataset state
......@@ -209,7 +185,14 @@ class ProcessManager:
self._dataset_process_states[process.process_id] = OrderedDict()
if details is None:
details = ""
dataset_id = dataset.get_identifier()
if isinstance(dataset, Dataset):
dataset_id = dataset.get_identifier()
else:
dataset_id = dataset
if not isinstance(dataset_id, DatasetIdentifier):
raise TypeError(
f"dataset should be an instance of {Dataset} or {DatasetIdentifier}. Got {type(dataset)}"
)
# as we store the identifier and not a string anymore we might need to remove another instanciation
process_states = self._dataset_process_states[process.process_id]
to_remove = set()
......@@ -253,7 +236,6 @@ class ProcessManager:
:param Dataset dataset_id:
:param BaseProcess process:
:return: DatasetState relative to provided process if know
:rtype: Union[None, DatasetState]
"""
dataset_id = self._find_dataset_id(dataset_id)
process = self._find_process(process)
......@@ -273,7 +255,6 @@ class ProcessManager:
:param Dataset dataset_id:
:param BaseProcess process:
:return: DatasetState relative to provided process if know
:rtype: Union[None, DatasetState]
"""
dataset_id = self._find_dataset_id(dataset_id)
process = self._find_process(process)
......@@ -287,14 +268,15 @@ class ProcessManager:
return self._dataset_process_states[process.process_id][dataset_id][1]
return None
def get_dataset_stream(self, dataset, time_stamp=False) -> tuple:
def get_dataset_stream(
self, dataset, time_stamp=False
) -> tuple[int, DatasetState, list]:
"""
:param Dataset dataset: dataset the stream is focus on
:param bool time_stamp: if True then return timestamp in the list of
elements
:return: stream of (process ID, DatasetState) for a given dataset
:rtype: tuple of (process ID, DatasetState, [timestamp])
"""
stream = []
for process_id, dataset_states in self._dataset_process_states.items():
......@@ -316,7 +298,6 @@ class ProcessManager:
:param bool time_stamp: if True then return timestamp in the list of
elements
:return: tuple of (DatasetIdentifier, state, [timestamp])
:rtype: tuple
"""
history = []
if process.process_id in self._dataset_process_states:
......
# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# ###########################################################################*/
__authors__ = ["H. Payno"]
__license__ = "MIT"
__date__ = "03/11/2020"
from __future__ import annotations
import fnmatch
from collections import OrderedDict
......@@ -83,8 +54,8 @@ class ObservationTable(qt.QTableView):
self.dataset_menu = qt.QMenu()
self._copyAction = qt.QAction("copy")
self.dataset_menu.addAction(self._copyAction)
self._clearAction = qt.QAction("clear")
self.dataset_menu.addAction(self._clearAction)
self._removeAction = qt.QAction("remove")
self.dataset_menu.addAction(self._removeAction)
# QMenu for cell from on dataset and one process
self.menu_dataset_vs_process = qt.QMenu()
......@@ -94,14 +65,14 @@ class ObservationTable(qt.QTableView):
self.menu_dataset_vs_process.addAction(self._cancelAction)
self._infoAction = qt.QAction("info")
self.menu_dataset_vs_process.addAction(self._infoAction)
self.menu_dataset_vs_process.addAction(self._clearAction)
self.menu_dataset_vs_process.addAction(self._removeAction)
self._target = (None, None)
# register target of the last menu (process, DatasetIdentifier)
# connect signal / slot
self._copyAction.triggered.connect(self._requestDatasetIdCopy)
self._clearAction.triggered.connect(self._requestClearDataset)
self._removeAction.triggered.connect(self._requestRemoveDataset)
self._reprocessAction.triggered.connect(self._requestReprocessing)
self._infoAction.triggered.connect(self._requestInfo)
self._cancelAction.triggered.connect(self._requestCancelProcessing)
......@@ -163,7 +134,7 @@ class ObservationTable(qt.QTableView):
clipboard = qt.QGuiApplication.clipboard()
clipboard.setText(dataset.to_str())
def _requestClearDataset(self, *args, **kwargs):
def _requestRemoveDataset(self, *args, **kwargs):
def get_dataset_at(row: int):
datasets = self.model()._sorted_datasets
return datasets.get(
......
......@@ -92,7 +92,7 @@ class TestProcessManager(TestCaseQt):
)
window._centralWidget.observationTable.selectAll()
window._centralWidget.observationTable._requestClearDataset()
window._centralWidget.observationTable._requestRemoveDataset()
self.qapp.processEvents()
assert len(manager.manager._dataset_process_states[p1.process_id]) == 0
manager.notify_dataset_state(
......