Skip to content

Commit

Permalink
Allow to define link label for CALL links
Browse files Browse the repository at this point in the history
The `Process` class defines a new metadata input `call_link_label` that
when set for a process that is called by another, will be used as the
link label for the `CALL` link, instead of the default.
  • Loading branch information
sphuber committed Jun 14, 2019
1 parent 607f973 commit 43f91e3
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 22 deletions.
41 changes: 40 additions & 1 deletion aiida/backends/tests/engine/test_work_chain.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from aiida.common.links import LinkType
from aiida.common.utils import Capturing
from aiida.engine import ExitCode, Process, ToContext, WorkChain, if_, while_, return_, run, run_get_node, submit
from aiida.engine import launch
from aiida.engine import launch, calcfunction
from aiida.engine.persistence import ObjectLoader
from aiida.manage.manager import get_manager
from aiida.orm import load_node, Bool, Float, Int, Str
Expand Down Expand Up @@ -537,6 +537,45 @@ def after(self):

run_and_check_success(WcWithReturn)

def test_call_link_label(self):
"""Test that the `call_link_label` metadata input is properly used and set."""

label_workchain = 'some_not_default_call_link_label'
label_calcfunction = 'call_link_label_for_calcfunction'

@calcfunction
def calculation_function():
return

class MainWorkChain(WorkChain):

@classmethod
def define(cls, spec):
super(MainWorkChain, cls).define(spec)
spec.outline(cls.launch)

def launch(self):
# "Call" a calculation function simply by running it
inputs = {'metadata': {'call_link_label': label_calcfunction}}
result = calculation_function(**inputs)

# Call a sub work chain
inputs = {'metadata': {'call_link_label': label_workchain}}
return ToContext(subwc=self.submit(SubWorkChain, **inputs))

class SubWorkChain(WorkChain):
pass

process = run_and_check_success(MainWorkChain)

# Verify that the `CALL` link of the calculation function is there with the correct label
link_triple = process.node.get_outgoing(link_type=LinkType.CALL_CALC, link_label_filter=label_calcfunction).one()
self.assertIsInstance(link_triple.node, orm.CalcFunctionNode)

# Verify that the `CALL` link of the work chain is there with the correct label
link_triple = process.node.get_outgoing(link_type=LinkType.CALL_WORK, link_label_filter=label_workchain).one()
self.assertIsInstance(link_triple.node, orm.WorkChainNode)

def test_tocontext_submit_workchain_no_daemon(self):

class MainWorkChain(WorkChain):
Expand Down
25 changes: 22 additions & 3 deletions aiida/backends/tests/engine/test_workfunctions.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@
from __future__ import absolute_import

from aiida.backends.testbase import AiidaTestCase
from aiida.manage.caching import enable_caching
from aiida.common.links import LinkType
from aiida.engine import workfunction, Process
from aiida.orm import Int, WorkFunctionNode
from aiida.engine import calcfunction, workfunction, Process
from aiida.manage.caching import enable_caching
from aiida.orm import Int, WorkFunctionNode, CalcFunctionNode


class TestWorkFunction(AiidaTestCase):
Expand Down Expand Up @@ -78,3 +78,22 @@ def test_workfunction_caching(self):
with enable_caching(WorkFunctionNode):
_, cached = self.test_workfunction.run_get_node(self.default_int)
self.assertFalse(cached.is_created_from_cache)

def test_call_link_label(self):
"""Verify that setting a `call_link_label` on a `calcfunction` called from a `workfunction` works."""

link_label = 'non_default_call_link_label'

@calcfunction
def calculation():
return

@workfunction
def caller():
calculation(metadata={'call_link_label': link_label}) # pylint: disable=unexpected-keyword-arg

_, node = caller.run_get_node()

# Verify that the `CALL` link of the calculation function is there with the correct label
link_triple = node.get_outgoing(link_type=LinkType.CALL_CALC, link_label_filter=link_label).one()
self.assertIsInstance(link_triple.node, CalcFunctionNode)
26 changes: 14 additions & 12 deletions aiida/engine/processes/process.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
from six.moves import filter, range
from pika.exceptions import ConnectionClosed

from kiwipy.communications import UnroutableError
import plumpy
from plumpy import ProcessState
from kiwipy.communications import UnroutableError

