Beispiel #1
0
class HumanTask(AbstractTask):
    with param_group('Assigned'):
        candidats = ComputedParam().ui(editor='choices_for', editor_options={'target_param':'user'})
        user = CaseParam().ui(editor='node_ref', editor_options={'root_name':'resources'})
        
    _status_manager = Child(HumanTaskStatus).affects(AbstractTask.status)
    
    def _configure(self):
        super(HumanTask, self)._configure()
        self.candidats.add_source(self.parent().user_groups)
    
    def compute(self, param_name):
        if param_name == 'candidats':
            if not self.candidats.has_source():
                self.candidats.set([])
            else:
                uids = self.candidats.get_from_sources()
                if uids is None:
                    self.candidats.set([])
                else:
                    nodes = [ self.flow().get(uid) for uid in uids ]
                    groups = [ n for n in nodes if n.has_param('users') ]
                    users = [ n.uid() for n in nodes if n.has_param('login') ]
                    [ users.extend(group.users.get() or []) for group in groups ]
                    self.candidats.set(sorted(set(users)))
        else:
            super(HumanTask, self).compute(param_name)
Beispiel #2
0
class AbstractTask(FileNode):
    ICON_NAME = 'task'

    with param_group('Task'):
        status = CaseParam('NYS')
        status_choices = ComputedParam().ui(editor='choices_for', editor_options={'target_param':'status'})
        progress = ComputedParam().ui(editor='percent')
        up_to_date = ComputedParam().ui('Is up to date?', editor='bool')

    #_status_manager = Child(SpecificStatusManager).affects(status) subclasses must define this!
                
    def param_touched(self, param_name):
        if param_name in ('status'):
            self.status_choices.touch()
            self.progress.touch()
            return 
        
        super(AbstractTask, self).param_touched(param_name)

    def _is_up_to_date(self):
        prev_mtime = self.prev_mtime.get()
        if prev_mtime is None:
            return self.exists.get()
        else:
            mtime = self.mtime.get()
            if not mtime:
                return False
            else:
                delta = 60 # allow 60 second of delay.
                return self.mtime.get()+delta>self.prev_mtime.get()

    def compute(self, param_name):
        if param_name == 'progress':
            self.progress.set(
                self._status_manager.get_progress(self.status.get())
            )
             
        elif param_name == 'status_choices':
            self.status_choices.set(
                self._status_manager.get_choices(self.status.get())
            )

        elif param_name == 'up_to_date':
            self.up_to_date.set(self._is_up_to_date())

        else:
            super(AbstractTask, self).compute(param_name)
Beispiel #3
0
class NamedNode(Node):
    with param_group('_Naming', group_index=1000):
        _naming = Param()

    _namer = Child(NamingNode)

    def set_namer_config(self, **config):
        self._namer.config.set(config)
    
    def add_namer_config(self, **config):
        cfg = self._namer.config.get() or {}
        cfg.update(config)
        self._namer.config.set(cfg)
        
    def set_namer_from_id(self, key=None):
        key = key or self.__class__.__name__
        self._namer.config.set({key:self.node_id})
Beispiel #4
0
class TaskGroup(NamedNode):
    ICON_NAME = 'action'

    with param_group('Tasks'):
        tasks_statuses = Param({}, sources_as_dict=True).ui(editor='status_sumary')
        tasks_progresses = Param({}, sources_as_dict=True)
        status = ComputedParam()
        progress = ComputedParam().ui(editor='percent')

    _status_manager = Child(TaskGroupStatus) # NB: this is a status summary, it does not affect a param 
    notes = Child(NoteThread)

    def _configure(self):
        super(TaskGroup, self)._configure()
        for _, child in self.iterchildren():
            if child.has_param('status'):
                self.tasks_statuses.add_source(child.status)
            if child.has_param('progress'):
                self.tasks_progresses.add_source(child.progress)

    def param_touched(self, param_name):
        if param_name == 'tasks_progresses':
            self.progress.touch()
            
        elif param_name == 'progress':
            self.status.touch()
            
    def compute(self, param_name):
        if param_name == 'progress':
            self.progress.set(
                self._status_manager.get_average_progress(
                    (self.tasks_progresses.get() or {}).values()
                )
            )
                
        if param_name == 'status':
            self.status.set(
                self._status_manager.get_status(
                    self.progress.get()
                )
            )
