def check(self, W): """Verify invariants.""" if W == 0: return # Some checks already performed before: iteration assignments do not violate deps, prios match self.visit_goals(callback=lambda g: g.check(W)) # Check that iterations are continuous and start from 0 iters = set() def collect_iters(g): if g.iter is not None: iters.add(g.iter) self.visit_goals(callback=collect_iters) iters = sorted(list(iters)) if W and iters: warn_if(iters[0] != 1, "iterations do not start with 1") for itr, nxt in zip(iters, iters[1:]): if itr + 1 != nxt: warn(f"iterations are not consecutive: {itr} and {nxt}") break # Check for loops for root in self.roots: path = [] def enter(g, path=path): # pylint: disable=dangerous-default-value error_if(g.name in path, "found a cycle: %s" % '\n '.join(path)) path.append(g.name) def exit(g, path=path): # pylint: disable=dangerous-default-value path[:] = path[:-1] root.visit(before=lambda g: enter(g, path), after=lambda g: exit(g, path)) # pylint: disable=cell-var-from-loop,consider-using-sys-exit
def _schedule_block(self, block, start, alloc, par): logger.debug(f"_schedule_block: scheduling block in {block.loc}: " f"start={start}, alloc={alloc}, par={par}") alloc = block.alloc or alloc par = block.parallel or par latest = start if block.goal_name is None: for b in block.blocks: last = self._schedule_block(b, start, alloc, par) latest = max(latest or last, last) if block.seq: start = last else: assert not block.blocks, "block with goals should have no subblocks" goal = self.net.name_to_goal.get(block.goal_name) error_if(goal is None, block.loc, f"goal '{block.goal_name}' not found in plan") goal_finish = self._schedule_goal(goal, start, alloc, par) latest = max(latest, goal_finish) if block.deadline is not None and latest > block.deadline: warn( "Failed to schedule block at {block.loc} before deadline {block.deadline}" ) return latest
def check(self, W): """Verify invariants.""" if W == 0: return if self.alloc != ['all'] and not self.effort.defined(): warn(self.loc, "activity is assigned but no effort is specified")
def assign_inferred_attrs(g): new_attr = inferred_attrs.get(g.name) if new_attr is not None: old_attr = getattr(g, attr_name) if old_attr is None: setattr(g, attr_name, new_attr) elif less(old_attr, new_attr): warn(g.loc, f"inferred ({new_attr}) and assigned ({old_attr}) {attr_name} " f"for goal '{g.name}' do not match") setattr(g, attr_name, new_attr)
def check(self, W): """Verify invariants.""" if W and not self.defined and not self.dummy: warn(self.loc, f"goal '{self.name}' is undefined") pending_conds = [c.name for c in self.checks if not c.done()] if W and self.completion_date is not None \ and self.completion_date <= datetime.date.today() \ and pending_conds: warn(self.loc, "goal '%s' marked as completed but some checks are still pending:\n %s" % (self.name, '\n '.join(pending_conds))) if W and self.is_completed() and not self.completion_date: warn(self.loc, f"goal '{self.name}' marked as completed but is missing tracking data") for act in self.global_preds: if not act.is_instant(): error(act.loc, "global dependencies must be instant") if W and not act.head: warn(act.loc, f"goal '{self.name}' has empty global dependency") for act in self.preds: act.check(W) if act.head and self.iter is not None and act.head.iter is None: warn(self.loc, f"goal has been scheduled but one of it's dependents is not: " f"'{act.head.name}'") if self.is_completed() and (not act.duration or not act.effort.real): warn(self.loc, f"goal '{self.name}' is achieved but " f"one of it's actions is missing tracking data")
def _schedule_goal(self, goal, start, alloc, par, warn_if_past=True): logger.debug(f"_schedule_goal: scheduling goal '{goal.name}': " f"start={start}, alloc={alloc}, par={par}") if self.sched.is_completed(goal): return self.sched.get_completion_date(goal) if goal.completion_date is not None: logger.debug("_schedule_goal: goal already scheduled") if warn_if_past and goal.completion_date < start: warn( goal.loc, f"goal '{goal.name}' is completed on {goal.completion_date}, before {start}" ) # TODO: warn if completion_date < start self.sched.set_completion_date(goal, goal.completion_date) return goal.completion_date if goal.is_completed(): warn( goal.loc, f"unable to schedule completed goal '{goal.name}' with no completion date" ) self.sched.set_completion_date(goal, datetime.date.today()) return datetime.date.today() completion_date = start for act in goal.preds: logger.debug( f"_schedule_goal: scheduling activity '{act.name}' for goal '{goal.name}'" ) if act.duration is not None: # TODO: register spent time for devs if warn_if_past and act.duration.start < start: warn( act.loc, f"activity '{act.name}' started on {act.duration.start}, before {start}" ) completion_date = max(completion_date, act.duration.finish) continue act_start = start if act.head is not None: if self.sched.is_completed(act.head): act_start = max(act_start, self.sched.get_completion_date(act.head)) else: # For goals that are not specified by schedule we use default settings logger.debug( f"_schedule_goal: scheduling predecessor '{act.head.name}'" ) self._schedule_goal(act.head, datetime.date.today(), [], None, warn_if_past=False) if not act.overlaps: act_start = max( act_start, self.sched.get_completion_date(act.head)) else: for pred in act.head.preds: overlap = act.overlaps.get(pred.id) if overlap is not None: pred_iv = self.sched.get_duration(pred) span = (pred_iv.finish - pred_iv.start) * (1 - overlap) act_start = max(act_start, pred_iv.start + span) if act.is_instant(): completion_date = max(completion_date, act_start) continue plan_rcs = self.prj.get_resources(act.alloc) if alloc: rcs = self.prj.get_resources(alloc) if any(rc for rc in rcs if rc not in plan_rcs): allocs = '/'.join(alloc) assignees = '/'.join(rc.name for rc in plan_rcs) error( f"allocations defined in schedule ({allocs}) do not match " f"allocations defined in action ({assignees})") else: rcs = plan_rcs act_par = par if act_par is None: act_par = act.parallel act_effort, _ = self.est.estimate(act) act_effort *= 1 - act.effort.completion assignees = '/'.join(rc.name for rc in rcs) logger.debug( f"_schedule_goal: scheduling activity '{act.name}': " f"start={act_start}, effort={act_effort}, par={act_par}, rcs={assignees}" ) iv, assigned_rcs = self.sched.assign_best_rcs( rcs, act_start, act_effort, act_par) assignees = '/'.join(rc.name for rc in assigned_rcs) logger.debug( f"_schedule_goal: assignment for activity '{act.name}': " f"@{assignees}, duration {iv}") self.sched.set_duration(act, iv, assigned_rcs) completion_date = max(completion_date, iv.finish) logger.debug( f"_schedule_goal: scheduled goal '{goal.name}' for completion_date" ) self.sched.set_completion_date(goal, completion_date) if goal.deadline is not None and completion_date > goal.deadline: warn( f"failed to schedule goal '{goal.name}' before deadline goal.deadline" ) return completion_date