Coupure prévue mardi 3 Août au matin pour maintenance du serveur. Nous faisons au mieux pour que celle-ci soit la plus brève possible.

models.py 58.6 KB
Newer Older
Janez K's avatar
Janez K committed
1
2
3
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
4
from django.conf import settings
Janez K's avatar
Janez K committed
5
6
7
import workflows.library

import time
8
import random
Janez K's avatar
Janez K committed
9
10
11
12
13
14

from picklefield.fields import PickledObjectField

from workflows.thumbs import ThumbnailField

from mothra.settings import DEBUG
Janez K's avatar
Janez K committed
15
from mothra.settings import USE_CONCURRENCY
Janez K's avatar
Janez K committed
16

Janez K's avatar
Janez K committed
17
if USE_CONCURRENCY:
Janez K's avatar
Janez K committed
18
19
    from workflows.tasks import runWidgetAsync, runForLoopIteration

Janez K's avatar
Janez K committed
20
from workflows.tasks import executeWidgetFunction, executeWidgetProgressBar, executeWidgetStreaming, executeWidgetWithRequest, runWidget, executeWidgetPostInteract
21

22
23
from workflows.engine import WidgetRunner, WorkflowRunner

Janez K's avatar
Janez K committed
24
25
26
class WidgetException(Exception):
    pass

Janez K's avatar
Janez K committed
27
28
29
30
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")
Janez K's avatar
Janez K committed
31

32
33
    def export(self):
        d = {}
Janez K's avatar
Janez K committed
34
35
        d['output_id']=self.output_id
        d['input_id']=self.input_id
36
37
        return d

38
39
40
41
42
    def import_from_json(self,json_data,input_conversion,output_conversion):
        self.output_id = output_conversion[json_data['output_id']]
        self.input_id = input_conversion[json_data['input_id']]
        self.save()

Janez K's avatar
Janez K committed
43
44
45
46
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")
Janez K's avatar
Janez K committed
47

Janez K's avatar
Janez K committed
48
    workflow = models.ForeignKey('Workflow',null=True,blank=True,related_name="categories")
49
50
51

    order = models.PositiveIntegerField(default=1)

Janez K's avatar
Janez K committed
52
53
    uid = models.CharField(max_length=250,blank=True,default='')

Janez K's avatar
Janez K committed
54
55
56
    def update_uid(self):
        import uuid
        if self.uid == '' or self.uid is None:
Janez K's avatar
bugfix  
Janez K committed
57
            self.uid = str(uuid.uuid4())
Janez K's avatar
Janez K committed
58
59
60
61
            self.save()
        if self.parent:
            self.parent.update_uid()

Janez K's avatar
Janez K committed
62
63
    class Meta:
        verbose_name_plural = "categories"
64
65
        ordering = ('order','name',)

Janez K's avatar
Janez K committed
66
67
68
69
70
71
72
    def __unicode__(self):
        if self.parent is None:
            return unicode(self.name)
        else:
            return unicode(unicode(self.parent)+" :: "+self.name)

class Workflow(models.Model):
dejan's avatar
dejan committed
73
74
75
76
    name = models.CharField(max_length=200,default='Untitled workflow') # a field
    user = models.ForeignKey(User,related_name="workflows") # django relationship (ForeignKey), each Workflow is related to a single User
    public = models.BooleanField(default=False) # a field
    description = models.TextField(blank=True,default='') # a field
Janez K's avatar
Janez K committed
77
78
    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)
Janez K's avatar
Janez K committed
79

80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
    def import_from_json(self,json_data,input_conversion,output_conversion):
        self.name = json_data['name']
        self.description = json_data['description']
        self.save()
        for widget in json_data['widgets']:
            w = Widget()
            w.workflow = self
            w.import_from_json(widget,input_conversion,output_conversion)
            if widget['workflow']:
                subwidget_workflow = Workflow()
                subwidget_workflow.user = self.user
                subwidget_workflow.import_from_json(widget['workflow'],input_conversion,output_conversion)
                subwidget_workflow.widget = w
                subwidget_workflow.save()
        for connection in json_data['connections']:
            c = Connection()
            c.workflow = self
            c.import_from_json(connection,input_conversion,output_conversion)

99
100
101
102
103
104
    def export(self):
        """ Exports the workflow to a dictionary that can be imported """
        d = {}
        d['name']=self.name
        d['description']=self.description
        d['widgets'] = []
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
        inps = Input.objects.filter(widget__workflow=self).defer('value').prefetch_related('options')
        outs = Output.objects.filter(widget__workflow=self).defer('value')
        widgets = self.widgets.all().select_related('abstract_widget')
        workflow_links = Workflow.objects.filter(widget__in=widgets)
        inps_by_id = {}
        outs_by_id = {}
        for i in inps:
            l = inps_by_id.get(i.widget_id,[])
            l.append(i)
            inps_by_id[i.widget_id] = l
        for o in outs:
            l = outs_by_id.get(o.widget_id,[])
            l.append(o)
            outs_by_id[o.widget_id] = l
        for w in widgets:
            for workflow in workflow_links:
                if workflow.widget_id == w.id:
                    w.workflow_link_data = workflow
                    w.workflow_link_exists = True
                    break
            else:
                w.workflow_link_exists = False
            w.inputs_all = inps_by_id.get(w.id,[])
            w.outputs_all = outs_by_id.get(w.id,[])
129
130
131
132
133
134
            d['widgets'].append(w.export())
        d['connections'] = []
        for c in self.connections.all():
            d['connections'].append(c.export())
        return d

Janez K's avatar
Janez K committed
135
    def can_be_streaming(self):
dejan's avatar
dejan committed
136
137
        """ Method checks if workflow can be streamed. Check if there is at least one widget with
        the flag abstract_widget__is_streaming on True.  """
Janez K's avatar
Janez K committed
138
139
140
141
        if self.widgets.filter(abstract_widget__is_streaming=True).count()>0:
            return True
        else:
            return False
Janez K's avatar
Janez K committed
142

Janez K's avatar
Janez K committed
143
    def is_for_loop(self):
dejan's avatar
dejan committed
144
145
        """ Method checks if workflow is a for loop. Checks if at least one widget is 
        type for_input. """
Janez K's avatar
Janez K committed
146
147
148
        if self.widgets.filter(type='for_input').count()>0:
            return True
        else:
Janez K's avatar
Janez K committed
149
150
            return False

dejan's avatar
dejan committed
151
152
153
154
155
156
157
158
    def is_cross_validation(self):
        """ Method checks if workflow is a for loop. Checks if at least one widget is 
        type cv input. """
        if self.widgets.filter(type='cv_input').count()>0:
            return True
        else:
            return False

Janez K's avatar
Janez K committed
159
    def get_ready_to_run(self):
dejan's avatar
dejan committed
160
        """ Method prepares this workflows widgets. Returns a list of widget id-s. """
Janez K's avatar
Janez K committed
161
162
163
164
        widgets = self.widgets.all()
        unfinished_list = []
        for w in widgets:
            if not w.finished and not w.running:
dejan's avatar
dejan committed
165
                """ if widget isn't finished and is not running than true"""
Janez K's avatar
Janez K committed
166
167
168
169
                ready_to_run = True
                connections = self.connections.filter(input__widget=w)
                for c in connections:
                    if not c.output.widget.finished:
dejan's avatar
dejan committed
170
                        """ if widget not finished than true """
Janez K's avatar
Janez K committed
171
172
173
174
175
                        ready_to_run = False
                        break
                if ready_to_run:
                    unfinished_list.append(w.id)
        return unfinished_list
Janez K's avatar
Janez K committed
176

Janez K's avatar
Janez K committed
177
    def get_runnable_widgets(self):
dejan's avatar
dejan committed
178
179
        """ Method is the same as get_ready_to_run method. The difference is only that this method
        returns a list widgets as objects (and not only id-s).  """
Janez K's avatar
Janez K committed
180
181
182
183
184
        widgets = self.widgets.all()
        unfinished_list = []
        for w in widgets:
            if not w.finished and not w.running:
                ready_to_run = True
185
                connections = self.connections.filter(input__widget=w).select_related('input__widget')
Janez K's avatar
Janez K committed
186
187
                for c in connections:
                    if not c.output.widget.finished:
188
                        #print c.output.widget
Janez K's avatar
Janez K committed
189
190
191
192
193
194
                        ready_to_run = False
                        break
                if ready_to_run:
                    unfinished_list.append(w)
        return unfinished_list

Janez K's avatar
Janez K committed
195
    """def run_for_loop(self):
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
        widgets = self.widgets.all().prefetch_related('inputs','outputs')
        connections = self.connections.all().select_related('input','output','input__widget','output__widget')
        fi = None
        fo = None
        for w in widgets:
            if w.type=='for_input':
                fi = w
            if w.type=='for_output':
                fo = w
        outer_output = fo.inputs.all()[0].outer_output
        outer_output.value=[]
        outer_output.save()
        total = len(widgets)
        input_list = fi.outputs.all()[0].outer_input.value # get all inputs from outer part
        progress_total = len(input_list) # for progress bar
        current_iteration = 0
        for i in input_list:
            finished = []
            unfinished_list = []
            fi.finished = True
Janez K's avatar
Janez K committed
216
            proper_output = fi.outputs.all()[0]"""
217

Janez K's avatar
Janez K committed
218
    def run_for_loop(self):
dejan's avatar
dejan committed
219
220
        """ Method runs the workflow for loop. The use of [0] at the end of lines is because
        there can be only one for loop in one workflow. This way we take the first one. """
Janez K's avatar
Janez K committed
221
        #clear for_input and for_output
222
        #print("run_for_loop")
223
224
225
226
227
228
229
230
        widgets = self.widgets.all().prefetch_related('inputs','outputs')
        fi = None
        fo = None
        for w in widgets:
            if w.type=='for_input':
                fi = w
            if w.type=='for_output':
                fo = w
Janez K's avatar
Janez K committed
231
232
233
        outer_output = fo.inputs.all()[0].outer_output
        outer_output.value=[]
        outer_output.save()
234
        total = len(widgets)
dejan's avatar
dejan committed
235
236
        input_list = fi.outputs.all()[0].outer_input.value # get all inputs from outer part
        progress_total = len(input_list) # for progress bar
Janez K's avatar
Janez K committed
237
238
        current_iteration = 0
        for i in input_list:
Anze Vavpetic's avatar
Anze Vavpetic committed
239
            #print(i);
dejan's avatar
dejan committed
240
241
242
243
            """ Different parameters on which the widgets are going to be run"""
            fi.unfinish() # resets widgets, (read all widgets.finished=false)
            fo.unfinish() # resets widgets, (read all widgets.finished=false)
            proper_output = fi.outputs.all()[0] # inner output
Janez K's avatar
Janez K committed
244
245
            proper_output.value = i
            proper_output.save()
dejan's avatar
dejan committed
246
            fi.finished=True # set the input widget as finished
Janez K's avatar
Janez K committed
247
            fi.save()
Janez K's avatar
Janez K committed
248
            if not USE_CONCURRENCY or 1==1:
dejan's avatar
dejan committed
249
                """ This if statement is always true. """
Janez K's avatar
Janez K committed
250
251
252
253
                unfinished_list = self.get_runnable_widgets()
                try:
                    while len(unfinished_list)>0:
                        for w in unfinished_list:
dejan's avatar
dejan committed
254
                            w.run(True) # run the widget
255
256
257
258
259
260
                            completed = 0
                            for w in widgets:
                                if w.finished:
                                    completed = completed+1
                        self.widget.progress = (int)((current_iteration*100.0/progress_total)+(((completed*1.0)/total)*(100/progress_total)))
                        self.widget.save()                        
Janez K's avatar
Janez K committed
261
262
263
264
                        unfinished_list = self.get_runnable_widgets()
                except:
                    raise
            else:
dejan's avatar
dejan committed
265
                """ This part is never executed  """