from aiida import orm
from aiida.common import exceptions
Expand Down Expand Up @@ -65,12 +65,18 @@ class SaveKeys(enum.Enum):

@classmethod
def define(cls, spec):
# yapf: disable
super(Process, cls).define(spec)
spec.input_namespace(spec.metadata_key, required=False, non_db=True)
spec.input_namespace('{}.{}'.format(spec.metadata_key, spec.options_key), required=False)
spec.input('{}.store_provenance'.format(spec.metadata_key), valid_type=bool, default=True)
spec.input('{}.description'.format(spec.metadata_key), valid_type=six.string_types[0], required=False)
spec.input('{}.label'.format(spec.metadata_key), valid_type=six.string_types[0], required=False)
spec.input('{}.store_provenance'.format(spec.metadata_key), valid_type=bool, default=True,
help='If set to `False` provenance will not be stored in the database.')
spec.input('{}.description'.format(spec.metadata_key), valid_type=six.string_types[0], required=False,
help='Description to set on the process node.')
spec.input('{}.label'.format(spec.metadata_key), valid_type=six.string_types[0], required=False,
help='Label to set on the process node.')
spec.input('{}.call_link_label'.format(spec.metadata_key), valid_type=six.string_types[0], default='CALL',
help='The label to use for the `CALL` link if the process is called by another process.')
spec.exit_code(10, 'ERROR_INVALID_OUTPUT', message='the process returned an invalid output')
spec.exit_code(11, 'ERROR_MISSING_OUTPUT', message='the process did not register a required output')

Expand Down Expand Up @@ -637,18 +643,18 @@ def _setup_db_record(self):
raise exceptions.InvalidOperation('calling processes from a calculation type process is forbidden.')

if isinstance(self.node, orm.CalculationNode):
self.node.add_incoming(parent_calc, LinkType.CALL_CALC, 'CALL_CALC')
self.node.add_incoming(parent_calc, LinkType.CALL_CALC, self.metadata.call_link_label)

elif isinstance(self.node, orm.WorkflowNode):
self.node.add_incoming(parent_calc, LinkType.CALL_WORK, 'CALL_WORK')
self.node.add_incoming(parent_calc, LinkType.CALL_WORK, self.metadata.call_link_label)

self._setup_metadata()
self._setup_inputs()

def _setup_metadata(self):
"""Store the metadata on the ProcessNode."""
for name, metadata in self.metadata.items():
if name in ['store_provenance', 'dry_run']:
if name in ['store_provenance', 'dry_run', 'call_link_label']:
continue
elif name == 'label':
self.node.label = metadata
Expand All @@ -673,11 +679,7 @@ def _setup_inputs(self):
self.node.computer = node.get_remote_computer()

# Need this special case for tests that use ProcessNodes as classes
if isinstance(self.node, orm.ProcessNode) and not isinstance(self.node,
(orm.CalculationNode, orm.WorkflowNode)):
self.node.add_incoming(node, LinkType.INPUT_WORK, name)

elif isinstance(self.node, orm.CalculationNode):
if isinstance(self.node, orm.CalculationNode):
self.node.add_incoming(node, LinkType.INPUT_CALC, name)

