Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EWM7751 replaced save tab of reduction with pop up, removed some noisy warnings #482

Merged
merged 4 commits into from
Oct 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def validateInputs(self) -> Dict[str, str]:

if groupingFileExt not in self.supported_xml_file_extensions:
if not self.getProperty("InstrumentDonor").isDefault:
logger.warning("InstrumentDonor will only be used if GroupingFilename is in XML format.")
logger.debug("InstrumentDonor will only be used if GroupingFilename is in XML format.")

instrumentSources = ["InstrumentDonor", "InstrumentName", "InstrumentFilename"]
specifiedSources = [s for s in instrumentSources if not self.getProperty(s).isDefault]
Expand Down
5 changes: 5 additions & 0 deletions src/snapred/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -223,3 +223,8 @@ docs:

metadata:
tagPrefix: SNAPRed_

ui:
default:
workflow:
completionMessage: "‧₊‧₊The workflow has been completed successfully!‧₊‧₊"
12 changes: 7 additions & 5 deletions src/snapred/ui/presenter/WorkflowPresenter.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from typing import Callable, List

from qtpy.QtCore import QObject, Signal, Slot
from qtpy.QtWidgets import QMainWindow
from qtpy.QtWidgets import QMainWindow, QMessageBox

from snapred.backend.api.InterfaceController import InterfaceController
from snapred.backend.error.ContinueWarning import ContinueWarning
Expand Down Expand Up @@ -29,13 +29,16 @@ def __init__(
iterateLambda=None,
resetLambda=None,
cancelLambda=None,
completionMessageLambda=None,
parent=None,
):
super().__init__()

# 'WorkerPool' is a singleton:
# declaring it as an instance attribute, rather than a class attribute,
# allows singleton reset during testing.
self.completionMessageLambda = completionMessageLambda

self.worker_pool = WorkerPool()

self.view = WorkflowView(model, parent)
Expand Down Expand Up @@ -138,11 +141,10 @@ def handleSkipButtonClicked(self):

def advanceWorkflow(self):
if self.view.currentTab >= self.view.totalNodes - 1:
ActionPrompt.prompt(
"‧₊Workflow Complete‧₊",
"‧₊‧₊The workflow has been completed successfully!‧₊‧₊",
lambda: None,
QMessageBox.information(
self.view,
"‧₊Workflow Complete‧₊",
self.completionMessageLambda(),
)
self.reset()
else:
Expand Down
2 changes: 2 additions & 0 deletions src/snapred/ui/widget/Workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ def __init__(
iterateLambda=None,
resetLambda=None,
cancelLambda=None,
completionMessageLambda=None,
parent=None,
):
# default loading subview
Expand All @@ -20,6 +21,7 @@ def __init__(
iterateLambda=iterateLambda,
resetLambda=resetLambda,
cancelLambda=cancelLambda,
completionMessageLambda=completionMessageLambda,
parent=parent,
)

Expand Down
28 changes: 23 additions & 5 deletions src/snapred/ui/workflow/ReductionWorkflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ def __init__(self, parent=None):
startLambda=self.start,
# Retain reduction-output workspaces.
resetLambda=lambda: self.reset(True),
completionMessageLambda=self.completionMessage,
parent=parent,
)
.addNode(
Expand All @@ -50,7 +51,6 @@ def __init__(self, parent=None):
"Reduction",
continueAnywayHandler=self._continueAnywayHandler,
)
.addNode(self._nothing, self._reductionSaveView, "Save")
.build()
)

Expand All @@ -63,6 +63,27 @@ def _enableConvertToUnits(self):
def _nothing(self, workflowPresenter): # noqa: ARG002
return SNAPResponse(code=200)

def completionMessage(self):
panelText = ""
if (
self.continueAnywayFlags is not None
and ContinueWarning.Type.NO_WRITE_PERMISSIONS in self.continueAnywayFlags
):
panelText = (
"<p>You didn't have permissions to write to "
+ f"<br><b>{self.savePath}</b>,<br>"
+ "but you can still save using the workbench tools.</p>"
+ "<p>Please remember to save your output workspaces!</p>"
)
else:
panelText = (
"<p>Reduction has completed successfully!"
+ "<br>Reduction workspaces have been saved to "
+ f"<br><b>{self.savePath}</b>.<br></p>"
+ "<p>If required later, these can be reloaded into Mantid workbench using 'LoadNexus'.</p>"
)
return panelText