Beispiel #5
0
class Casting(Cast):
    '''
    A Casting node is used to build up a set of interesting nodes.
    
    It does so by storing a list of Cast node uids and generating
    a list of nodes.
    Each Cast node referenced knows in which Casting it is used
    and provide the node it casts.
    
    As a Casting node is also a Cast node, one can cast a casting
    in another one. This gives the ability to build complexe and
    hierarchical node groups.
    
    '''
    with param_group('Casting', 0):
        casted_uids = CaseParam().ui(editor='node_refs')
        casted = ComputedParam()
        clean_up = TriggerParam()

    def _configure(self):
        super(Casting, self)._configure()
        self._last_strict_casted = None

    def get_casted(self):
        return self.casted.get()

    def add_cast(self, cast):
        cast_uid = cast.uid()
        casted_uids = self.casted_uids.get() or []
        if cast_uid not in casted_uids:
            self.casted_uids.set(casted_uids + [cast_uid])

    def remove_cast(self, cast):
        cast_uid = cast.uid()
        casted_uids = self.casted_uids.get() or []
        try:
            casted_uids.remove(cast_uid)
        except ValueError:
            pass
        else:
            self.casted_uids.set(casted_uids)

    def param_touched(self, param_name):
        if param_name == 'casted_uids':
            self.casted.touch()
        else:
            super(Casting, self).param_touched(param_name)

    def compute(self, param_name):
        if param_name == 'casted':
            flow = self.flow()
            casted = []
            strict_casted = []
            for uid in self.casted_uids.get() or []:
                node = flow.get(uid)
                strict_casted.append(node)
                try:
                    casted.extend(node.get_casted())
                except AttributeError:
                    raise ValueError(
                        'The uid %r is not castable. Please add only Cast and Casting nodes'
                        % (uid, ))

            # Removes disconnected:
            for n in self._last_strict_casted or []:
                if n not in strict_casted:
                    n.remove_casting(self)

            # Add new connected:
            for n in strict_casted:
                if n not in (self._last_strict_casted or []):
                    n.add_casting(self)

            self.casted.set(casted)
            self._last_strict_casted = strict_casted

            # Touch the casting using me:
            castings = self.castings.get()
            print '##################', castings
            for casting in castings:
                casting.casted.touch()

        else:
            super(Casting, self).compute(param_name)

    def trigger(self, param_name):
        if param_name == 'clean_up':
            flow = self.flow()
            valid_uids = []
            for uid in self.casted_uids.get() or []:
                node = flow.get(uid)
                try:
                    node.get_casted
                except AttributeError:
                    continue
                else:
                    valid_uids.append(uid)

            self.casted_uids.set(sorted(valid_uids))

        else:
            super(Cast, self).trigger(param_name)
Beispiel #6
0
class Cast(Node):
    '''
    A Cast node is used by the Casting nodes to build up a set
    of interesting nodes.
    
    The Cast node must be a Child of the interesting node.
    '''
    with param_group('Casted By'):
        casting_uids = CaseParam().ui(editor='node_refs')
        castings = ComputedParam()

    def _configure(self):
        super(Cast, self)._configure()
        self._last_castings = None

    def get_casted(self):
        return [self.parent()]

    def add_casting(self, casting):
        casting_uid = casting.uid()
        casting_uids = self.casting_uids.get() or []
        if casting_uid not in casting_uids:
            self.casting_uids.set(casting_uids + [casting_uid])

    def remove_casting(self, casting):
        casting_uid = casting.uid()
        casting_uids = self.casting_uids.get() or []
        try:
            casting_uids.remove(casting_uid)
        except ValueError:
            pass
        else:
            self.casting_uids.set(casting_uids)

    def param_touched(self, param_name):
        if param_name == 'casting_uids':
            self.castings.touch()
        else:
            super(Cast, self).param_touched(param_name)

    def compute(self, param_name):
        if param_name == 'castings':
            flow = self.flow()
            castings = []
            for uid in self.casting_uids.get() or []:
                try:
                    n = flow.get(uid)
                except:
                    continue
                castings.append(n)

            # Removes disconnected:
            for n in self._last_castings or []:
                if n not in castings:
                    n.remove_cast(self)

            # Add new connected:
            for n in castings:
                if n not in (self._last_castings or []):
                    n.add_cast(self)

            self.castings.set(castings)
            self._last_castings = list(castings)
        else:
            super(Cast, self).compute(param_name)
