Commit 74a34af4 authored by Jerome Mariette's avatar Jerome Mariette
Browse files

display error, and handle errors with raise instead of sys.exit

parent 0e480b39
...@@ -312,11 +312,13 @@ class Component(object): ...@@ -312,11 +312,13 @@ class Component(object):
elif exec_path is None and os.path.isfile(os.path.join(os.path.dirname(inspect.getfile(self.__class__)), "bin", software)): elif exec_path is None and os.path.isfile(os.path.join(os.path.dirname(inspect.getfile(self.__class__)), "bin", software)):
exec_path = os.path.join(os.path.dirname(inspect.getfile(self.__class__)), "bin", software) exec_path = os.path.join(os.path.dirname(inspect.getfile(self.__class__)), "bin", software)
elif exec_path is None and which(software) == None: elif exec_path is None and which(software) == None:
display_error_message("'" + software + "' path connot be retrieved either in the PATH and in the application.properties file!") logging.getLogger("jflow").exception("'" + software + "' path connot be retrieved either in the PATH and in the application.properties file!")
raise Exception("'" + software + "' path connot be retrieved either in the PATH and in the application.properties file!")
elif exec_path is None and which(software) != None: elif exec_path is None and which(software) != None:
exec_path = software exec_path = software
elif exec_path != None and not os.path.isfile(exec_path): elif exec_path != None and not os.path.isfile(exec_path):
display_error_message("'" + exec_path + "' set for '" + software + "' does not exists, please provide a valid path!") logging.getLogger("jflow").exception("'" + exec_path + "' set for '" + software + "' does not exists, please provide a valid path!")
raise Exception("'" + exec_path + "' set for '" + software + "' does not exists, please provide a valid path!")
return exec_path return exec_path
def get_nameid(self): def get_nameid(self):
......
...@@ -70,7 +70,8 @@ class JFlowConfigReader(object): ...@@ -70,7 +70,8 @@ class JFlowConfigReader(object):
exec_path = None exec_path = None
if exec_path is None: exec_path = "makeflow" if exec_path is None: exec_path = "makeflow"
if which(exec_path) == None: if which(exec_path) == None:
display_error_message("'makeflow' path connot be retrieved either in the PATH and in the application.properties file!") logging.getLogger("jflow").exception("'makeflow' path connot be retrieved either in the PATH and in the application.properties file!")
raise Exception("'makeflow' path connot be retrieved either in the PATH and in the application.properties file!")
return exec_path return exec_path
def get_date_format(self): def get_date_format(self):
......
...@@ -766,7 +766,7 @@ class AbstractInputFile(AbstractIOFile): ...@@ -766,7 +766,7 @@ class AbstractInputFile(AbstractIOFile):
# Parts of download # Parts of download
local_file.write(buffer) local_file.write(buffer)
local_file.close() local_file.close()
logging.getLogger("AbstractInputFile.download_urlfile").debug("URL file '{0}' successfully downloaded as: {1}".format(input, file_path)) logging.getLogger("jflow").debug("URL file '{0}' successfully downloaded as: {1}".format(input, file_path))
return [file_path, True] return [file_path, True]
except: except:
return [input, False] return [input, False]
...@@ -780,9 +780,9 @@ class AbstractInputFile(AbstractIOFile): ...@@ -780,9 +780,9 @@ class AbstractInputFile(AbstractIOFile):
try: try:
eval(self.file_format)(ifile) eval(self.file_format)(ifile)
except jflow.InvalidFormatError as e: except jflow.InvalidFormatError as e:
display_error_message(str(e)) raise Exception (str(e))
else: else:
display_error_message("Invalid file format '" + self.file_format + "'!") raise Exception("Invalid file format '" + self.file_format + "'!")
class AbstractOutputFile(AbstractIOFile): class AbstractOutputFile(AbstractIOFile):
""" """
......
...@@ -88,7 +88,9 @@ class Workflow(threading.Thread): ...@@ -88,7 +88,9 @@ class Workflow(threading.Thread):
PROPERTIES_FILE_NAME = "workflow.properties" PROPERTIES_FILE_NAME = "workflow.properties"
MAKEFLOW_LOG_FILE_NAME = "Makeflow.makeflowlog" MAKEFLOW_LOG_FILE_NAME = "Makeflow.makeflowlog"
DUMP_FILE_NAME = ".workflow.dump" DUMP_FILE_NAME = ".workflow.dump"
STDERR_FILE_NAME = "wf_stderr.txt"
WORKING = ".working" WORKING = ".working"
OLD_EXTENSION = ".old"
STATUS_STARTED = "started" STATUS_STARTED = "started"
STATUS_COMPLETED = "completed" STATUS_COMPLETED = "completed"
...@@ -151,7 +153,7 @@ class Workflow(threading.Thread): ...@@ -151,7 +153,7 @@ class Workflow(threading.Thread):
if not os.path.isdir(self.directory): if not os.path.isdir(self.directory):
os.makedirs(self.directory, 0751) os.makedirs(self.directory, 0751)
if self.stderr is None: if self.stderr is None:
self.set_stderr() self.stderr = self._set_stderr()
self._serialize() self._serialize()
def add_input_file(self, name, help, file_format="any", default=None, type="inputfile", def add_input_file(self, name, help, file_format="any", default=None, type="inputfile",
...@@ -288,7 +290,8 @@ class Workflow(threading.Thread): ...@@ -288,7 +290,8 @@ class Workflow(threading.Thread):
elif parameter.__class__ == InputFileList: elif parameter.__class__ == InputFileList:
if value == "" : value = [] # from GUI if value == "" : value = [] # from GUI
iovalues = [] iovalues = []
for file in parameter.prepare_input_files(value): prepared_files = parameter.prepare_input_files(value)
for file in prepared_files:
iovalues.append(IOFile(file, parameter.file_format, parameter.linkTrace_nameid, None)) iovalues.append(IOFile(file, parameter.file_format, parameter.linkTrace_nameid, None))
new_param = InputFileList( parameter.name, parameter.help, file_format=parameter.file_format, default=iovalues, new_param = InputFileList( parameter.name, parameter.help, file_format=parameter.file_format, default=iovalues,
type=parameter.type, choices=parameter.choices, required=parameter.required, flag=parameter.flag, type=parameter.type, choices=parameter.choices, required=parameter.required, flag=parameter.flag,
...@@ -296,7 +299,8 @@ class Workflow(threading.Thread): ...@@ -296,7 +299,8 @@ class Workflow(threading.Thread):
new_param.linkTrace_nameid = parameter.linkTrace_nameid new_param.linkTrace_nameid = parameter.linkTrace_nameid
elif parameter.__class__ == InputFile: elif parameter.__class__ == InputFile:
if value == "" : value = None # from GUI if value == "" : value = None # from GUI
new_param = InputFile( parameter.name, parameter.help, file_format=parameter.file_format, default=parameter.prepare_input_file(value), prepared_file = parameter.prepare_input_file(value)
new_param = InputFile( parameter.name, parameter.help, file_format=parameter.file_format, default=prepared_file,
type=parameter.type, choices=parameter.choices, required=parameter.required, flag=parameter.flag, type=parameter.type, choices=parameter.choices, required=parameter.required, flag=parameter.flag,
group=parameter.group, display_name=parameter.display_name ) group=parameter.group, display_name=parameter.display_name )
new_param.linkTrace_nameid = parameter.linkTrace_nameid new_param.linkTrace_nameid = parameter.linkTrace_nameid
...@@ -367,19 +371,6 @@ class Workflow(threading.Thread): ...@@ -367,19 +371,6 @@ class Workflow(threading.Thread):
for orphan_node in all_nodes.keys(): for orphan_node in all_nodes.keys():
gr.del_node(orphan_node) gr.del_node(orphan_node)
return gr return gr
def set_stderr(self):
if hasattr(self, "stderr") and self.stderr is not None:
os.rename( self.stderr, os.path.join(self.directory, str(time.time()) + "wf_stderr.old") )
stderr = os.path.join(self.directory, "wf_stderr.txt")
logger = logging.getLogger( "wf." + str(self.id) )
logger.setLevel(logging.DEBUG)
formatter = logging.Formatter( '%(asctime)s :: %(message)s' )
file_handler = FileHandler(stderr, 'a')
file_handler.setLevel(logging.ERROR)
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
self.stderr = stderr
def delete(self): def delete(self):
if self.get_status() in [self.STATUS_COMPLETED, self.STATUS_FAILED, self.STATUS_ABORTED]: if self.get_status() in [self.STATUS_COMPLETED, self.STATUS_FAILED, self.STATUS_ABORTED]:
...@@ -488,7 +479,7 @@ class Workflow(threading.Thread): ...@@ -488,7 +479,7 @@ class Workflow(threading.Thread):
FH_stderr = open( self.stderr ) FH_stderr = open( self.stderr )
lines = FH_stderr.readlines() lines = FH_stderr.readlines()
while line_idx < len(lines): while line_idx < len(lines):
if lines[line_idx].strip().endswith("RunWorflowException"): if lines[line_idx].strip().startswith("##"):
error["title"] = lines[line_idx].rstrip() error["title"] = lines[line_idx].rstrip()
error["msg"] = list() error["msg"] = list()
error["traceback"] = list() error["traceback"] = list()
...@@ -501,8 +492,8 @@ class Workflow(threading.Thread): ...@@ -501,8 +492,8 @@ class Workflow(threading.Thread):
}) })
line_idx += 2 line_idx += 2
# Error message # Error message
while line_idx < len(lines) and not lines[line_idx].strip().endswith("RunWorflowException"): while line_idx < len(lines) and not lines[line_idx].strip().startswith("##"):
error["msg"].append( lines[line_idx].strip() ) error["msg"].append( lines[line_idx].strip().split(":", 1)[1][1:] )
line_idx += 1 line_idx += 1
line_idx -= 1 line_idx -= 1
line_idx += 1 line_idx += 1
...@@ -582,7 +573,7 @@ class Workflow(threading.Thread): ...@@ -582,7 +573,7 @@ class Workflow(threading.Thread):
s.close() s.close()
except: except:
logging.getLogger("wf." + str(self.id)).debug("Impossible to connect to smtp server '" + smtps + "'") logging.getLogger("wf." + str(self.id)).debug("Impossible to connect to smtp server '" + smtps + "'")
def get_parameters_per_groups(self): def get_parameters_per_groups(self):
name = self.get_name() name = self.get_name()
description = self.get_description() description = self.get_description()
...@@ -611,11 +602,11 @@ class Workflow(threading.Thread): ...@@ -611,11 +602,11 @@ class Workflow(threading.Thread):
elif exec_path is None and os.path.isfile(os.path.join(os.path.dirname(inspect.getfile(self.__class__)), "bin", software)): elif exec_path is None and os.path.isfile(os.path.join(os.path.dirname(inspect.getfile(self.__class__)), "bin", software)):
exec_path = os.path.join(os.path.dirname(inspect.getfile(self.__class__)), "bin", software) exec_path = os.path.join(os.path.dirname(inspect.getfile(self.__class__)), "bin", software)
elif exec_path is None and utils.which(software) == None: elif exec_path is None and utils.which(software) == None:
utils.display_error_message("'" + software + "' path connot be retrieved either in the PATH and in the application.properties file!") raise Exception("'" + software + "' path connot be retrieved either in the PATH and in the application.properties file!")
elif exec_path is None and utils.which(software) != None: elif exec_path is None and utils.which(software) != None:
exec_path = software exec_path = software
elif exec_path != None and not os.path.isfile(exec_path): elif exec_path != None and not os.path.isfile(exec_path):
utils.display_error_message("'" + exec_path + "' set for '" + software + "' does not exists, please provide a valid path!") raise Exception("'" + exec_path + "' set for '" + software + "' does not exists, please provide a valid path!")
return exec_path return exec_path
def add_component(self, component_name, args=[], kwargs={}, component_prefix="default"): def add_component(self, component_name, args=[], kwargs={}, component_prefix="default"):
...@@ -775,9 +766,9 @@ class Workflow(threading.Thread): ...@@ -775,9 +766,9 @@ class Workflow(threading.Thread):
self.end_time = time.time() self.end_time = time.time()
self._serialize() self._serialize()
self._send_email() self._send_email()
except: except Exception as e:
logging.getLogger("wf." + str(self.id)).exception("RunWorflowException") logging.getLogger("wf." + str(self.id)).exception(str(e))
raise utils.display_error_message(str(e))
def _update_status_from_log(self): def _update_status_from_log(self):
# first update the status from weaver folders # first update the status from weaver folders
...@@ -851,7 +842,7 @@ class Workflow(threading.Thread): ...@@ -851,7 +842,7 @@ class Workflow(threading.Thread):
cpt.reset() cpt.reset()
found = True found = True
if not found: if not found:
utils.display_error_message("Impossible to reset component '" + component_name + "'! This one is not part of the workflow") raise Exception("Impossible to reset component '" + component_name + "'! This one is not part of the workflow")
self.reseted_components.append(component_name) self.reseted_components.append(component_name)
self.status = self.STATUS_RESETED self.status = self.STATUS_RESETED
self._serialize() self._serialize()
...@@ -875,6 +866,19 @@ class Workflow(threading.Thread): ...@@ -875,6 +866,19 @@ class Workflow(threading.Thread):
sys.stdout.write('{0:>10} {1:>10} {2}\n'.format('', 'COMMAND', node.command)) sys.stdout.write('{0:>10} {1:>10} {2}\n'.format('', 'COMMAND', node.command))
def _set_stderr(self):
if hasattr(self, "stderr") and self.stderr is not None:
os.rename( self.stderr, os.path.join(self.directory, str(time.time()) + self.STDERR_FILE_NAME + self.OLD_EXTENSION) )
stderr = os.path.join(self.directory, self.STDERR_FILE_NAME)
logger = logging.getLogger( "wf." + str(self.id) )
logger.setLevel(logging.DEBUG)
formatter = logging.Formatter( '## %(asctime)s :: %(message)s' )
file_handler = FileHandler(stderr, 'a')
file_handler.setLevel(logging.ERROR)
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
return stderr
def _execute_weaver(self, engine_wrapper=None): def _execute_weaver(self, engine_wrapper=None):
# Add nest path and path to script to Python module path to allow # Add nest path and path to script to Python module path to allow
# for importing modules outside of $PYTHONPATH # for importing modules outside of $PYTHONPATH
...@@ -962,7 +966,7 @@ class Workflow(threading.Thread): ...@@ -962,7 +966,7 @@ class Workflow(threading.Thread):
if issubclass(obj, jflow.component.Component) and obj.__name__ != jflow.component.Component.__name__: if issubclass(obj, jflow.component.Component) and obj.__name__ != jflow.component.Component.__name__:
pckge[class_name] = modname pckge[class_name] = modname
except Exception as e: except Exception as e:
logging.getLogger("Workflow._import_components").debug("Component <{0}> cannot be loaded: {1}".format(modname, e)) logging.getLogger("wf." + str(self.id)).debug("Component <{0}> cannot be loaded: {1}".format(modname, e))
# finally import workflows shared packages # finally import workflows shared packages
workflows_dir = os.path.dirname(os.path.dirname(inspect.getfile(self.__class__))) workflows_dir = os.path.dirname(os.path.dirname(inspect.getfile(self.__class__)))
for importer, modname, ispkg in pkgutil.iter_modules([os.path.join(workflows_dir, "components")], "workflows.components."): for importer, modname, ispkg in pkgutil.iter_modules([os.path.join(workflows_dir, "components")], "workflows.components."):
...@@ -972,7 +976,7 @@ class Workflow(threading.Thread): ...@@ -972,7 +976,7 @@ class Workflow(threading.Thread):
if issubclass(obj, jflow.component.Component) and obj.__name__ != jflow.component.Component.__name__: if issubclass(obj, jflow.component.Component) and obj.__name__ != jflow.component.Component.__name__:
pckge[class_name] = modname pckge[class_name] = modname
except Exception as e: except Exception as e:
logging.getLogger("Workflow._import_components").debug("Component <{0}> cannot be loaded: {1}".format(modname, e)) logging.getLogger("wf." + str(self.id)).debug("Component <{0}> cannot be loaded: {1}".format(modname, e))
return pckge return pckge
def _import(self, module, symbols): def _import(self, module, symbols):
......
...@@ -127,6 +127,7 @@ class WorkflowsManager(object): ...@@ -127,6 +127,7 @@ class WorkflowsManager(object):
del workflows_dump[rworkflow_id] del workflows_dump[rworkflow_id]
workflow_dump.close() workflow_dump.close()
except: except:
logging.getLogger("jflow").debug("Workflow #" + rworkflow_id + " connot be retrieved in the available workflows!")
utils.display_error_message("Workflow #" + rworkflow_id + " connot be retrieved in the available workflows!") utils.display_error_message("Workflow #" + rworkflow_id + " connot be retrieved in the available workflows!")
# and save them # and save them
pickle.dump(workflows_dump, open(self.dump_file, "w")) pickle.dump(workflows_dump, open(self.dump_file, "w"))
...@@ -187,7 +188,8 @@ class WorkflowsManager(object): ...@@ -187,7 +188,8 @@ class WorkflowsManager(object):
workflow = pickle.load(workflow_dump) workflow = pickle.load(workflow_dump)
workflow_dump.close() workflow_dump.close()
else: else:
utils.display_error_message("Workflow with id " + str(rworkflow_id) + " cannot be retrived") logging.getLogger("jflow").debug("Workflow #" + str(rworkflow_id) + " connot be retrieved in the available workflows!")
utils.display_error_message("Workflow #" + str(rworkflow_id) + " connot be retrieved in the available workflows!")
return workflow return workflow
def get_workflow_directory(self, wname, wid): def get_workflow_directory(self, wname, wid):
......
...@@ -70,7 +70,7 @@ ...@@ -70,7 +70,7 @@
if (this.options.forceUsingWorkflow) { if (this.options.forceUsingWorkflow) {
var workflow = this.reformatWorkflowJSON(this.options.forceUsingWorkflow); var workflow = this.reformatWorkflowJSON(this.options.forceUsingWorkflow);
this.$element.html(""); this.$element.html("");
$.tmpl(this.options.headTemplate, {workflow: workflow}).appendTo(this.$element); $.tmpl(this.options.headTemplate, {workflow: workflow, verbose:this.options.verbose}).appendTo(this.$element);
$.tmpl(this.options.listTemplate, {workflow: workflow}).appendTo(this.$element); $.tmpl(this.options.listTemplate, {workflow: workflow}).appendTo(this.$element);
// force for first display, then reload an update // force for first display, then reload an update
this.options.forceUsingWorkflow = null; this.options.forceUsingWorkflow = null;
...@@ -104,7 +104,7 @@ ...@@ -104,7 +104,7 @@
success: function(data) { success: function(data) {
var workflow = $this.reformatWorkflowJSON(data); var workflow = $this.reformatWorkflowJSON(data);
$this.$element.html(""); $this.$element.html("");
$.tmpl($this.options.headTemplate, {workflow: workflow}).appendTo($this.$element); $.tmpl($this.options.headTemplate, {workflow: workflow, verbose:$this.options.verbose}).appendTo($this.$element);
$.tmpl($this.options.listTemplate, {workflow: workflow}).appendTo($this.$element); $.tmpl($this.options.listTemplate, {workflow: workflow}).appendTo($this.$element);
// handle if there is some error // handle if there is some error
...@@ -164,7 +164,7 @@ ...@@ -164,7 +164,7 @@
success: function(data) { success: function(data) {
var workflow = $this.reformatWorkflowJSON(data); var workflow = $this.reformatWorkflowJSON(data);
$this.$element.html(""); $this.$element.html("");
$.tmpl($this.options.headTemplate, {workflow: workflow}).appendTo($this.$element); $.tmpl($this.options.headTemplate, {workflow: workflow, verbose:$this.options.verbose}).appendTo($this.$element);
$.tmpl($this.options.graphTemplate, {workflow: workflow}).appendTo($this.$element); $.tmpl($this.options.graphTemplate, {workflow: workflow}).appendTo($this.$element);
// prepare the data // prepare the data
...@@ -457,10 +457,12 @@ ...@@ -457,10 +457,12 @@
'<dd>${workflow.elapsed_time}</dd>', '<dd>${workflow.elapsed_time}</dd>',
'</dl>', '</dl>',
'<div id="wfstatus_error_panel" class="alert alert-danger" role="alert" style="display:none;">', '<div id="wfstatus_error_panel" class="alert alert-danger" role="alert" style="display:none;">',
' <strong>Error message :</strong><br/>', ' <strong>Error!</strong>',
' <span id="wfstatus_error_msg"></span><br/>', ' <span id="wfstatus_error_msg"></span><br/>',
' <strong>Error location :</strong><br/>', ' {{if verbose}}',
' <span id="wfstatus_error_location"></span>', ' <strong>Error location:</strong><br/>',
' <span id="wfstatus_error_location"></span>',
' {{/if}}',
'</div>'].join('\n'), '</div>'].join('\n'),
listTemplate: ['<dl class="dl-horizontal">', listTemplate: ['<dl class="dl-horizontal">',
'{{each(index, component) workflow.components}}', '{{each(index, component) workflow.components}}',
...@@ -487,6 +489,7 @@ ...@@ -487,6 +489,7 @@
'</div>'].join('\n'), '</div>'].join('\n'),
workflowID: null, workflowID: null,
forceUsingWorkflow: null, forceUsingWorkflow: null,
verbose: false,
display: "graph" display: "graph"
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment