def _handle_error_unrecognized_by_parser(self, calculation): """ Calculation failed with an error that was not recognized by the parser and was attached wholesale to the warnings. We treat it as an unexpected failure and raise the exception """ warnings = calculation.res.warnings if (any(['%%%' in w for w in warnings]) or any(['Error' in w for w in warnings])): raise UnexpectedCalculationFailure('PwCalculation<{}> failed due to an unknown reason'.format(calculation.pk))
def _handle_calculation_failure(self, calculation): """Call the attached error handlers if any to attempt to correct the cause of the calculation failure. The registered error handlers will be called in order based on their priority until a handler returns a report that instructs to break. If the last executed error handler defines an exit code, that will be returned to instruct the work chain to abort. Otherwise the work chain will continue the cycle. :param calculation: the calculation that finished with a non-zero exit status :return: `ExitCode` if the work chain is to be aborted :raises `UnexpectedCalculationFailure`: if no error handlers were registered or no errors were handled. """ is_handled = False handler_report = None if not hasattr(self, '_error_handlers') or not self._error_handlers: raise UnexpectedCalculationFailure('no calculation error handlers were registered') # Sort the handlers with a priority defined, based on their priority in reverse order handlers = [handler for handler in self._error_handlers if handler.priority] handlers = sorted(handlers, key=lambda x: x.priority, reverse=True) for handler in handlers: handler_report = handler.method(self, calculation) # If at least one error is handled, we consider the calculation failure handled. if handler_report and handler_report.is_handled: self.ctx.unexpected_failure = False is_handled = True # After certain error handlers, we may want to skip all other error handling if handler_report and handler_report.do_break: break # If none of the executed error handlers reported that they handled an error, the failure reason is unknown if not is_handled: raise UnexpectedCalculationFailure('calculation failure was not handled') # The last called error handler may not necessarily have returned a handler report if handler_report: return handler_report.exit_code return
def _handle_calculation_failure(self, calculation): """ The calculation has failed so we try to analyze the reason and change the inputs accordingly for the next calculation. If the calculation failed, but did so cleanly, we set it as the restart_calc, in all other cases we do not replace the restart_calc """ try: outputs = calculation.out.output_parameters.get_dict() _ = outputs['warnings'] _ = outputs['parser_warnings'] except (AttributeError, KeyError) as exception: raise UnexpectedCalculationFailure(exception) is_handled = False # Sort the handlers based on their priority in reverse order handlers = sorted(self._error_handlers, key=lambda x: x.priority, reverse=True) if not handlers: raise UnexpectedCalculationFailure( 'no calculation error handlers were registered') for handler in handlers: handler_report = handler.method(self, calculation) # If at least one error is handled, we consider the calculation failure handled if handler_report and handler_report.is_handled: self.ctx.restart_calc = calculation is_handled = True # After certain error handlers, we may want to skip all other error handling if handler_report and handler_report.do_break: break # If none of the executed error handlers reported that they handled an error, the failure reason is unknown if not is_handled: raise UnexpectedCalculationFailure( 'calculation failure was not handled') return