Janez K's avatar
Janez K committed
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
                unfinished_list = self.get_runnable_widgets()
                try:
                    statuses = {}
                    total = self.widgets.count()
                    completed = self.widgets.filter(finished=True).count()
                    while len(unfinished_list)>0:
                        for w in unfinished_list:
                            if statuses.has_key(w.pk):
                                if statuses[w.pk].failed():
                                    raise Exception(statuses[w.pk].info[0])
                            else:
                                statuses[w.pk]=runWidgetAsync.delay(w)
                            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()
                        is_running=True
                        unfinished_list = self.get_runnable_widgets()
                        while len(unfinished_list)==0 and is_running:
                            unfinished_list = self.get_runnable_widgets()
                            is_running = False
                            for st in statuses.values():
                                if st.status == 'PENDING':
                                    is_running = True
                                else:
                                    st.get()
                                    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)))
Janez K's avatar
Janez K committed
295
                                        self.widget.save()
Janez K's avatar
Janez K committed
296
297
298
299
300
                            unfinished_list = self.get_runnable_widgets()
                except:
                    raise
            current_iteration = current_iteration+1

dejan's avatar
dejan committed
301
302
303
    def run_cross_validation(self):
        """ Method runs cross_validation. """
        #clear for_input and for_output
304
        #print("run_cross_validation")
dejan's avatar
dejan committed
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
        import random as rand
        fi = self.widgets.filter(type='cv_input')[0]
        fo = self.widgets.filter(type='cv_output')[0]
        outer_output = fo.inputs.all()[0].outer_output
        outer_output.value=[]
        outer_output.save()

        # get all inputs from outer part
        input_list = fi.outputs.all()[0].outer_input.value 
        input_fold = fi.outputs.all()[1].outer_input.value
        input_seed = fi.outputs.all()[2].outer_input.value

        if input_fold != None:
            #check if we have an input
            input_fold = int(fi.outputs.all()[1].outer_input.value)
        else:
            input_fold = 10
        
        if input_seed != None:
            #check if we have an input
            input_seed = int(fi.outputs.all()[2].outer_input.value)
        else:
327
            input_seed = random.randint(0, 10**9)
dejan's avatar
dejan committed
328

329
330
331
332
333
334
335
336
337
338
        # Special case when reading from a DB
        input_type = input_list.__class__.__name__
        context = None
        if input_type == 'DBContext':
            context = input_list
            input_list = context.orng_tables.get(context.target_table, None)

        if not input_list:
            raise Exception('CrossValidation: Empty input list!')

dejan's avatar
dejan committed
339
340
341
342
        progress_total = len(input_list) # for progress bar
        current_iteration = 0

        # create folds
343
344
345

        folds = []
        if hasattr(input_list, "get_items_ref"):
346
            import orange 
347
            # Orange table on input, so we cannot do slices
348
            indices = orange.MakeRandomIndicesCV(input_list, randseed=input_seed, folds=input_fold, stratified=orange.MakeRandomIndices.Stratified)
349
350
351
            for i in range(input_fold):
                output_train = input_list.select(indices, i, negate=1)
                output_test = input_list.select(indices, i)
352
353
                output_train.name = input_list.name
                output_test.name = input_list.name
354
                folds.append((output_train, output_test))
355
        else:
356
357
            rand.seed(input_seed)
            rand.shuffle(input_list)
358
            folds = [input_list[i::input_fold] for i in range(input_fold)]
dejan's avatar
dejan committed
359
360
361
362
363
364
365
366
367
368

        # pass forward the seed
        proper_output = fi.outputs.all()[2] # inner output
        proper_output.value = input_seed
        proper_output.save()

        # this for loop delets all previous results
        for i in fo.inputs.all():
            if not i.parameter:
                if i.connections.count() > 0:
369
370
                    i.value = []
                    i.save()
dejan's avatar
dejan committed
371
372

        for i in range(len(folds)):
373
374
            #import pdb; pdb.set_trace()
            if hasattr(input_list, "get_items_ref"):
Marko Lalovic's avatar
Marko Lalovic committed
375
376
                output_test = folds[i][1]
                output_train = folds[i][0]
377
378
379
            else:
                output_train = folds[:i] + folds[i+1:]
                output_test = folds[i]
380
381
382
383
384
385
386
387
            if input_type == 'DBContext':
                output_train_obj = context.copy()
                output_train_obj.orng_tables[context.target_table] = output_train
                output_test_obj = context.copy()
                output_test_obj.orng_tables[context.target_table] = output_test
                output_train = output_train_obj
                output_test = output_test_obj

dejan's avatar
dejan committed
388
389
390
391
            """ Different parameters on which the widgets are going to be run"""
            fi.unfinish() # resets widgets, (read all widgets.finished=false)
            fo.unfinish() # resets widgets, (read all widgets.finished=false)
            proper_output = fi.outputs.all()[0] # inner output
392
            proper_output.value = output_train
dejan's avatar
dejan committed
393
394
            proper_output.save()
            proper_output = fi.outputs.all()[1] # inner output
395
            proper_output.value = output_test
dejan's avatar
dejan committed
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
            proper_output.save()
            fi.finished=True # set the input widget as finished
            fi.save()
            if not USE_CONCURRENCY or 1==1:
                """ This if statement is always true. """
                unfinished_list = self.get_runnable_widgets()
                try:
                    while len(unfinished_list)>0:
                        for w in unfinished_list:
                            w.run(True) # run the widget
                            total = self.widgets.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()
                except:
                    raise
            current_iteration = current_iteration+1

Janez K's avatar
Janez K committed
415
    def run(self):
Janez K's avatar
Janez K committed
416
        if not USE_CONCURRENCY or not self.widget:
Janez K's avatar
Janez K committed
417
            unfinished_list = self.get_runnable_widgets()
418
            #print unfinished_list
Janez K's avatar
Janez K committed
419
420
421
422
423
424
425
426
427
428
429
430
            try:
                total = self.widgets.count()
                completed = self.widgets.filter(finished=True).count()
                while len(unfinished_list)>0:
                    for w in unfinished_list:
                        w.run(True)
                        #runWidgetAsync.delay(w)
                        completed = self.widgets.filter(finished=True).count()
                        if self.widget:
                            self.widget.progress = (int)(((completed*1.0)/total)*100)
                            self.widget.save()
                    unfinished_list = self.get_runnable_widgets()
431
                    #print unfinished_list
