From dc1c0a539efacfeda873847b4c2d3491891a5e39 Mon Sep 17 00:00:00 2001 From: Sebastiaan Huber Date: Wed, 26 Oct 2022 10:52:36 +0200 Subject: [PATCH] `Process`: Add hook to customize the `process_label` attribute (#5713) Up till now the `process_label` of a `ProcessNode` instance representing the execution of a `Process` would be set to the name of the process class. This was hardcoded and could not be changed, but in certain cases it may be useful for the subclass to provide a more meaningful label. Here the `_build_process_label` method is called which should return the process label. It can be overridden by subclasses to return another string. When an instance of the `Process` is run, the value returned by this method will be stored in the `process_label` attribute. --- aiida/engine/processes/process.py | 12 +++++++++++- docs/source/howto/plugin_codes.rst | 24 ++++++++++++++++++++++++ tests/engine/test_process.py | 15 +++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/aiida/engine/processes/process.py b/aiida/engine/processes/process.py index 770ed9fcce..0310824be8 100644 --- a/aiida/engine/processes/process.py +++ b/aiida/engine/processes/process.py @@ -662,6 +662,16 @@ def update_outputs(self) -> None: output.store() + def _build_process_label(self) -> str: + """Construct the process label that should be set on ``ProcessNode`` instances for this process class. + + .. note:: By default this returns the name of the process class itself. It can be overridden by ``Process`` + subclasses to provide a more specific label. + + :returns: The process label to use for ``ProcessNode`` instances. + """ + return self.__class__.__name__ + def _setup_db_record(self) -> None: """ Create the database record for this process and the links with respect to its inputs @@ -680,7 +690,7 @@ def _setup_db_record(self) -> None: # Store important process attributes in the node proxy self.node.set_process_state(None) - self.node.set_process_label(self.__class__.__name__) + self.node.set_process_label(self._build_process_label()) self.node.set_process_type(self.__class__.build_process_type()) parent_calc = self.get_parent_calc() diff --git a/docs/source/howto/plugin_codes.rst b/docs/source/howto/plugin_codes.rst index 80b1d767b6..957639d0a9 100644 --- a/docs/source/howto/plugin_codes.rst +++ b/docs/source/howto/plugin_codes.rst @@ -295,6 +295,30 @@ Note that some scheduler plugins can detect issues at the scheduler level (by pa The Topics section on :ref:`scheduler exit codes ` explains how these can be inspected inside a parser and how they can optionally be overridden. +.. how-to:plugin-codes:customization: + +Customizations +============== + +.. how-to:plugin-codes:customization:process-label: + +Process label +------------- + +Each time a ``Process`` is run, a ``ProcessNode`` is stored in the database to record the execution. +A human-readable label is stored in the ``process_label`` attribute. +By default, the name of the process class is used as this label. +If this default is not informative enough, it can be customized by overriding the :meth:`~aiida.engine.processes.process.Process._build_process_label`: method: + +.. code-block:: python + + class SomeProcess(Process): + + def _build_process_label(self): + return 'custom_process_label' + +Nodes created through executions of this process class will have ``node.process_label == 'custom_process_label'``. + .. _how-to:plugin-codes:entry-points: Registering entry points diff --git a/tests/engine/test_process.py b/tests/engine/test_process.py index cc0ddfc213..cc6fe75faa 100644 --- a/tests/engine/test_process.py +++ b/tests/engine/test_process.py @@ -434,6 +434,21 @@ def define(cls, spec): with pytest.raises(KeyError): process.exposed_outputs(node_child, ChildProcess, namespace='cildh') + def test_build_process_label(self): + """Test the :meth:`~aiida.engine.processes.process.Process.build_process_label` method.""" + custom_process_label = 'custom_process_label' + + class CustomLabelProcess(Process): + """Class that provides custom process label.""" + + _node_class = orm.WorkflowNode + + def _build_process_label(self): + return custom_process_label + + _, node = run_get_node(CustomLabelProcess) + assert node.process_label == custom_process_label + class TestValidateDynamicNamespaceProcess(Process): """Simple process with dynamic input namespace."""