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

Ensure that WorkChain._do_step return None, int or ExitCode #1704

Merged
merged 1 commit into from
Jun 30, 2018
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
18 changes: 18 additions & 0 deletions aiida/backends/tests/work/work_chain.py
Original file line number Diff line number Diff line change
Expand Up @@ -1133,3 +1133,21 @@ def test_nested_expose(self):
'sub.sub.sub_2.b': Float(1.2), 'sub.sub.sub_2.sub_3.c': Bool(False)
}
)


class TestWorkChainReturnDict(AiidaTestCase):

class PointlessWorkChain(WorkChain):

@classmethod
def define(cls, spec):
super(TestWorkChainReturnDict.PointlessWorkChain, cls).define(spec)
spec.outline(cls.return_dict)

def return_dict(self):
"""Only return a dictionary, which should be allowed, even though it accomplishes nothing."""
return {}

def test_run_pointless_workchain(self):
"""Running the pointless workchain should not incur any exceptions"""
result = work.run(TestWorkChainReturnDict.PointlessWorkChain)
28 changes: 19 additions & 9 deletions aiida/work/workchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

from .awaitable import AwaitableTarget, AwaitableAction, construct_awaitable
from .context import ToContext, assign_, append_
from .exit_code import ExitCode
from .process_spec import ProcessSpec
from .processes import Process, ProcessState

Expand Down Expand Up @@ -139,28 +140,37 @@ def _run(self):

def _do_step(self):
"""
Execute the next step in the outline, if the stepper returns a non-finished status
and the return value is of type ToContext, it will be added to the awaitables.
If the stepper returns that the process is finished, we return the return value
Execute the next step in the outline and return the result.

If the stepper returns a non-finished status and the return value is of type ToContext, the contents of the
ToContext container will be turned into awaitables if necessary. If any awaitables were created, the process
will enter in the Wait state, otherwise it will go to Continue. When the stepper returns that it is done, the
stepper result will be converted to None and returned, unless it is an integer or instance of ExitCode.
"""
self._awaitables = []
result = None

try:
finished, return_value = self._stepper.step()
finished, stepper_result = self._stepper.step()
except _PropagateReturn as exception:
finished, return_value = True, exception.exit_code
finished, result = True, exception.exit_code
else:
if isinstance(stepper_result, (int, ExitCode)):
result = stepper_result
else:
result = None

if not finished and (return_value is None or isinstance(return_value, ToContext)):
if not finished and (stepper_result is None or isinstance(stepper_result, ToContext)):

if isinstance(return_value, ToContext):
self.to_context(**return_value)
if isinstance(stepper_result, ToContext):
self.to_context(**stepper_result)

if self._awaitables:
return Wait(self._do_step, 'Waiting before next step')

return Continue(self._do_step)

return return_value
return result

def on_wait(self, awaitables):
super(WorkChain, self).on_wait(awaitables)
Expand Down