elif isinstance(self.node, orm.WorkflowNode):
Expand Down
6 changes: 3 additions & 3 deletions aiida/sphinxext/tests/reference_results/workchain.py2.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE document PUBLIC "+//IDN docutils.sourceforge.net//DTD Docutils Generic//EN//XML" "http://docutils.sourceforge.net/docs/ref/docutils.dtd">
<!-- Generated by Docutils 0.14 -->
<document source="/home/sphuber/code/aiida/env/prov/aiida-core/aiida/sphinxext/tests/workchain_source/index.rst">
<document source="/home/sphuber/code/aiida/env/dev/aiida-core/aiida/sphinxext/tests/workchain_source/index.rst">
<section ids="sphinx-aiida-demo" names="sphinx-aiida\ demo">
<title>sphinx-aiida demo</title>
<paragraph>This is a demo documentation to show off the features of the <literal>sphinx-aiida</literal> extension.</paragraph>
Expand All @@ -13,7 +13,7 @@
<paragraph>
A demo workchain to show how the workchain auto-documentation works.
</paragraph>
<paragraph><strong>Inputs:</strong><bullet_list bullet="*"><list_item><literal_strong>metadata</literal_strong>, <emphasis>Namespace</emphasis><bullet_list bullet="*"><list_item><paragraph><literal_strong>description</literal_strong>, <emphasis>basestring</emphasis>, optional, <emphasis>non_db</emphasis></paragraph></list_item><list_item><paragraph><literal_strong>label</literal_strong>, <emphasis>basestring</emphasis>, optional, <emphasis>non_db</emphasis></paragraph></list_item><list_item><literal_strong>options</literal_strong>, <emphasis>Namespace</emphasis><bullet_list bullet="*"></bullet_list></list_item><list_item><paragraph><literal_strong>store_provenance</literal_strong>, <emphasis>bool</emphasis>, optional, <emphasis>non_db</emphasis></paragraph></list_item></bullet_list></list_item><list_item><literal_strong>nsp</literal_strong>, <emphasis>Namespace</emphasis> – A separate namespace, <literal>nsp</literal>.<bullet_list bullet="*"></bullet_list></list_item><list_item><literal_strong>nsp2</literal_strong>, <emphasis>Namespace</emphasis><bullet_list bullet="*"></bullet_list></list_item><list_item><paragraph><literal_strong>x</literal_strong>, <emphasis>Float</emphasis>, required – First input argument.</paragraph></list_item><list_item><literal_strong>y</literal_strong>, <emphasis>Namespace</emphasis><bullet_list bullet="*"><list_item><paragraph><literal_strong>z</literal_strong>, <emphasis>Int</emphasis>, required – Input in a separate namespace.</paragraph></list_item></bullet_list></list_item></bullet_list></paragraph>
<paragraph><strong>Inputs:</strong><bullet_list bullet="*"><list_item><literal_strong>metadata</literal_strong>, <emphasis>Namespace</emphasis><bullet_list bullet="*"><list_item><paragraph><literal_strong>call_link_label</literal_strong>, <emphasis>basestring</emphasis>, optional, <emphasis>non_db</emphasis> – The label to use for the <title_reference>CALL</title_reference> link if the process is called by another process.</paragraph></list_item><list_item><paragraph><literal_strong>description</literal_strong>, <emphasis>basestring</emphasis>, optional, <emphasis>non_db</emphasis> – Description to set on the process node.</paragraph></list_item><list_item><paragraph><literal_strong>label</literal_strong>, <emphasis>basestring</emphasis>, optional, <emphasis>non_db</emphasis> – Label to set on the process node.</paragraph></list_item><list_item><literal_strong>options</literal_strong>, <emphasis>Namespace</emphasis><bullet_list bullet="*"></bullet_list></list_item><list_item><paragraph><literal_strong>store_provenance</literal_strong>, <emphasis>bool</emphasis>, optional, <emphasis>non_db</emphasis> – If set to <title_reference>False</title_reference> provenance will not be stored in the database.</paragraph></list_item></bullet_list></list_item><list_item><literal_strong>nsp</literal_strong>, <emphasis>Namespace</emphasis> – A separate namespace, <literal>nsp</literal>.<bullet_list bullet="*"></bullet_list></list_item><list_item><literal_strong>nsp2</literal_strong>, <emphasis>Namespace</emphasis><bullet_list bullet="*"></bullet_list></list_item><list_item><paragraph><literal_strong>x</literal_strong>, <emphasis>Float</emphasis>, required – First input argument.</paragraph></list_item><list_item><literal_strong>y</literal_strong>, <emphasis>Namespace</emphasis><bullet_list bullet="*"><list_item><paragraph><literal_strong>z</literal_strong>, <emphasis>Int</emphasis>, required – Input in a separate namespace.</paragraph></list_item></bullet_list></list_item></bullet_list></paragraph>
<paragraph><strong>Outputs:</strong><bullet_list bullet="*"><list_item><paragraph><literal_strong>z</literal_strong>, <emphasis>Bool</emphasis>, required – Output of the demoworkchain.</paragraph></list_item></bullet_list></paragraph>
</desc_content>
</desc>
Expand All @@ -38,7 +38,7 @@
<paragraph>
A demo workchain to show how the workchain auto-documentation works.
</paragraph>
<paragraph><strong>Inputs:</strong><bullet_list bullet="*"><list_item><literal_strong>metadata</literal_strong>, <emphasis>Namespace</emphasis><bullet_list bullet="*"><list_item><paragraph><literal_strong>description</literal_strong>, <emphasis>basestring</emphasis>, optional, <emphasis>non_db</emphasis></paragraph></list_item><list_item><paragraph><literal_strong>label</literal_strong>, <emphasis>basestring</emphasis>, optional, <emphasis>non_db</emphasis></paragraph></list_item><list_item><literal_strong>options</literal_strong>, <emphasis>Namespace</emphasis><bullet_list bullet="*"></bullet_list></list_item><list_item><paragraph><literal_strong>store_provenance</literal_strong>, <emphasis>bool</emphasis>, optional, <emphasis>non_db</emphasis></paragraph></list_item></bullet_list></list_item><list_item><literal_strong>nsp</literal_strong>, <emphasis>Namespace</emphasis> – A separate namespace, <literal>nsp</literal>.<bullet_list bullet="*"></bullet_list></list_item><list_item><literal_strong>nsp2</literal_strong>, <emphasis>Namespace</emphasis><bullet_list bullet="*"></bullet_list></list_item><list_item><paragraph><literal_strong>x</literal_strong>, <emphasis>Float</emphasis>, required – First input argument.</paragraph></list_item><list_item><literal_strong>y</literal_strong>, <emphasis>Namespace</emphasis><bullet_list bullet="*"><list_item><paragraph><literal_strong>z</literal_strong>, <emphasis>Int</emphasis>, required – Input in a separate namespace.</paragraph></list_item></bullet_list></list_item></bullet_list></paragraph>
<paragraph><strong>Inputs:</strong><bullet_list bullet="*"><list_item><literal_strong>metadata</literal_strong>, <emphasis>Namespace</emphasis><bullet_list bullet="*"><list_item><paragraph><literal_strong>call_link_label</literal_strong>, <emphasis>basestring</emphasis>, optional, <emphasis>non_db</emphasis> – The label to use for the <title_reference>CALL</title_reference> link if the process is called by another process.</paragraph></list_item><list_item><paragraph><literal_strong>description</literal_strong>, <emphasis>basestring</emphasis>, optional, <emphasis>non_db</emphasis> – Description to set on the process node.</paragraph></list_item><list_item><paragraph><literal_strong>label</literal_strong>, <emphasis>basestring</emphasis>, optional, <emphasis>non_db</emphasis> – Label to set on the process node.</paragraph></list_item><list_item><literal_strong>options</literal_strong>, <emphasis>Namespace</emphasis><bullet_list bullet="*"></bullet_list></list_item><list_item><paragraph><literal_strong>store_provenance</literal_strong>, <emphasis>bool</emphasis>, optional, <emphasis>non_db</emphasis> – If set to <title_reference>False</title_reference> provenance will not be stored in the database.</paragraph></list_item></bullet_list></list_item><list_item><literal_strong>nsp</literal_strong>, <emphasis>Namespace</emphasis> – A separate namespace, <literal>nsp</literal>.<bullet_list bullet="*"></bullet_list></list_item><list_item><literal_strong>nsp2</literal_strong>, <emphasis>Namespace</emphasis><bullet_list bullet="*"></bullet_list></list_item><list_item><paragraph><literal_strong>x</literal_strong>, <emphasis>Float</emphasis>, required – First input argument.</paragraph></list_item><list_item><literal_strong>y</literal_strong>, <emphasis>Namespace</emphasis><bullet_list bullet="*"><list_item><paragraph><literal_strong>z</literal_strong>, <emphasis>Int</emphasis>, required – Input in a separate namespace.</paragraph></list_item></bullet_list></list_item></bullet_list></paragraph>
<paragraph><strong>Outputs:</strong><bullet_list bullet="*"><list_item><paragraph><literal_strong>z</literal_strong>, <emphasis>Bool</emphasis>, required – Output of the demoworkchain.</paragraph></list_item></bullet_list></paragraph>
</desc_content>
</desc>
Expand Down
Loading

0 comments on commit 43f91e3

Please sign in to comment.