@ExceptionToErrLog
def _populatePixelMaskDropdown(self):
if len(self._reductionRequestView.getRunNumbers()) == 0:
Expand Down Expand Up @@ -153,10 +174,7 @@ def _triggerReduction(self, workflowPresenter):
record, unfocusedData = response.data.record, response.data.unfocusedData

# .. update "save" panel message:
savePath = self.request(path="reduction/getSavePath", payload=record.runNumber).data
self._reductionSaveView.updateContinueAnyway(self.continueAnywayFlags)
# Warning: 'updateSavePath' uses the current 'continueAnywayFlags'
self._reductionSaveView.updateSavePath(savePath)
self.savePath = self.request(path="reduction/getSavePath", payload=record.runNumber).data

# Save the reduced data. (This is automatic: it happens before the "save" panel opens.)
if ContinueWarning.Type.NO_WRITE_PERMISSIONS not in self.continueAnywayFlags:
Expand Down
14 changes: 13 additions & 1 deletion src/snapred/ui/workflow/WorkflowBuilder.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
from snapred.meta.Config import Config
from snapred.ui.model.WorkflowNodeModel import WorkflowNodeModel
from snapred.ui.widget.Workflow import Workflow


class WorkflowBuilder:
def __init__(self, *, startLambda=None, iterateLambda=None, resetLambda=None, cancelLambda=None, parent=None):
def __init__(
self,
*,
startLambda=None,
iterateLambda=None,
resetLambda=None,
cancelLambda=None,
parent=None,
completionMessageLambda=lambda: Config["ui.default.workflow.completionMessage"],
Comment on lines +10 to +15
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like I could reduce the number of lambdas by just passing the WorkflowImplementer itself.

):
self.parent = parent
self._startLambda = startLambda
self._iterateLambda = iterateLambda
self._resetLambda = resetLambda
self._cancelLambda = cancelLambda
self._completionMessageLambda = completionMessageLambda
self._workflow = None

def addNode(
Expand Down Expand Up @@ -46,5 +57,6 @@ def build(self):
iterateLambda=self._iterateLambda,
resetLambda=self._resetLambda,
cancelLambda=self._cancelLambda,
completionMessageLambda=self._completionMessageLambda,
parent=self.parent,
)
4 changes: 4 additions & 0 deletions src/snapred/ui/workflow/WorkflowImplementer.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
)
from snapred.backend.error.ContinueWarning import ContinueWarning
from snapred.backend.log.logger import snapredLogger
from snapred.meta.Config import Config
from snapred.ui.handler.SNAPResponseHandler import SNAPResponseHandler
from snapred.ui.widget.Workflow import Workflow

Expand Down Expand Up @@ -117,6 +118,9 @@ def complete(self):
for hook in self.resetHooks:
hook()

def completionMessage(self):
return Config["ui.default.workflow.completionMessage"]

def _request(self, request: SNAPRequest):
response = self.interfaceController.executeRequest(request)
self._handleComplications(response)
Expand Down
45 changes: 27 additions & 18 deletions tests/integration/test_workflow_panels_happy_path.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,10 @@ def _setup_gui(self, qapp):
self._warningMessageBox = mock.patch(
"qtpy.QtWidgets.QMessageBox.warning",
lambda *args, **kwargs: pytest.fail(
"WARNING messagebox:\n" + f" args: {args}\n" + f" kwargs: {kwargs}", pytrace=False
),
"WARNING This test seems to be missing expected calibration and/or normalization data", pytrace=False
)
if "Reduction is missing calibration data," in args[2]
else pytest.fail("WARNING messagebox:\n" + f" args: {args}\n" + f" kwargs: {kwargs}", pytrace=False),
)
self._warningMessageBox.start()

Expand Down Expand Up @@ -182,10 +184,8 @@ def _setup_gui(self, qapp):