Janez K's avatar
Janez K committed
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
            except:
                raise
        else:
            unfinished_list = self.get_runnable_widgets()
            try:
                statuses = {}
                total = self.widgets.count()
                completed = self.widgets.filter(finished=True).count()
                while len(unfinished_list)>0:
                    for w in unfinished_list:
                        if statuses.has_key(w.pk):
                            if statuses[w.pk].failed():
                                raise Exception(statuses[w.pk].info[0])
                        else:
                            statuses[w.pk]=runWidgetAsync.delay(w)
                        completed = self.widgets.filter(finished=True).count()
                        if self.widget:
                            self.widget.progress = (int)(((completed*1.0)/total)*100)
                            self.widget.save()
                    is_running=True
Janez K's avatar
Janez K committed
452
                    unfinished_list = self.get_runnable_widgets()
Janez K's avatar
Janez K committed
453
454
455
456
457
458
459
460
461
462
463
                    while len(unfinished_list)==0 and is_running:
                        unfinished_list = self.get_runnable_widgets()
                        is_running = False
                        for st in statuses.values():
                            if st.status == 'PENDING':
                                is_running = True
                            else:
                                st.get()
                                completed = self.widgets.filter(finished=True).count()
                                if self.widget:
                                    self.widget.progress = (int)(((completed*1.0)/total)*100)
Janez K's avatar
Janez K committed
464
                                    self.widget.save()
Janez K's avatar
Janez K committed
465
                        time.sleep(1)
Janez K's avatar
Janez K committed
466
                    unfinished_list = self.get_runnable_widgets()
Janez K's avatar
Janez K committed
467
468
469
470
            except:
                raise
    def rename(self,new_name):
        self.name = new_name
Janez K's avatar
Janez K committed
471
472
        self.save()

Janez K's avatar
Janez K committed
473
474
    @models.permalink
    def get_absolute_url(self):
Janez K's avatar
Janez K committed
475
476
        return ('open workflow', [str(self.id)])

Janez K's avatar
Janez K committed
477
478
479
    @models.permalink
    def get_copy_url(self):
        return ('copy workflow', [str(self.id)])
Janez K's avatar
Janez K committed
480

Janez K's avatar
Janez K committed
481
482
483
    @models.permalink
    def get_info_url(self):
        return ('workflow information', [str(self.id)])
Janez K's avatar
Janez K committed
484

485
486
487
488
    @models.permalink
    def get_export_url(self):
        return ('export workflow', [str(self.id)])

Janez K's avatar
Janez K committed
489
490
    def __unicode__(self):
        return unicode(self.name)
Janez K's avatar
Janez K committed
491

Janez K's avatar
Janez K committed
492
    class Meta:
Janez K's avatar
Janez K committed
493
        ordering = ['name']
Janez K's avatar
Janez K committed
494
495

class AbstractWidget(models.Model):
Janez K's avatar
Janez K committed
496
497
    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.')
    action = models.CharField(max_length=200,help_text='Action is the name of a python function that will be called when the widget is executed.')
Janez K's avatar
Janez K committed
498
    wsdl = models.URLField(max_length=200,blank=True,help_text='WSDL and WSDL method are used if the widget is a call of a Web Service. Web Service widgets are usually not entered in the admin panel, but in the application itself by importing a Web Service.')
Janez K's avatar
Janez K committed
499
    wsdl_method = models.CharField(max_length=200,blank=True,default='')
Janez K's avatar
Janez K committed
500
501
502
    description = models.TextField(blank=True,help_text='Description is used for a human readable description of what a widget does. A user will see this when he right clicks the widget and clicks help.')
    category = models.ForeignKey(Category,related_name="widgets",help_text='Category determines to which category this widget belongs. Categories can be nested.')
    visualization_view = models.CharField(max_length=200,blank=True,default='',help_text='Visualization view is (like the action) a python function that is a view that will render a template.')
503
    streaming_visualization_view = models.CharField(max_length=200,blank=True,default='',help_text='Visualization view is (like the action) a python function that is a view that will render a template.')
Janez K's avatar
Janez K committed
504
505
    user = models.ForeignKey(User,blank=True,null=True,related_name="widgets",help_text='If the User field is blank, everyone will see the widget, otherwise just this user. This is mainly used for Web Service imports as they are only visible to users that imported them.')
    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.')
Janez K's avatar
Janez K committed
506
507
    interaction_view = models.CharField(max_length=200,blank=True,default='')
    post_interact_action = models.CharField(max_length=200,blank=True,default='')
Janez K's avatar
Janez K committed
508

Janez K's avatar
Janez K committed
509
    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.')
Janez K's avatar
Janez K committed
510
    treeview_image = ThumbnailField(blank=True,null=True,upload_to="treeview",size=(16,16))
511

Janez K's avatar
Janez K committed
512
    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.')
Janez K's avatar
Janez K committed
513

Janez K's avatar
Janez K committed
514
515
    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.')
Janez K's avatar
Janez K committed
516

Janez K's avatar
Janez K committed
517
    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.')
Janez K's avatar
Janez K committed
518

Janez K's avatar
Janez K committed
519
    uid = models.CharField(max_length=250,blank=True,default='',help_text='UID is set automatically when you export a package with the -u switch.')
Janez K's avatar
Janez K committed
520

Janez K's avatar
Janez K committed
521
    package = models.CharField(max_length=150,blank=True,default='',help_text='Package is the package name. You are encouraged to use packages.')
Janez K's avatar
Janez K committed
522

523
524
    windows_queue = models.BooleanField(default=False,help_text="This is used for Matjaz Jursic's widgets.")

Janez K's avatar
Janez K committed
525
526
    class Meta:
        ordering = ('order','name',)
527

Janez K's avatar
Janez K committed
528
529
    def set_uid(self,commit=False):
        import uuid
Janez K's avatar
Janez K committed
530
        self.uid = str(uuid.uuid4())
Janez K's avatar
Janez K committed
531
532
533
        if commit:
            self.save()
        for i in self.inputs.all():
Janez K's avatar
Janez K committed
534
            i.uid = str(uuid.uuid4())
Janez K's avatar
Janez K committed
535
536
            if commit:
                i.save()
bogdan's avatar
bogdan committed
537
            for option in i.options.all():
Janez K's avatar
Janez K committed
538
                option.uid = str(uuid.uuid4())
539
540
                if commit:
                    option.save()
Janez K's avatar
Janez K committed
541
        for o in self.outputs.all():
