Skip to content

Commit cd4015c

Browse files
Avoid storing the process node in step 4, opting for loading from uuid on the fly (thread safety)
1 parent e671688 commit cd4015c

File tree

11 files changed

+42
-41
lines changed

11 files changed

+42
-41
lines changed

src/aiidalab_qe/app/result/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ def _update_kill_button_layout(self):
209209
return
210210
process_node = self._model.fetch_process_node()
211211
if (
212-
not self._model.has_process
212+
not process_node
213213
or process_node.is_finished
214214
or process_node.is_excepted
215215
or self.state
@@ -236,7 +236,7 @@ def _update_status(self):
236236

237237
def _update_state(self):
238238
process_node = self._model.fetch_process_node()
239-
if not self._model.has_process:
239+
if not process_node:
240240
self.state = self.State.INIT
241241
elif process_node.process_state in (
242242
ProcessState.CREATED,

src/aiidalab_qe/app/result/model.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ def update(self):
1818
self._update_process_remote_folder_state()
1919

2020
def kill_process(self):
21-
if self.has_process:
22-
control.kill_processes([self.process_node])
21+
if process_node := self.fetch_process_node():
22+
control.kill_processes([process_node])
2323

2424
def clean_remote_data(self):
25-
if not self.has_process:
25+
if not (process_node := self.fetch_process_node()):
2626
return
27-
for called_descendant in self.process_node.called_descendants:
27+
for called_descendant in process_node.called_descendants:
2828
if isinstance(called_descendant, orm.CalcJobNode):
2929
with contextlib.suppress(Exception):
3030
called_descendant.outputs.remote_folder._clean()
@@ -35,10 +35,10 @@ def reset(self):
3535
self.process_info = ""
3636

3737
def _update_process_remote_folder_state(self):
38-
if not self.has_process:
38+
if not (process_node := self.fetch_process_node()):
3939
return
4040
cleaned = []
41-
for called_descendant in self.process_node.called_descendants:
41+
for called_descendant in process_node.called_descendants:
4242
if isinstance(called_descendant, orm.CalcJobNode):
4343
with contextlib.suppress(Exception):
4444
cleaned.append(called_descendant.outputs.remote_folder.is_empty)

src/aiidalab_qe/app/result/summary/model.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,8 @@ def _generate_report_parameters(self):
125125
"""
126126
from aiida.orm.utils.serialize import deserialize_unsafe
127127

128-
qeapp_wc = self.process_node
128+
if not (qeapp_wc := self.fetch_process_node()):
129+
return {"error": "WorkChain not found."}
129130

130131
ui_parameters = qeapp_wc.base.extras.get("ui_parameters", {})
131132
if isinstance(ui_parameters, str):

src/aiidalab_qe/app/result/viewer/viewer.py

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,18 @@ def render(self):
4949
if self.rendered:
5050
return
5151

52-
node = self._model.process_node
52+
node = self._model.fetch_process_node()
5353

54-
self.title = ipw.HTML(f"""
55-
<hr style="height:2px;background-color:#2097F3;">
56-
<h4>
57-
QE App Workflow (pk: {node.pk}) &mdash; {node.inputs.structure.get_formula()}
58-
</h4>
59-
""")
54+
self.title = ipw.HTML()
55+
56+
title = "<hr style='height:2px;background-color:#2097F3;'>"
57+
if node:
58+
formula = node.inputs.structure.get_formula()
59+
title += f"\n<h4>QE App Workflow (pk: {node.pk}) &mdash; {formula}</h4>"
60+
else:
61+
title += "\n<h4>QE App Workflow</h4>"
62+
63+
self.title.value = title
6064

6165
self.tabs = ipw.Tab(selected_index=None)
6266

@@ -69,7 +73,7 @@ def render(self):
6973

7074
self._update_tabs()
7175

72-
if node.is_finished:
76+
if node and node.is_finished:
7377
self._add_workflow_output_widget()
7478

7579
def _update_tabs(self):
@@ -87,7 +91,8 @@ def _update_tabs(self):
8791
self.summary.render()
8892

8993
def _add_workflow_output_widget(self):
90-
self.summary.children += (WorkChainOutputs(self._model.process_node),)
94+
process_node = self._model.fetch_process_node()
95+
self.summary.children += (WorkChainOutputs(node=process_node),)
9196

9297
def _add_structure_panel(self):
9398
structure_model = StructureResultsModel()

src/aiidalab_qe/common/mixins.py

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -49,36 +49,29 @@ def _link_model(self, model: T):
4949

5050
class HasProcess(tl.HasTraits):
5151
process_uuid = tl.Unicode(allow_none=True)
52-
monitor_counter = tl.Int(0)
53-
54-
process_node = None
55-
56-
@property
57-
def has_process(self):
58-
return self.process_node is not None
52+
monitor_counter = tl.Int(0) # used for continuous updates
5953

6054
@property
6155
def inputs(self):
62-
return self.process_node.inputs if self.has_process else []
56+
process_node = self.fetch_process_node()
57+
return process_node.inputs if process_node else []
6358

6459
@property
6560
def properties(self):
66-
return self.process_node.inputs.properties if self.has_process else []
61+
process_node = self.fetch_process_node()
62+
return process_node.inputs.properties if process_node else []
6763

6864
@property
6965
def outputs(self):
70-
return self.process_node.outputs if self.has_process else []
66+
process_node = self.fetch_process_node()
67+
return process_node.outputs if process_node else []
7168

7269
def fetch_process_node(self):
7370
try:
7471
return orm.load_node(self.process_uuid) if self.process_uuid else None
7572
except NotExistent:
7673
return None
7774

78-
@tl.observe("process_uuid")
79-
def _on_process_uuid_change(self, _):
80-
self.process_node = self.fetch_process_node()
81-
8275

8376
class Confirmable(tl.HasTraits):
8477
confirmed = tl.Bool(False)

src/aiidalab_qe/common/panel.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ def _get_child_outputs(self, child="this"):
231231
return AttributeDict({key: getattr(node.outputs, key) for key in node.outputs})
232232

233233
def _fetch_child_process_node(self, child="this") -> orm.ProcessNode | None:
234-
if not self.process_node:
234+
if not self.process_uuid:
235235
return
236236
uuid = getattr(self, f"_{child}_process_uuid")
237237
label = getattr(self, f"_{child}_process_label")
@@ -240,7 +240,7 @@ def _fetch_child_process_node(self, child="this") -> orm.ProcessNode | None:
240240
orm.QueryBuilder()
241241
.append(
242242
orm.WorkChainNode,
243-
filters={"uuid": self.process_node.uuid},
243+
filters={"uuid": self.process_uuid},
244244
tag="root_process",
245245
)
246246
.append(

src/aiidalab_qe/plugins/xas/result/model.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,16 @@ class XasResultsModel(ResultsModel):
2929
_this_process_label = "XspectraCrystalWorkChain"
3030

3131
def update_spectrum_options(self):
32+
if not (process_node := self.fetch_process_node()):
33+
return
3234
outputs = self._get_child_outputs()
3335
(
3436
self.final_spectra,
3537
self.equivalent_sites_data,
3638
) = export_xas_data(outputs)
3739
xas_workchain = next(
3840
node
39-
for node in self.process_node.called
41+
for node in process_node.called
4042
if node.process_label == self._this_process_label
4143
)
4244
core_workchains = {

tests/test_plugins_bands.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ def test_result(generate_qeapp_workchain):
66

77
workchain = generate_qeapp_workchain()
88
model = BandsResultsModel()
9-
model.process_node = workchain.node
9+
model.process_uuid = workchain.node.uuid
1010
result = BandsResults(model=model)
1111
result.render()
1212

tests/test_plugins_electronic_structure.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ def test_electronic_structure(generate_qeapp_workchain):
99

1010
workchain = generate_qeapp_workchain()
1111
model = ElectronicStructureResultsModel()
12-
model.process_node = workchain.node
12+
model.process_uuid = workchain.node.uuid
1313
result = ElectronicStructureResults(model=model)
1414
result.render()
1515

tests/test_plugins_pdos.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ def test_result(generate_qeapp_workchain):
66

77
workchain = generate_qeapp_workchain()
88
model = PdosResultsModel()
9-
model.process_node = workchain.node
9+
model.process_uuid = workchain.node.uuid
1010
result = PdosResults(model=model)
1111
result.render()
1212

0 commit comments

Comments
 (0)