Skip to content

Commit

Permalink
Process: raise when exposed_outputs gets non-existing namespace
Browse files Browse the repository at this point in the history
Up till now, a call to `exposed_outputs` providing a `namespace` as
argument that doesn't exist, i.e., no outputs were ever exposed in that
namespace, would simply be a no-op. Given that this would often be
because the namespace was accidentally misspelled, the error would go
unnoticed and the process would finish without error message.

To prevent this situation that is difficult to debug, the method will
now raise a `KeyError` if the top-level namespace does not exist.
  • Loading branch information
sphuber committed Dec 10, 2021
1 parent cdef910 commit 5329524
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 0 deletions.
2 changes: 2 additions & 0 deletions aiida/engine/processes/process.py
Original file line number Diff line number Diff line change
Expand Up @@ -903,6 +903,8 @@ def exposed_outputs(
for port_namespace in self._get_namespace_list(namespace=namespace, agglomerate=agglomerate):
# only the top-level key is stored in _exposed_outputs
for top_name in top_namespace_map:
if namespace is not None and namespace not in self.spec()._exposed_outputs: # pylint: disable=protected-access
raise KeyError(f'the namespace `{namespace}` is not an exposed namespace.')
if top_name in self.spec()._exposed_outputs[port_namespace][process_class]: # pylint: disable=protected-access
output_key_map[top_name] = port_namespace

Expand Down
43 changes: 43 additions & 0 deletions tests/engine/test_process.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,3 +393,46 @@ def define(cls, spec):
'output': node_output,
})
self.assertEqual(exposed_outputs, expected)

def test_exposed_outputs_non_existing_namespace(self):
"""Test the ``Process.exposed_outputs`` method for non-existing namespace."""
from aiida.common.links import LinkType
from aiida.engine.utils import instantiate_process
from aiida.manage.manager import get_manager

runner = get_manager().get_runner()

class ChildProcess(Process):
"""Dummy process with normal output and output namespace."""

_node_class = orm.WorkflowNode

@classmethod
def define(cls, spec):
super(ChildProcess, cls).define(spec)
spec.input('input', valid_type=orm.Int)
spec.output('output', valid_type=orm.Int)
spec.output('name.space', valid_type=orm.Int)

class ParentProcess(Process):
"""Dummy process that exposes the outputs of ``ChildProcess``."""

_node_class = orm.WorkflowNode

@classmethod
def define(cls, spec):
super(ParentProcess, cls).define(spec)
spec.input('input', valid_type=orm.Int)
spec.expose_outputs(ChildProcess, namespace='child')

node_child = orm.WorkflowNode().store()
node_output = orm.Int(1).store()
node_output.add_incoming(node_child, link_label='output', link_type=LinkType.RETURN)
node_name_space = orm.Int(1).store()
node_name_space.add_incoming(node_child, link_label='name__space', link_type=LinkType.RETURN)

process = instantiate_process(runner, ParentProcess, input=orm.Int(1))

# If the ``namespace`` does not exist, for example because it is slightly misspelled, a ``KeyError`` is raised
with self.assertRaises(KeyError):
process.exposed_outputs(node_child, ChildProcess, namespace='cildh')

0 comments on commit 5329524

Please sign in to comment.