Janez K's avatar
Janez K committed
542
            o.uid = str(uuid.uuid4())
Janez K's avatar
Janez K committed
543
544
545
            if commit:
                o.save()

Janez K's avatar
Janez K committed
546
547
548
    def update_uid(self):
        import uuid
        if self.uid == '' or self.uid is None:
Janez K's avatar
bugfix  
Janez K committed
549
            self.uid = str(uuid.uuid4())
Janez K's avatar
Janez K committed
550
551
            self.save()
        for i in self.inputs.filter(uid=''):
Janez K's avatar
bugfix  
Janez K committed
552
            i.uid = str(uuid.uuid4())
Janez K's avatar
Janez K committed
553
554
            i.save()
            for option in i.options.filter(uid=''):
Janez K's avatar
bugfix  
Janez K committed
555
                option.uid = str(uuid.uuid4())
Janez K's avatar
Janez K committed
556
557
                option.save()
        for o in self.outputs.filter(uid=''):
Janez K's avatar
bugfix  
Janez K committed
558
            o.uid = str(uuid.uuid4())
Janez K's avatar
Janez K committed
559
560
561
            o.save()   
        self.category.update_uid()     

Janez K's avatar
Janez K committed
562
563
564
565
566
567
568
    def __unicode__(self):
        return unicode(self.name)

class AbstractInput(models.Model):
    name = models.CharField(max_length=200)
    short_name = models.CharField(max_length=3)
    description = models.TextField(blank=True)
Janez K's avatar
Janez K committed
569
    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.')
Janez K's avatar
Janez K committed
570
571
572
    widget = models.ForeignKey(AbstractWidget,related_name="inputs")
    required = models.BooleanField()
    parameter = models.BooleanField()
Janez K's avatar
Janez K committed
573
    multi = models.BooleanField(default=False,help_text='Inputs with this flag set will behave like this: whenever a connection is added to this input another input will be created on the fly that accepts the same data. In the action function, this will be represented as a list.')
Janez K's avatar
Janez K committed
574
575
576
    default = models.TextField(blank=True)
    PARAMETER_CHOICES = (
        ('text','Single line'),
577
        ('password', 'Password'),
Janez K's avatar
Janez K committed
578
579
580
581
582
583
        ('textarea','Multi line text'),
        ('select', 'Select box'),
        ('checkbox', 'Checkbox'),
        ('file', 'File'),
    )
    parameter_type = models.CharField(max_length=50,choices=PARAMETER_CHOICES,blank=True,null=True)
Janez K's avatar
Janez K committed
584

Janez K's avatar
Janez K committed
585
    order = models.PositiveIntegerField(default=1)
Janez K's avatar
Janez K committed
586
587

    uid = models.CharField(max_length=250,blank=True,default='')
Janez K's avatar
Janez K committed
588

Janez K's avatar
Janez K committed
589
590
    def __unicode__(self):
        return unicode(self.name)
Janez K's avatar
Janez K committed
591

Janez K's avatar
Janez K committed
592
593
    class Meta:
        ordering = ('order',)
Janez K's avatar
Janez K committed
594

Janez K's avatar
Janez K committed
595
596
597
598
class AbstractOption(models.Model):
    abstract_input = models.ForeignKey(AbstractInput,related_name="options")
    name = models.CharField(max_length=200)
    value = models.TextField(blank=True)
Janez K's avatar
Janez K committed
599
600
601

    uid = models.CharField(max_length=250,blank=True,default='')

Janez K's avatar
Janez K committed
602
603
    def __unicode__(self):
        return unicode(self.name)
Janez K's avatar
Janez K committed
604

Janez K's avatar
Janez K committed
605
    class Meta:
Janez K's avatar
Janez K committed
606
        ordering = ['name']
Janez K's avatar
Janez K committed
607
608
609
610
611

class AbstractOutput(models.Model):
    name = models.CharField(max_length=200)
    short_name = models.CharField(max_length=3)
    description = models.TextField(blank=True)
Janez K's avatar
Janez K committed
612
    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.')
Janez K's avatar
Janez K committed
613
    widget = models.ForeignKey(AbstractWidget,related_name="outputs")
Janez K's avatar
Janez K committed
614

Janez K's avatar
Janez K committed
615
    order = models.PositiveIntegerField(default=1)
Janez K's avatar
Janez K committed
616
617

    uid = models.CharField(max_length=250,blank=True,default='')
Janez K's avatar
Janez K committed
618

Janez K's avatar
Janez K committed
619
    class Meta:
Janez K's avatar
Janez K committed
620
621
        ordering = ('order',)

Janez K's avatar
Janez K committed
622
623
624
625
    def __unicode__(self):
        return unicode(self.name)

class Widget(models.Model):
dejan's avatar
dejan committed
626
627
    """ Widget """
    # django relationship (ForeignKey), each widget is related to a single workflow
Janez K's avatar
Janez K committed
628
    workflow = models.ForeignKey(Workflow,related_name="widgets")
dejan's avatar
dejan committed
629
630
631
    x = models.IntegerField() # a field
    y = models.IntegerField() # a field
    name = models.CharField(max_length=200) # a field
Janez K's avatar
Janez K committed
632
    abstract_widget = models.ForeignKey(AbstractWidget,related_name="instances",blank=True,null=True)
dejan's avatar
dejan committed
633
634
635
636
637
    finished = models.BooleanField(default=False) # a field
    error = models.BooleanField(default=False) # a field
    running = models.BooleanField(default=False) # a field
    interaction_waiting = models.BooleanField(default=False) # a field
    """ type of widgets """
Janez K's avatar
Janez K committed
638
639
640
641
642
    WIDGET_CHOICES = (
        ('regular','Regular widget'),
        ('subprocess','Subprocess widget'),
        ('input', 'Input widget'),
        ('output', 'Output widget'),
643
644
        ('for_input', 'For input'),
        ('for_output', 'For output'),
Janez K's avatar
Janez K committed
645
646
        ('cv_input', 'Cross Validation input'),
        ('cv_output', 'Cross Validation output'),
Janez K's avatar
Janez K committed
647
648
        ('cv_input2', 'Cross Validation input 2'),
        ('cv_input3', 'Cross Validation input 3'),
Janez K's avatar
Janez K committed
649
650
    )
    type = models.CharField(max_length=50,choices=WIDGET_CHOICES,default='regular')