Beispiel #7
0
class Scheduled(TaskGroup):
    ICON_NAME = 'scheduled'

    AFTER_PREV_END = 'After Previous End'
    AFTER_PREV_START = 'After Previous Start'
    FIXED_START = 'Fixed Start Date'
    SCHEDULE_MODES = (
        AFTER_PREV_END,
        AFTER_PREV_START,
        FIXED_START,
    )

    with param_group('Planning'):
        schedule_mode = CaseParam().ui(
            editor='choice', editor_options={'choices': SCHEDULE_MODES})
        fixed_start_date = CaseParam().ui(editor='date')
        start_offset = CaseParam().ui(editor='int')
        start_date = ComputedParam().ui(editor='date')
        work_days = CaseParam().ui(editor='int')
        end_date = ComputedParam().ui(editor='date')

    with param_group('Planning Dependencies'):
        dep_start_dates = Param().ui(editor='date')
        dep_end_dates = Param().ui(editor='date')

    with param_group('Assigned'):
        manager = CaseParam().ui(editor='node_ref',
                                 editor_options={'root_name': 'resources'})
        lead = CaseParam().ui(editor='node_ref',
                              editor_options={'root_name': 'resources'})
        user_groups = CaseParam().ui(editor='node_refs',
                                     editor_options={'root_name': 'resources'})

    def add_dependency(self, scheduled):
        self.dep_start_dates.add_source(scheduled.start_date)
        self.dep_end_dates.add_source(scheduled.end_date)

    def param_touched(self, param_name):
        if param_name in ('schedule_mode', 'fixed_start_date', 'start_offset',
                          'dep_start_dates', 'dep_end_dates'):
            self.start_date.touch()
        elif param_name in ('start_date', 'work_days'):
            self.end_date.touch()
        else:
            return super(Scheduled, self).param_touched(param_name)

    def compute(self, param_name):
        if param_name == 'start_date':
            mode = self.schedule_mode.get()

            if mode == self.FIXED_START:
                self.start_date.set(
                    self.fixed_start_date.get() +
                    datetime.timedelta(self.start_offset.get() or 0))

            elif not mode or mode == self.AFTER_PREV_END:
                prev_end = self.dep_end_dates.get()
                if prev_end is None:
                    raise Exception(
                        'Cannot use schedule mode %r without a dependency.' %
                        (mode, ))
                self.start_date.set(
                    prev_end +
                    datetime.timedelta(self.start_offset.get() or 0))

            elif mode == self.AFTER_PREV_START:
                prev_start = self.dep_start_dates.get()
                if prev_start is None:
                    raise Exception(
                        'Cannot use schedule mode %r without a dependency.' %
                        (mode, ))
                self.start_date.set(
                    prev_start +
                    datetime.timedelta(self.start_offset.get() or 0))

            else:
                raise Exception('Unknown Schedule Mode %r' % (mode, ))

        elif param_name == 'end_date':
            start = self.start_date.get()
            if start is None:
                raise Exception('Cannot find end date without start date')
            self.end_date.set(start +
                              datetime.timedelta(self.work_days.get() or 0))

        else:
            return super(Scheduled, self).compute(param_name)
Beispiel #8
0
class FileNode(NamedNode):
    
    thumbnail = ComputedParam().tag('preview').ui(editor='thumbnail', group_index=-1, index=-1)
    
    with param_group('Previous File'):
        prev_filename = Param().tag('filename')
        prev_mtime = Param().ui(editor='timestamp')
        
    with param_group('File'):
        filename = ComputedParam().tag('filename')
        exists = ComputedParam()
        mtime = ComputedParam().ui(editor='timestamp')
        
    def set_prev_file(self, file_node):
        self.prev_filename.disconnect()
        self.prev_filename.add_source(file_node.filename)
        
        self.prev_mtime.disconnect()
        self.prev_mtime.add_source(file_node.mtime)

    browse = Proc(BrowseCmdNode)
    
    def _configure(self):
        super(FileNode, self)._configure()
        self.browse.filename.add_source(self.filename)
        self.set_ticked()

    def tick(self):
        '''
        Checks for mtime modifications and update it
        if needed.
        '''
        # Skip tick when it might come from a touch of the params used here:
        # (it could lead to a loop)
        if self.exists.is_dirty() or self.mtime.is_dirty() or self.filename.is_dirty():
            return
        
        # Check file existence first
        filename = self.filename.get()
        if not os.path.exists(filename):
            if self.exists.get():
                self.exists.touch()
            return
        elif not self.exists.get():
            self.exists.touch()
            return
        
        curr_mtime = self.mtime.get()
        real_mtime = os.stat(filename)[stat.ST_MTIME]   
        if real_mtime != curr_mtime:
            self.mtime.touch()
            
    def param_touched(self, param_name):
        if param_name == '_naming':
            self.filename.touch()
        elif param_name == 'filename':
            self.exists.touch()
            self.thumbnail.touch()
        elif param_name == 'exists':
            self.mtime.touch()
        else:
            super(FileNode, self).param_touched(param_name)
            
    def compute(self, param_name):
        if param_name == 'filename':
            config = self._naming.get()
            named = self.flow().get_named(config)
            self.filename.set(named.path())
            
        elif param_name == 'exists':
            filename = self.filename.get()
            if not filename:
                self.exists.set(False)
            else:
                self.exists.set(os.path.exists(filename))
        
        elif param_name == 'mtime':
            if not self.exists.get():
                self.mtime.set(0)
            else:
                filename = self.filename.get()
                self.mtime.set(
                    os.stat(filename)[stat.ST_MTIME]
                )

        elif param_name == 'thumbnail':
            dir, name = os.path.split(self.filename.get())
            thumbnail = os.path.join(dir, '.thumbnails', name+'.png')
            self.thumbnail.set(thumbnail)