# Automatically continue at the end of each workflow.
self._actionPrompt = mock.patch(
"snapred.ui.presenter.WorkflowPresenter.ActionPrompt.prompt",
lambda *args: TestGUIPanels._actionPromptContinue(
*args, match=r".*The workflow has been completed successfully.*"
),
"qtpy.QtWidgets.QMessageBox.information",
lambda *args: TestGUIPanels._actionPromptContinue(*args, match=r".*has been completed successfully.*"),
)
self._actionPrompt.start()
# ---------------------------------------------------------------------------
Expand All @@ -206,12 +206,12 @@ def _setup_gui(self, qapp):
self.exitStack.close()

@staticmethod
def _actionPromptContinue(title, message, action, parent=None, match=r".*"): # noqa: ARG004
def _actionPromptContinue(parent, title, message, match=r".*"): # noqa: ARG004
_pattern = re.compile(match)
if not _pattern.match(message):
pytest.fail(
f"unexpected: ActionPrompt.prompt('{title}', '{message}'...)\n"
+ f" expecting: ActionPrompt.prompt(...'{message}'...)"
f"unexpected: QMessageBox.information('{title}', '{message}'...)\n"
+ f" expecting: QMessageBox.information(...'{message}'...)"
)

@pytest.mark.skip(reason="each workflow panel now has a separate test")
Expand Down Expand Up @@ -1160,7 +1160,7 @@ def test_normalization_panel_happy_path(self, qtbot, qapp, calibration_home_from

def test_reduction_panel_happy_path(self, qtbot, qapp, reduction_home_from_mirror):
##
## WARNING: this test requires EXISTING diffraction-calibration and normalization-calibration data!
## NOTE: WARNING: this test requires EXISTING diffraction-calibration and normalization-calibration data!
## As an alternative `test_calibration_and_reduction_panels_happy_path`, now skipped, could be run instead.
##

Expand All @@ -1172,6 +1172,20 @@ def test_reduction_panel_happy_path(self, qtbot, qapp, reduction_home_from_mirro
# under the existing location within the mirror.
tmpReductionHomeDirectory = reduction_home_from_mirror(reductionRunNumber) # noqa: F841

self.completionMessageHasAppeared = False

def completionMessageBoxAssert(*args, **kwargs): # noqa: ARG001
self.completionMessageHasAppeared = True
assert "Reduction has completed successfully!" in args[2]
return QMessageBox.Ok

self._actionPrompt.stop()
completionMessageBox = mock.patch(
"qtpy.QtWidgets.QMessageBox.information",
completionMessageBoxAssert, # noqa: ARG005
)
completionMessageBox.start()

with (
qtbot.captureExceptions() as exceptions,
suppress(InterruptWithBlock),
Expand Down Expand Up @@ -1307,25 +1321,20 @@ def test_reduction_panel_happy_path(self, qtbot, qapp, reduction_home_from_mirro
# (2) execute the reduction workflow
with qtbot.waitSignal(actionCompleted, timeout=120000):
qtbot.mouseClick(workflowNodeTabs.currentWidget().continueButton, Qt.MouseButton.LeftButton)
qtbot.waitUntil(lambda: isinstance(workflowNodeTabs.currentWidget().view, ReductionSaveView), timeout=60000)
saveView = workflowNodeTabs.currentWidget().view # noqa: F841

"""
# set "author" and "comment"
saveView.fieldAuthor.setText("kat")
saveView.fieldComments.setText("calibration-panel integration test")
"""

# continue in order to save workspaces and to finish the workflow
with qtbot.waitSignal(actionCompleted, timeout=60000):
qtbot.mouseClick(workflowNodeTabs.currentWidget().continueButton, Qt.MouseButton.LeftButton)

# `ActionPrompt.prompt("..The workflow has completed successfully..)` gives immediate mocked response:
# Here we still need to wait until the ADS cleanup has occurred,
# or else it will happen in the middle of the next workflow. :(
qtbot.waitUntil(
lambda: isinstance(workflowNodeTabs.currentWidget().view, ReductionRequestView), timeout=5000
lambda: self.completionMessageHasAppeared,
timeout=60000,
)
completionMessageBox.stop()

###############################
########### END OF TEST #######
Expand Down
5 changes: 5 additions & 0 deletions tests/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -237,3 +237,8 @@ constants:

metadata:
tagPrefix: testSNAPfuntime_

ui:
default:
workflow:
completionMessage: "‧₊‧₊The workflow has been completed successfully!‧₊‧₊"