Janez K's avatar
Janez K committed
651

Janez K's avatar
Janez K committed
652
    progress = models.IntegerField(default=0)
Janez K's avatar
Janez K committed
653

654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
    def import_from_json(self,json_data,input_conversion,output_conversion):
        self.x = json_data['x']
        self.y = json_data['y']
        self.name = json_data['name']
        if json_data['abstract_widget']:
            aw = AbstractWidget.objects.get(uid=json_data['abstract_widget'],package=json_data['abstract_widget_package'])
            self.abstract_widget = aw
        self.type = json_data['type']
        self.save()
        for i in json_data['inputs']:
            new_i = Input()
            new_i.widget = self
            new_i.import_from_json(i,input_conversion,output_conversion)
        for o in json_data['outputs']:
            new_o = Output()
            new_o.widget = self
            new_o.import_from_json(o,input_conversion,output_conversion)


673
674
    def export(self):
        d = {}
675
676
677
        if self.workflow_link_exists:
            d['workflow']=self.workflow_link_data.export()
        else:
678
679
680
681
682
683
684
            d['workflow']=None
        d['x']=self.x
        d['y']=self.y
        d['name']=self.name
        if self.abstract_widget:
            if self.abstract_widget.uid:
                d['abstract_widget']=self.abstract_widget.uid
685
                d['abstract_widget_package']=self.abstract_widget.package
686
687
688
689
            else:
                raise Exception("Cannot export a widget that doesn't have a UID. ("+str(self.name)+")")
        else:
            d['abstract_widget']=None
690
691
692
693
        #d['finished']=self.finished
        #d['error']=self.error
        #d['running']=self.running
        #d['interaction_waiting']=self.interaction_waiting
694
        d['type']=self.type
695
        #d['progress']=self.progress
696
697
        d['inputs']=[]
        d['outputs']=[]
698
        for i in self.inputs_all:
699
            d['inputs'].append(i.export())
700
        for o in self.outputs_all:
701
702
703
            d['outputs'].append(o.export())
        return d

Janez K's avatar
Janez K committed
704
705
706
707
708
709
    def is_visualization(self):
        try:
            if self.abstract_widget.visualization_view != '':
                return True
        except:
            return False
Janez K's avatar
Janez K committed
710

Janez K's avatar
Janez K committed
711
712
713
714
715
716
    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
Janez K's avatar
Janez K committed
717

Janez K's avatar
Janez K committed
718
    def unfinish(self):
Janez K's avatar
Janez K committed
719
        self.reset_descendants()
Janez K's avatar
Janez K committed
720

Janez K's avatar
Janez K committed
721
722
723
724
725
726
727
728
    def subunfinish(self):
        if self.type == 'subprocess':
            for w in self.workflow_link.widgets.all():
                w.finished=False
                w.error = False
                w.save()
                if w.type=='subprocess':
                    w.subunfinish()
Janez K's avatar
Janez K committed
729

Janez K's avatar
Janez K committed
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
    def rename(self,new_name):
        self.name = new_name
        self.save()
        if self.type=='input':
            inp = self.outputs.all()[0]
            inp.short_name = self.name[:3]
            inp.name = self.name
            inp.save()
            inp.outer_input.name = self.name
            inp.outer_input.short_name = self.name[:3]
            inp.outer_input.save()
        if self.type=='output':
            inp = self.inputs.all()[0]
            inp.short_name = self.name[:3]
            inp.name = self.name
            inp.save()
            inp.outer_output.name = self.name
            inp.outer_output.short_name = self.name[:3]
Janez K's avatar
Janez K committed
748
            inp.outer_output.save()
Janez K's avatar
Janez K committed
749
750
751
752
753
754
        try:
            w_link = self.workflow_link
            w_link.name=new_name
            w_link.save()
        except Workflow.DoesNotExist:
            pass
Janez K's avatar
Janez K committed
755

Janez K's avatar
Janez K committed
756
    def run(self,offline):
dejan's avatar
dejan committed
757
        """ This is only a hack, to make this work on windows """
Janez K's avatar
bugfix  
Janez K committed
758
        try: 
759
            if self.abstract_widget.windows_queue and settings.USE_WINDOWS_QUEUE:
Janez K's avatar
bugfix  
Janez K committed
760
761
762
763
764
                t = runWidget.apply_async([self,offline],queue="windows")
                t.wait()
            else:
                self.proper_run(offline)
        except AttributeError:
Janez K's avatar
fix  
Janez K committed
765
766
767
            self.proper_run(offline)

    def proper_run(self,offline):
dejan's avatar
dejan committed
768
        """ This is the real start. """
769
        #print("proper_run_widget")
Janez K's avatar
Janez K committed
770
        if not self.ready_to_run():
Janez K's avatar
Janez K committed
771
            raise WidgetException("The prerequisites for running this widget have not been met.")
Janez K's avatar
Janez K committed
772
773
774
        self.running=True
        self.save()
        if self.type == 'regular' or self.type == 'subprocess':
dejan's avatar
dejan committed
775
            """ if this is a subprocess or a regular widget than true."""
Janez K's avatar
Janez K committed
776
            if not self.abstract_widget is None:
777
                """if this is an abstract widget than true we save the widget function in a variable """
Janez K's avatar
Janez K committed
778
779
780
781
                function_to_call = getattr(workflows.library,self.abstract_widget.action)
            input_dict = {}
            outputs = {}
            for i in self.inputs.all():
dejan's avatar
dejan committed
782
                """ we walk through all the inputs """
Janez K's avatar
Janez K committed
783
784
                #gremo pogledat ce obstaja povezava in ce obstaja gremo value prebrat iz outputa
                if not i.parameter:
dejan's avatar
dejan committed
785
                    """ if there is a connection than true and read the output value """
Janez K's avatar
Janez K committed
786
787
788
789
790
791
792
793
794
795
796
797
798
                    if i.connections.count() > 0:
                        i.value = i.connections.all()[0].output.value
                        i.save()
                    else:
                        i.value = None
                        i.save()
                if i.multi_id == 0:
                    input_dict[i.variable]=i.value
                else:
                    if not i.variable in input_dict:
                        input_dict[i.variable]=[]
                    if not i.value==None:
                        input_dict[i.variable].append(i.value)
