Commit a0ef382b authored by Janez K's avatar Janez K

nicer error reporting

parent 6dcf7a3b
......@@ -15,16 +15,19 @@ from mothra.settings import USE_CONCURRENCY
if USE_CONCURRENCY:
from workflows.tasks import runWidgetAsync, runForLoopIteration
class WidgetException(Exception):
pass
class Connection(models.Model):
output = models.ForeignKey("Output",related_name="connections")
input = models.ForeignKey("Input",related_name="connections")
workflow = models.ForeignKey("Workflow",related_name="connections")
class Category(models.Model):
name = models.CharField(max_length=50)
parent = models.ForeignKey('self',related_name="children",null=True,blank=True)
user = models.ForeignKey(User,null=True,blank=True,related_name="categories")
workflow = models.ForeignKey('Workflow',null=True,blank=True,related_name="categories")
order = models.PositiveIntegerField(default=1)
......@@ -48,14 +51,14 @@ class Workflow(models.Model):
description = models.TextField(blank=True,default='')
widget = models.OneToOneField('Widget',related_name="workflow_link",blank=True,null=True)
template_parent = models.ForeignKey('Workflow',blank=True,null=True,default=None,on_delete=models.SET_NULL)
def is_for_loop(self):
if self.widgets.filter(type='for_input').count()>0:
return True
else:
return False
return False
def get_ready_to_run(self):
widgets = self.widgets.all()
unfinished_list = []
......@@ -70,7 +73,7 @@ class Workflow(models.Model):
if ready_to_run:
unfinished_list.append(w.id)
return unfinished_list
def get_runnable_widgets(self):
widgets = self.widgets.all()
unfinished_list = []
......@@ -93,7 +96,7 @@ class Workflow(models.Model):
outer_output = fo.inputs.all()[0].outer_output
outer_output.value=[]
outer_output.save()
input_list = fi.outputs.all()[0].outer_input.value
progress_total = len(input_list)
current_iteration = 0
......@@ -112,7 +115,7 @@ class Workflow(models.Model):
for w in unfinished_list:
w.run(True)
total = self.widgets.count()
completed = self.widgets.filter(finished=True).count()
completed = self.widgets.filter(finished=True).count()
self.widget.progress = (int)((current_iteration*100.0/progress_total)+(((completed*1.0)/total)*(100/progress_total)))
self.widget.save()
unfinished_list = self.get_runnable_widgets()
......@@ -148,7 +151,7 @@ class Workflow(models.Model):
completed = self.widgets.filter(finished=True).count()
if self.widget:
self.widget.progress = (int)((current_iteration*100.0/progress_total)+(((completed*1.0)/total)*(100/progress_total)))
self.widget.save()
self.widget.save()
unfinished_list = self.get_runnable_widgets()
except:
raise
......@@ -189,7 +192,7 @@ class Workflow(models.Model):
self.widget.progress = (int)(((completed*1.0)/total)*100)
self.widget.save()
is_running=True
unfinished_list = self.get_runnable_widgets()
unfinished_list = self.get_runnable_widgets()
while len(unfinished_list)==0 and is_running:
unfinished_list = self.get_runnable_widgets()
is_running = False
......@@ -201,32 +204,32 @@ class Workflow(models.Model):
completed = self.widgets.filter(finished=True).count()
if self.widget:
self.widget.progress = (int)(((completed*1.0)/total)*100)
self.widget.save()
self.widget.save()
time.sleep(1)
unfinished_list = self.get_runnable_widgets()
unfinished_list = self.get_runnable_widgets()
except:
raise
def rename(self,new_name):
self.name = new_name
self.save()
self.save()
@models.permalink
def get_absolute_url(self):
return ('open workflow', [str(self.id)])
return ('open workflow', [str(self.id)])
@models.permalink
def get_copy_url(self):
return ('copy workflow', [str(self.id)])
@models.permalink
def get_info_url(self):
return ('workflow information', [str(self.id)])
def __unicode__(self):
return unicode(self.name)
class Meta:
ordering = ['name']
ordering = ['name']
class AbstractWidget(models.Model):
name = models.CharField(max_length=200,help_text='Name is the name that will be displayed in the widget repository and under the actual widget itself.')
......@@ -240,21 +243,21 @@ class AbstractWidget(models.Model):
interactive = models.BooleanField(default=False,help_text='The widget can be interactive. This means that when a user executes the widget, the action will perform, then the interaction view will be executed and finally the Post interact action will be executed.')
interaction_view = models.CharField(max_length=200,blank=True,default='')
post_interact_action = models.CharField(max_length=200,blank=True,default='')
image = ThumbnailField(blank=True,null=True,upload_to="images",size=(34,34),help_text='Image and Treeview image are deprecated and will be phased out soon. Please use the static image field.')
treeview_image = ThumbnailField(blank=True,null=True,upload_to="treeview",size=(16,16))
static_image = models.CharField(max_length=250,blank=True,default='',help_text='In the static image field just enter the filename of the image (without the path). The path will be $package_name$/icons/widget/$filename$ and $package_name$/icons/treeview/$filename$ where the treeview image is the small image that appears in the treeview on the left side and the widget image is the actual normal sized icon for the widget. IMPORTANT: the static image field only works if the package is set.')
has_progress_bar = models.BooleanField(default=False,help_text='The flag has progress bar determines if the widget implements a progress bar.')
is_streaming = models.BooleanField(default=False,help_text='The is streaming flag is currently under construction, please do not use it yet.')
order = models.PositiveIntegerField(default=1,help_text='The Order determines the order in which the widget will be displayed in the repository. This is set automatically when sorting widgets in a single category from the admin.')
uid = models.CharField(max_length=250,blank=True,default='',help_text='UID is set automatically when you export a package with the -u switch.')
package = models.CharField(max_length=150,blank=True,default='',help_text='Package is the package name. You are encouraged to use packages.')
class Meta:
ordering = ('order','name',)
......@@ -298,17 +301,17 @@ class AbstractInput(models.Model):
('file', 'File'),
)
parameter_type = models.CharField(max_length=50,choices=PARAMETER_CHOICES,blank=True,null=True)
order = models.PositiveIntegerField(default=1)
uid = models.CharField(max_length=250,blank=True,default='')
def __unicode__(self):
return unicode(self.name)
class Meta:
ordering = ('order',)
class AbstractOption(models.Model):
abstract_input = models.ForeignKey(AbstractInput,related_name="options")
name = models.CharField(max_length=200)
......@@ -318,9 +321,9 @@ class AbstractOption(models.Model):
def __unicode__(self):
return unicode(self.name)
class Meta:
ordering = ['name']
ordering = ['name']
class AbstractOutput(models.Model):
name = models.CharField(max_length=200)
......@@ -328,14 +331,14 @@ class AbstractOutput(models.Model):
description = models.TextField(blank=True)
variable = models.CharField(max_length=50,help_text='The variable attribute of both the input and the output are important because this is how the data will be accessed in the python function that is executed when the widget runs.')
widget = models.ForeignKey(AbstractWidget,related_name="outputs")
order = models.PositiveIntegerField(default=1)
uid = models.CharField(max_length=250,blank=True,default='')
class Meta:
ordering = ('order',)
ordering = ('order',)
def __unicode__(self):
return unicode(self.name)
......@@ -356,23 +359,23 @@ class Widget(models.Model):
('output', 'Output widget'),
)
type = models.CharField(max_length=50,choices=WIDGET_CHOICES,default='regular')
progress = models.IntegerField(default=0)
def is_visualization(self):
try:
if self.abstract_widget.visualization_view != '':
return True
except:
return False
def ready_to_run(self):
cons = Connection.objects.filter(input__widget=self)
for c in cons:
if not c.output.widget.finished:
return False
return True
def unfinish(self):
if self.finished or self.error:
self.finished=False
......@@ -390,7 +393,7 @@ class Widget(models.Model):
w.save()
if w.type=='subprocess':
w.subunfinish()
def subunfinish(self):
if self.type == 'subprocess':
for w in self.workflow_link.widgets.all():
......@@ -399,7 +402,7 @@ class Widget(models.Model):
w.save()
if w.type=='subprocess':
w.subunfinish()
def rename(self,new_name):
self.name = new_name
self.save()
......@@ -418,17 +421,17 @@ class Widget(models.Model):
inp.save()
inp.outer_output.name = self.name
inp.outer_output.short_name = self.name[:3]
inp.outer_output.save()
inp.outer_output.save()
try:
w_link = self.workflow_link
w_link.name=new_name
w_link.save()
except Workflow.DoesNotExist:
pass
def run(self,offline):
if not self.ready_to_run():
raise Exception("The prerequisites for running this widget have not been met.")
raise WidgetException("The prerequisites for running this widget have not been met.")
self.running=True
self.save()
if self.type == 'regular' or self.type == 'subprocess':
......@@ -535,12 +538,12 @@ class Widget(models.Model):
i.outer_output.value = i.value
i.outer_output.save()
self.finished=True
self.finished=True
self.finished=True
self.running=False
self.error=False
self.save()
return None
def reset(self,offline):
for i in self.inputs.defer("value").all():
if not i.parameter:
......@@ -556,7 +559,7 @@ class Widget(models.Model):
def run_post(self,request):
if not self.ready_to_run():
raise Exception("The prerequisites for running this widget have not been met.")
raise WidgetException("The prerequisites for running this widget have not been met.")
self.running=True
self.save()
function_to_call = getattr(workflows.library,self.abstract_widget.post_interact_action)
......@@ -603,11 +606,11 @@ class Widget(models.Model):
cons = Connection.objects.filter(output__widget=self)
for c in cons:
c.input.widget.unfinish()
return outputs
return outputs
def __unicode__(self):
return unicode(self.name)
class Input(models.Model):
name = models.CharField(max_length=200)
short_name = models.CharField(max_length=3)
......@@ -630,17 +633,17 @@ class Input(models.Model):
class Meta:
ordering = ('order',)
def __unicode__(self):
return unicode(self.name)
return unicode(self.name)
class Option(models.Model):
input = models.ForeignKey(Input,related_name="options")
name = models.CharField(max_length=200)
value = models.TextField(blank=True,null=True)
class Meta:
ordering = ['name']
ordering = ['name']
class Output(models.Model):
name = models.CharField(max_length=200)
......@@ -655,14 +658,14 @@ class Output(models.Model):
class Meta:
ordering = ('order',)
def __unicode__(self):
return unicode(self.name)
class UserProfile(models.Model):
user = models.OneToOneField(User,related_name="userprofile")
active_workflow = models.ForeignKey(Workflow,related_name="users",null=True,blank=True,on_delete=models.SET_NULL)
def __unicode__(self):
return unicode(self.user)
......@@ -762,4 +765,4 @@ def copy_workflow(old, user, parent_widget_conversion={},parent_input_conversion
for widget in old.widgets.filter(type='subprocess'):
#tuki mormo vse subprocesse zrihtat
copy_workflow(widget.workflow_link, user, widget_conversion, input_conversion, output_conversion, Widget.objects.get(pk=widget_conversion[widget.id]))
return w
\ No newline at end of file
return w
......@@ -62,7 +62,7 @@ def new_workflow(request):
request.user.userprofile.active_workflow = w
request.user.userprofile.save()
return redirect('the index')
@login_required
def open_workflow(request,workflow_id):
w = get_object_or_404(Workflow, pk=workflow_id)
......@@ -70,9 +70,9 @@ def open_workflow(request,workflow_id):
request.user.userprofile.active_workflow = w
request.user.userprofile.save()
else:
return HttpResponse(status=400)
return redirect('the index')
return HttpResponse(status=400)
return redirect('the index')
@login_required
def widget_progress(request):
w = get_object_or_404(Widget, pk=request.GET['widget_id'])
......@@ -82,7 +82,7 @@ def widget_progress(request):
if w.progress==100:
return HttpResponse("100")
return HttpResponse("-1")
@login_required
def add_widget(request):
if request.is_ajax() or DEBUG:
......@@ -172,7 +172,7 @@ def add_widget(request):
j.widget = w
j.required = i.required
j.parameter = i.parameter
j.parameter_type = i.parameter_type
j.parameter_type = i.parameter_type
j.value = i.value
j.multi_id = i.multi_id
j.save()
......@@ -192,13 +192,13 @@ def add_widget(request):
j.save()
w.defered_outputs = w.outputs.defer("value").all()
w.defered_inputs = w.inputs.defer("value").all()
return render(request, 'widgets.html', {'widgets':[w,]})
return render(request, 'widgets.html', {'widgets':[w,]})
elif aw.type=='subprocess':
workflow = get_object_or_404(Workflow, pk=request.POST['active_workflow'])
if (workflow.user==request.user):
widget_conversion = {}
input_conversion = {}
output_conversion = {}
output_conversion = {}
w = Widget()
w.workflow = workflow
w.x = int(request.POST['scrollLeft'])+50
......@@ -220,7 +220,7 @@ def add_widget(request):
j.widget = w
j.required = i.required
j.parameter = i.parameter
j.parameter_type = i.parameter_type
j.parameter_type = i.parameter_type
j.value = i.value
j.multi_id = i.multi_id
j.save()
......@@ -243,12 +243,12 @@ def add_widget(request):
workflows.models.copy_workflow(aw.workflow_link, request.user, widget_conversion,input_conversion,output_conversion,w)
w.defered_outputs = w.outputs.defer("value").all()
w.defered_inputs = w.inputs.defer("value").all()
return render(request, 'widgets.html', {'widgets':[w,]})
return render(request, 'widgets.html', {'widgets':[w,]})
else:
return HttpResponse(status=400)
else:
return HttpResponse(status=400)
@login_required
def save_position(request):
if request.is_ajax() or DEBUG:
......@@ -262,7 +262,7 @@ def save_position(request):
return HttpResponse(status=400)
else:
return HttpResponse(status=400)
@login_required
def add_connection(request):
if request.is_ajax() or DEBUG:
......@@ -329,7 +329,7 @@ def add_connection(request):
return HttpResponse(data,mimetype)
else:
return HttpResponse(status=400)
@login_required
def delete_connection(request):
if request.is_ajax() or DEBUG:
......@@ -360,7 +360,7 @@ def delete_widget(request):
if request.is_ajax() or DEBUG:
w = get_object_or_404(Widget, pk=request.POST['widget_id'])
w.unfinish()
mimetype = 'application/javascript'
mimetype = 'application/javascript'
refresh = []
delete_tab = -1
if (w.workflow.user!=request.user):
......@@ -392,7 +392,7 @@ def add_subprocess(request):
w.x = int(request.POST['scrollLeft'])+50
y = int(request.POST['scrollTop'])+50
while workflow.widgets.filter(y=y,x=w.x).count()>0:
y = y + 100
y = y + 100
w.y=y
w.name = "Untitled widget"
w.type = 'subprocess'
......@@ -432,7 +432,7 @@ def add_for(request):
elif workflow.widgets.filter(type='for_input').count()>0:
message = 'This subprocess already has a for loop. Try deleting it and adding it again.'
data = simplejson.dumps({'message':message,'success':success})
return HttpResponse(data,mimetype)
return HttpResponse(data,mimetype)
else:
for_input = Widget()
for_input.workflow = workflow
......@@ -459,7 +459,7 @@ def add_for(request):
input.save()
output.outer_input = input
output.save()
widget = Widget()
widget.workflow = workflow
widget.x=int(request.POST['scrollLeft'])+200
......@@ -485,14 +485,14 @@ def add_for(request):
for_input.defered_outputs = for_input.outputs.defer("value").all()
for_input.defered_inputs = for_input.inputs.defer("value").all()
widget.defered_outputs = widget.outputs.defer("value").all()
widget.defered_inputs = widget.inputs.defer("value").all()
return render(request, 'widgets.html', {'widgets':[for_input,widget]})
widget.defered_inputs = widget.inputs.defer("value").all()
return render(request, 'widgets.html', {'widgets':[for_input,widget]})
else:
return HttpResponse(status=400)
else:
return HttpResponse(status=400)
return HttpResponse(status=400)
@login_required
def add_input(request):
success = False
......@@ -511,7 +511,7 @@ def add_input(request):
widget.x=int(request.POST['scrollLeft'])+50
y = int(request.POST['scrollTop'])+50
while workflow.widgets.filter(y=y,x=widget.x).count()>0:
y = y + 100
y = y + 100
widget.y=y
widget.name = 'Input'
widget.type = 'input'
......@@ -538,7 +538,7 @@ def add_input(request):
return HttpResponse(status=400)
else:
return HttpResponse(status=400)
@login_required
def add_output(request):
success = False
......@@ -583,8 +583,8 @@ def add_output(request):
else:
return HttpResponse(status=400)
else:
return HttpResponse(status=400)
return HttpResponse(status=400)
@login_required
def synchronize_widgets(request):
if request.is_ajax() or DEBUG:
......@@ -601,7 +601,7 @@ def synchronize_widgets(request):
return HttpResponse(status=400)
else:
return HttpResponse(status=400)
@login_required
def synchronize_connections(request):
if request.is_ajax() or DEBUG:
......@@ -614,8 +614,8 @@ def synchronize_connections(request):
else:
return HttpResponse(status=400)
else:
return HttpResponse(status=400)
return HttpResponse(status=400)
@login_required
def get_widget(request):
if request.is_ajax() or DEBUG:
......@@ -628,7 +628,7 @@ def get_widget(request):
return HttpResponse(status=400)
else:
return HttpResponse(status=400)
@login_required
def get_parameters(request):
if request.is_ajax() or DEBUG:
......@@ -639,7 +639,7 @@ def get_parameters(request):
return HttpResponse(status=400)
else:
return HttpResponse(status=400)
@login_required
def save_parameter(request):
if request.is_ajax() or DEBUG:
......@@ -667,7 +667,7 @@ def get_configuration(request):
return HttpResponse(status=400)
else:
return HttpResponse(status=400)
@login_required
def save_configuration(request):
if request.is_ajax() or DEBUG:
......@@ -744,8 +744,8 @@ def save_designation(request):
input.save()
return HttpResponse(status=200)
else:
return HttpResponse(status=400)
return HttpResponse(status=400)
@login_required
def get_parameters(request):
if request.is_ajax() or DEBUG:
......@@ -755,8 +755,8 @@ def get_parameters(request):
else:
return HttpResponse(status=400)
else:
return HttpResponse(status=400)
return HttpResponse(status=400)
@login_required
def get_rename_dialog(request):
if request.is_ajax() or DEBUG:
......@@ -766,7 +766,7 @@ def get_rename_dialog(request):
else:
return HttpResponse(status=400)
else:
return HttpResponse(status=400)
return HttpResponse(status=400)
@login_required
def rename_widget(request):
......@@ -795,7 +795,7 @@ def rename_widget(request):
return HttpResponse(status=400)
else:
return HttpResponse(status=400)
@login_required
def rename_workflow(request):
if request.is_ajax() or DEBUG:
......@@ -814,8 +814,8 @@ def rename_workflow(request):
else:
return HttpResponse(status=400)
else:
return HttpResponse(status=400)
return HttpResponse(status=400)
@login_required
def run_widget(request):
if request.is_ajax() or DEBUG:
......@@ -850,13 +850,13 @@ def run_widget(request):
for o in w.outputs.all():
o.value=None
o.save()
data = simplejson.dumps({'status':'error','message':'Error occurred when trying to execute widget '+w.name+':<pre>'+str(sys.exc_info())+'</pre>'})
data = simplejson.dumps({'status':'error','message':'Error occurred when trying to execute widget '+w.name+': '+str(type(e))+' '+str(e)})
return HttpResponse(data,mimetype)
else:
return HttpResponse(status=400)
else:
return HttpResponse(status=400)
@login_required
def run_tree(request):
if request.is_ajax() or DEBUG:
......@@ -885,11 +885,11 @@ def run_tree(request):
w.finished = False
w.save()
print traceback.format_exc(e)
raise
#raise
for o in w.outputs.all():
o.value=None
o.save()
data = simplejson.dumps({'status':'error','message':'Error occurred when trying to execute widget '+w.name+':<pre>'+str(sys.exc_info())+'</pre>'})
data = simplejson.dumps({'status':'error','message':'Error occurred when trying to execute widget '+w.name+': '+str(type(e))+' '+str(e)})
return HttpResponse(data,mimetype)
else:
return HttpResponse(status=400)
......@@ -914,12 +914,12 @@ def reset_widget(request):
w.save()
print traceback.format_exc(e)