Skip to content

Commit

Permalink
Ensure the type of exit codes is None, int or ExitCode (#1681)
Browse files Browse the repository at this point in the history
There was a bug in the execute method of the Waiting state of the
JobProcess, that in the case of a TransportException, which would
occur in the case of a SUBMISSIONFAILED or RETRIEVALFAILED, the
returned exit code was a JobCalculationExitStatus enum instance
and not the required integer or ExitCode. This would except the
process due to the check in the Process.on_finish call.

A similar problem existed in the execmanager.parse_results method
which also did not guarantee the return of an exit code of a valid
type. We now make sure to convert the bool, integer or ExitCode
which can be returned by parse_results is converted to an ExitCode
before it is returned.
  • Loading branch information
sphuber authored Jun 22, 2018
1 parent adefb22 commit 695b548
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 10 deletions.
25 changes: 17 additions & 8 deletions aiida/daemon/execmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -394,33 +394,42 @@ def parse_results(job, retrieved_temporary_folder=None):
:returns: integer exit code, where 0 indicates success and non-zero failure
"""
from aiida.orm.calculation.job import JobCalculationExitStatus
from aiida.work import ExitCode

logger_extra = get_dblogger_extra(job)

job._set_state(calc_states.PARSING)

Parser = job.get_parserclass()
exit_code = None
exit_code = ExitCode()

if Parser is not None:

parser = Parser(job)
exit_code, new_nodes_tuple = parser.parse_from_calc(retrieved_temporary_folder)

# Some implementations of parse_from_calc may still return a boolean for the exit_code
# If we get True we convert to 0, for false we simply use the generic value that
# maps to the calculation state FAILED
# Some implementations of parse_from_calc may still return a plain boolean or integer for the exit_code.
# In the case of a boolean: True should be mapped to the default ExitCode which corresponds to an exit
# status of 0. False values are mapped to the value that is mapped onto the FAILED calculation state
# throught the JobCalculationExitStatus. Plain integers are directly used to construct an ExitCode tuple
if isinstance(exit_code, bool) and exit_code is True:
exit_code = 0
exit_code = ExitCode(0)
elif isinstance(exit_code, bool) and exit_code is False:
exit_code = JobCalculationExitStatus[calc_states.FAILED]
exit_code = ExitCode(JobCalculationExitStatus[calc_states.FAILED].value)
elif isinstance(exit_code, int):
exit_code = ExitCode(exit_code)
elif isinstance(exit_code, ExitCode):
pass
else:
raise ValueError("parse_from_calc returned an 'exit_code' of invalid_type: {}. It should "
"return a boolean, integer or ExitCode instance".format(type(exit_code)))

for label, n in new_nodes_tuple:
n.add_link_from(job, label=label, link_type=LinkType.CREATE)
n.store()

try:
if exit_code == 0:
if exit_code.status == 0:
job._set_state(calc_states.FINISHED)
else:
job._set_state(calc_states.FAILED)
Expand All @@ -429,7 +438,7 @@ def parse_results(job, retrieved_temporary_folder=None):
# in order to avoid useless error messages, I just ignore
pass

if exit_code is not 0:
if exit_code.status is not 0:
execlogger.error("[parsing of calc {}] "
"The parser returned an error, but it should have "
"created an output node with some partial results "
Expand Down
4 changes: 2 additions & 2 deletions aiida/work/job_processes.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ def execute(self):
raise RuntimeError("Unknown waiting command")

except TransportTaskException as exception:
exit_status = JobCalculationExitStatus[exception.calc_state]
exit_status = JobCalculationExitStatus[exception.calc_state].value
raise Return(self.create_state(processes.ProcessState.FINISHED, exit_status, exit_status is 0))
except plumpy.CancelledError:
# A task was cancelled because the state (and process) is being killed
Expand Down Expand Up @@ -515,7 +515,7 @@ def retrieved(self, retrieved_temporary_folder=None):
"""
try:
exit_code = execmanager.parse_results(self.calc, retrieved_temporary_folder)
except BaseException:
except Exception:
try:
self.calc._set_state(calc_states.PARSINGFAILED)
except exceptions.ModificationNotAllowed:
Expand Down

0 comments on commit 695b548

Please sign in to comment.