Janez K's avatar
Janez K committed
799
            start = time.time()
Janez K's avatar
Janez K committed
800
801
            try:
                if not self.abstract_widget is None:
dejan's avatar
dejan committed
802
803
                    """ again, if this objects is an abstract widget than true and check certain parameters,
                    else check if is_for_loop"""
Janez K's avatar
Janez K committed
804
                    if self.abstract_widget.wsdl != '':
dejan's avatar
dejan committed
805
                        """ if abstrac widget is a web service """
Janez K's avatar
Janez K committed
806
807
808
                        input_dict['wsdl']=self.abstract_widget.wsdl
                        input_dict['wsdl_method']=self.abstract_widget.wsdl_method
                    if self.abstract_widget.has_progress_bar:
dejan's avatar
dejan committed
809
                        """ if abstrac widget has a progress bar """
Janez K's avatar
fix  
Janez K committed
810
                        outputs = function_to_call(input_dict,self)
Janez K's avatar
Janez K committed
811
                    elif self.abstract_widget.is_streaming:
dejan's avatar
dejan committed
812
                        """ if abstrac widget is a stream """
Janez K's avatar
fix  
Janez K committed
813
                        outputs = function_to_call(input_dict,self,None)
Janez K's avatar
Janez K committed
814
                    else:
dejan's avatar
dejan committed
815
                        """ else run abstract widget function """
Janez K's avatar
fix  
Janez K committed
816
                        outputs = function_to_call(input_dict)
Janez K's avatar
Janez K committed
817
                else:
Janez K's avatar
Janez K committed
818
819
                    Input.objects.filter(widget__workflow=self.workflow_link,parameter=False).update(value=None)
                    Output.objects.filter(widget__workflow=self.workflow_link).update(value=None)
820
821
822
                    wr = WidgetRunner(self,workflow_runner=WorkflowRunner(self.workflow,clean=False),standalone=True)
                    wr.run()
                    return
Janez K's avatar
Janez K committed
823
824
825
826
827
828
            except:
                self.error=True
                self.running=False
                self.finished=False
                self.save()
                raise
Janez K's avatar
Janez K committed
829
830
            elapsed = (time.time()-start)
            outputs['clowdflows_elapsed']=elapsed
Janez K's avatar
Janez K committed
831
            for o in self.outputs.all():
dejan's avatar
dejan committed
832
                """ we walk through all the outputs """
Janez K's avatar
Janez K committed
833
                if not self.abstract_widget is None:
dejan's avatar
dejan committed
834
835
                    """ if this object is an abstract widget than true and save output
                    else look for outputs in workflow """
Janez K's avatar
Janez K committed
836
837
838
839
                    try:
                        o.value = outputs[o.variable]
                    except:
                        pass
Janez K's avatar
Janez K committed
840
841
842
843
844
845
846
                    o.save()
                else:
                    #gremo v outpute pogledat
                    if not self.workflow_link.is_for_loop():
                        o.value = o.inner_input.value
                        o.save()
            if self.abstract_widget is None:
dejan's avatar
dejan committed
847
                """ if object is widget than true and configure parameters """
Janez K's avatar
Janez K committed
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
                self.finished=True
                self.running=False
                self.error=False
                self.save()
            else:
                if not self.abstract_widget.interactive or offline:
                    self.finished=True
                    self.running=False
                    self.error=False
                    self.save()
            cons = Connection.objects.filter(output__widget=self)
            for c in cons:
                c.input.widget.unfinish()
            return outputs
        elif self.type == 'for_input':
dejan's avatar
dejan committed
863
864
            """ if object is an input widget for for loop than read all input values and finish """
            #print("for_input")
Janez K's avatar
Janez K committed
865
866
            for o in self.outputs.all():
                o.value=o.outer_input.value
dejan's avatar
dejan committed
867
                #print(o.outer_input.value)
Janez K's avatar
Janez K committed
868
869
870
871
872
873
                o.save()
            self.finished=True
            self.running=False
            self.error=False
            self.save()
        elif self.type == 'for_output':
dejan's avatar
dejan committed
874
875
876
            """ if object is an output widget for for loop, then read output values and 
            configure parameters"""
            #print("for_output")
Janez K's avatar
Janez K committed
877
878
            for i in self.inputs.all():
                if not i.parameter:
dejan's avatar
dejan committed
879
                    """ if there is a connection than true and read the output value """
Janez K's avatar
Janez K committed
880
881
882
883
884
885
886
887
888
889
                    if i.connections.count() > 0:
                        i.value = i.connections.all()[0].output.value
                        i.save()
                        i.outer_output.value.append(i.value)
                        i.outer_output.save()
                        self.finished=True
            self.finished=True
            self.running=False
            self.error=False
            self.save()
dejan's avatar
dejan committed
890
891
892
893
894
895
896
897
898
899
900
901
902
903
        elif self.type == 'cv_input':
            """ if object is an input widget for cross validation 
            than read all input values and finish """
            for o in self.outputs.all():
                #print('cv_input')
                o.value=o.outer_input.value
                o.save()
            self.finished=True
            self.running=False
            self.error=False
            self.save()
        elif self.type == 'cv_output':
            """ if object is an output widget for cross validation, 
            then read output values and configure parameters"""
904
            print "smo v cv_output"
dejan's avatar
dejan committed
905
906
907
908
909
            for i in self.inputs.all():
                if not i.parameter:
                    """ if there is a connection than true and read the output value """
                    if i.connections.count() > 0:
                        if i.value is None:
910
                            print "1"
dejan's avatar
dejan committed
911
912
                            i.value = [i.connections.all()[0].output.value]
                        else:
913
                            print "2"
dejan's avatar
dejan committed
914
                            i.value = [i.connections.all()[0].output.value] + i.value
915
                            print i.value
dejan's avatar
dejan committed
916
917
                        #print i.value
                        i.save()
918
919
920
                        print "----"
                        print i.outer_output.value
                        print "----"
dejan's avatar
dejan committed
921
922
923
924
925
926
927
                        i.outer_output.value.append(i.value)
                        i.outer_output.save()
                        self.finished=True
            self.finished=True
            self.running=False
            self.error=False
            self.save()
