class User(Node): login = ComputedParam() first_name = CaseParam() last_name = CaseParam() mail = CaseParam() active = CaseParam().ui(editor='bool') teams = One(casting.Cast) def compute(self, param_name): if param_name == 'login': self.login.set(self.node_id)
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)
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)
class MyNode(Node): p1 = Param() p2 = CaseParam() mult = ComputedParam() def param_touched(self, param_name): if param_name in ('p1', 'p2'): self.mult.touch() def compute(self, param_name): if param_name == 'mult': p1 = self.p1.get() if not isinstance(p1, int): raise Exception('Invalid value for param p1: must be int') p2 = self.p2.get() if not isinstance(p2, int): raise Exception('Invalid value for param p2: must be int') self.mult.set(p1 * p2)
class MyComposedNode(Node): p1 = CaseParam() my_child = Child(MyNode)
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)
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)
class CasedNode(Node): node_param = Param() node_case_param = CaseParam(default='Case Param Default') c1 = Child(ChildNode).configure('Param in c1') c2 = Child(ChildNode).configure('Param in c2')
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)