Janez K's avatar
Janez K committed
928
        elif self.type == 'input':
dejan's avatar
dejan committed
929
            """ if object is an input widget for for loop than read all input values and finish """
Janez K's avatar
Janez K committed
930
931
932
933
934
935
936
937
            for o in self.outputs.all():
                o.value=o.outer_input.value
                o.save()
            self.finished=True
            self.running=False
            self.error=False
            self.save()
        elif self.type == 'output':
dejan's avatar
dejan committed
938
939
            """ if object is an output widget, then read output values and 
            configure parameters"""
Janez K's avatar
Janez K committed
940
941
            for i in self.inputs.all():
                if not i.parameter:
dejan's avatar
dejan committed
942
                    """ if there is a connection than true and read the output value """
Janez K's avatar
Janez K committed
943
944
945
946
947
948
                    if i.connections.count() > 0:
                        i.value = i.connections.all()[0].output.value
                        i.save()
                        i.outer_output.value = i.value
                        i.outer_output.save()
                        self.finished=True
Janez K's avatar
Janez K committed
949
            self.finished=True
Janez K's avatar
Janez K committed
950
951
            self.running=False
            self.error=False
952
            self.save()
Janez K's avatar
Janez K committed
953
        return None
Janez K's avatar
Janez K committed
954

955
    def reset(self,offline):
Janez K's avatar
Janez K committed
956
957
958
959
960
961
962
        #for i in self.inputs.all():
        #    if not i.parameter:
        #        i.value = None
        #        i.save()
        #for i in self.outputs.all():
        #    i.value = None
        #    i.save()
963
964
965
966
        self.finished = False
        self.error = False
        self.running = False
        self.save()
Janez K's avatar
Janez K committed
967
968
        if self.type == 'subprocess':
            self.subunfinish()
969

Janez K's avatar
Janez K committed
970
    def reset_descendants(self):
dejan's avatar
dejan committed
971
        """ Method resets all the widget connections/descendants. """
Janez K's avatar
Janez K committed
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
        pairs = []
        for c in self.workflow.connections.select_related("output","input").defer("output__value","input__value").all():
            if not (c.output.widget_id,c.input.widget_id) in pairs:
                pairs.append((c.output.widget_id,c.input.widget_id))
        next = {}                
        for p in pairs:
            if not next.has_key(p[0]):
                next[p[0]]=set()
            next[p[0]].add(p[1])
        widgets_that_need_reset = set([self.pk,])
        current_widgets_that_need_reset = set([self.pk,])
        while len(current_widgets_that_need_reset)>0:
            new_widgets_that_need_reset = set()
            for w_id in current_widgets_that_need_reset:
                try:
                    for p in next.get(w_id):
                        new_widgets_that_need_reset.add(p)
                        widgets_that_need_reset.add(p)
                except:
                    pass
            current_widgets_that_need_reset = new_widgets_that_need_reset
        Widget.objects.filter(id__in=widgets_that_need_reset).update(finished=False,error=False,running=False)
        subprocesses = Widget.objects.filter(id__in=widgets_that_need_reset,type='subprocess')
        for w in subprocesses:
            w.subunfinish()
        return widgets_that_need_reset

    def reset_descendants_slow(self):
Janez K's avatar
Janez K committed
1000
        #find all descendants and reset them as well
Janez K's avatar
Janez K committed
1001
        widgets = list(self.workflow.widgets.prefetch_related('inputs','outputs','inputs__connections','outputs__connections','outputs__connections__input','inputs__connections__output'))
Janez K's avatar
Janez K committed
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
        widgets_dict = {}
        widgets_that_need_reset = set([self.pk,])
        current_widgets_that_need_reset = set([self.pk,])
        for w in widgets:
            widgets_dict[w.pk]=w
        while len(current_widgets_that_need_reset)>0:
            new_widgets_that_need_reset = set()
            for w_id in current_widgets_that_need_reset:
                for o in widgets_dict[w_id].outputs.all():
                    for c in o.connections.all():
                        new_widgets_that_need_reset.add(c.input.widget_id)
                        widgets_that_need_reset.add(c.input.widget_id)
            current_widgets_that_need_reset = new_widgets_that_need_reset
Janez K's avatar
Janez K committed
1015
        Widget.objects.filter(id__in=widgets_that_need_reset).update(finished=False,error=False,running=False)
Janez K's avatar
Janez K committed
1016
        for w in widgets_that_need_reset:
Janez K's avatar
Janez K committed
1017
1018
1019
            if widgets_dict[w].type == 'subprocess':
                widgets_dict[w].subunfinish()
        #    widgets_dict[w].reset(False)
Janez K's avatar
Janez K committed
1020
1021
        return widgets_that_need_reset

Janez K's avatar
Janez K committed
1022
1023
    def run_post(self,request):
        if not self.ready_to_run():
Janez K's avatar
Janez K committed
1024
            raise WidgetException("The prerequisites for running this widget have not been met.")
Janez K's avatar
Janez K committed
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
        self.running=True
        self.save()
        function_to_call = getattr(workflows.library,self.abstract_widget.post_interact_action)
        input_dict = {}
        outputs = {}
        output_dict = {}
        for o in self.outputs.all():
            output_dict[o.variable]=o.value
        for i in self.inputs.all():
            #gremo pogledat ce obstaja povezava in ce obstaja gremo value prebrat iz outputa
            if not i.parameter:
                if i.connections.count() > 0:
                    i.value = i.connections.all()[0].output.value
                    i.save()
                else:
                    i.value = None
                    i.save()
            if i.multi_id == 0:
                input_dict[i.variable]=i.value
            else:
                if not i.variable in input_dict:
                    input_dict[i.variable]=[]
                if not i.value==None:
                    input_dict[i.variable].append(i.value)
        try:
            if not self.abstract_widget is None:
1051
                if self.abstract_widget.windows_queue and settings.USE_WINDOWS_QUEUE:
Janez K's avatar
Janez K committed
1052
                    t = executeWidgetPostInteract.apply_async([self,input_dict,output_dict,request],queue="windows")
1053
1054
                    outputs = t.wait()
                else:
Janez K's avatar
Janez K committed
1055
                    outputs = executeWidgetPostInteract(self,input_dict,output_dict,request)