def _filter_parameters( self, parameters: Iterable[AgentParameterDto] ) -> List[AgentParameterDto]: """ Remove parameters that should not be available to the user. """ # We don't allow the user to change these options which are only # intended to be used interactively on command line. remove_parameters = frozenset(("help", "version")) filtered_1 = [] for param in parameters: if param.name in remove_parameters: continue if param.name == "action": # However we still need the user to be able to set 'action' due # to backward compatibility reasons. So we just mark it as not # required. We also move it to advanced params to indicate users # should not set it in most cases. filtered_1.append( dc_replace( param, required=False, advanced=True, pcs_deprecated_warning=( "Specifying 'action' is deprecated and not " "necessary with current Pacemaker versions. " "Use {0} instead." ).format(format_list(STONITH_ACTION_REPLACED_BY)), ) ) else: filtered_1.append(param) # 'port' parameter is required by a fence agent, but it is filled # automatically by pacemaker based on 'pcmk_host_map' or # 'pcmk_host_list' parameter (defined in fenced metadata). Pacemaker # marks 'port' parameter as not required for us. # It, however, doesn't mark any parameters deprecating 'port' as not # required se we must do so ourselves. port_related_params = set(["port"]) new_deprecated = set(["port"]) while new_deprecated: current_deprecated = new_deprecated new_deprecated = set() for param in filtered_1: if param.obsoletes in current_deprecated: if param.name not in port_related_params: new_deprecated.add(param.name) port_related_params.add(param.name) filtered_2 = [] for param in filtered_1: if param.name in port_related_params: filtered_2.append(dc_replace(param, required=False)) else: filtered_2.append(param) return filtered_2
async def build_inferrer(self, a, fn, argvals): if isinstance(fn, TypedPrimitive): return _const(fn.prim, a) inf = self.specializer.engine.get_inferrer_for(fn) argvals = argvals and inf.normalize_args(argvals) argvals, outval = await self._find_unique_argvals(a, inf, argvals) if isinstance(inf, TrackedInferrer): fn = dc_replace(fn, tracking_id=None) inf = self.specializer.engine.get_inferrer_for(fn) if isinstance(fn, PrimitiveFunction): a = AbstractFunction(TypedPrimitive(fn.prim, argvals, outval)) return _const(fn.prim, a) assert isinstance(inf, BaseGraphInferrer) assert _visible(self.graph, fn.context.graph) if hasattr(inf, 'graph_cache'): await concretize_cache(inf.graph_cache) ctx = inf.make_context(self.specializer.engine, argvals) v = await self.specializer._specialize(ctx.graph, ctx, None) assert isinstance(v, Graph) newa = AbstractFunction(GraphFunction(v, ctx)) rval = _const(v, newa) newa.tracking_id = rval return rval
def _prepare(self): assert self.pattern pattern = to_pattern(self.pattern) self._rules = defaultdict(lambda: defaultdict(list)) self._key_captures = pattern.key_captures() for method in dir(self): fn = getattr(self, method) role = getattr(fn, "_ptera_role", None) if role is None: continue if role.target.capture is None: role.target = dc_replace(role.target, capture=self.default_target) _, names = get_names(fn) names = {*names, *[k for k, param in self._key_captures]} patt = pattern.rewrite(names, focus=role.target.capture) patt = patt.specialize({role.target.capture: role.target}) if role.role == "valuer": self._rules[patt]["value"].append(self._value_wrap(fn)) elif role.role == "initializer": self._rules[patt]["value"].append(self._init_wrap(fn)) elif role.role == "updater": self._rules[patt]["listeners"].append(self._update_wrap(fn)) else: raise AssertionError(f"Unknown role: {role.role}")
def get_actions(self) -> List[AgentActionDto]: """ Get list of agent's actions (operations) """ action_list = [] for action in self._get_raw_actions(): if action.depth is not None: if action.depth == "0": action_list.append(dc_replace(action, depth=None)) else: action_list.append( dc_replace(action, OCF_CHECK_LEVEL=action.depth) ) else: action_list.append(action) return action_list
def solve_rates( self, outflow: Frac, **solver_kwargs ) -> t.Tuple[t.List[BeltAssignment], int, t.List[Item.Flow]]: """ Solves the number of units to fill a full belt """ # NOTE we divide by 2 since the line solution is for half the flow # see: symmetric layout assumed (TODO) by belt_solver out_rate = outflow / 2 # base output per sec per unit rps = Frac(self.speed) * self.base_rps # NOTE this is the needed manufactories per side need_mfs = Frac(out_rate / rps) / self.prod assert self.recipe is not None need_flows = [ dc_replace(base_flow, num=base_flow.num * need_mfs * rps) for base_flow in self.recipe.inputs ] belt_assignment = solve_belts(need_flows) return belt_assignment, need_mfs, need_flows
def analyze_function(self, a, fn, argvals): """Analyze a function for the collect phase. Arguments: a: The abstract value for the function. fn: The Function object, equivalent a.get_unique(). argvals: The abstract arguments given to the function. Returns: ct: A Constant to use for this call. ctx: The context for this call, or None norm_ctx: The normalized context for this call, or None """ inf = self.engine.get_inferrer_for(fn) argvals = argvals and inf.normalize_args_sync(argvals) argvals, outval = self._find_unique_argvals(a, inf, argvals) if isinstance(inf, TrackedInferrer): fn = dc_replace(fn, tracking_id=None) inf = self.engine.get_inferrer_for(fn) if isinstance(fn, PrimitiveFunction): a = AbstractFunction(TypedPrimitive(fn.prim, argvals, outval)) return _const(fn.prim, a), None assert isinstance(inf, GraphInferrer) concretize_cache(inf.graph_cache) ctx = inf.make_context(self.engine, argvals) norm_ctx = _normalize_context(ctx) if norm_ctx not in self.specializations: self.specializations[norm_ctx] = ctx new_ct = _const(_Placeholder(norm_ctx), None) return new_ct, norm_ctx
def _get_parameters(self) -> List[AgentParameterDto]: """ Get list of agent's parameters """ params_element = self._get_metadata().find("parameters") if params_element is None: return [] preprocessed_param_list = [] deprecated_by_dict: Dict[str, Set[str]] = {} for param_el in params_element.iter("parameter"): param = self._get_parameter(param_el) if param is None: continue preprocessed_param_list.append(param) if param.obsoletes: obsoletes = param.obsoletes if not obsoletes in deprecated_by_dict: deprecated_by_dict[obsoletes] = set() deprecated_by_dict[obsoletes].add(param.name) param_list = [] for param in preprocessed_param_list: if param.name in deprecated_by_dict: param_list.append( dc_replace( param, deprecated_by=sorted(deprecated_by_dict[param.name]), ) ) else: param_list.append(param) return param_list
def _get_metadata(self) -> ResourceAgentMetadata: pcs_metadata = ocf_unified_to_pcs(self._raw_metadata) if self._additional_parameters: pcs_metadata = dc_replace( pcs_metadata, parameters=(pcs_metadata.parameters + list(self._additional_parameters)), ) return pcs_metadata
def with_modules(self, modules: t.List[Item.Module]) -> BaseManuf: if len(modules) > self.module_slots: raise ValueError( f"Too many modules for a {self.name} manufactory!") if (self.recipe and any(m.prod != Frac(0) for m in modules) and not self.recipe.proddable): raise ValueError( "Assigning productivity modules to non-proddable recipe!") return dc_replace(self, modules=modules)
def get_inferrer_for(__call__, self, fn): """Return the Inferrer for the given function.""" tracking = getattr(fn, "tracking_id", None) if tracking is None: return __call__(self, fn) if fn not in self.constructors: fn_generic = dc_replace(fn, tracking_id=None) inf = __call__(self, fn_generic) self.constructors[fn] = TrackedInferrer(inf) return self.constructors[fn]
def with_recipe(self, recipe: Recipe) -> BaseManuf: print(recipe) if (self.modules and any(m.prod != Frac(0) for m in self.modules) and not recipe.proddable): raise ValueError( "Assigning non-proddable recipe to manuf. with prodmods!") if recipe.category not in self.recipe_cap: raise ValueError(f"Recipe ({recipe.category})incompatible with " f"this manufactory ({self.recipe_cap}") return dc_replace(self, recipe=recipe)
def get_inferrer_for(ovldcall, fn): """Return the Inferrer for the given function.""" __call__ = ovldcall.resolve(fn) tracking = getattr(fn, "tracking_id", None) if tracking is None: return __call__(fn) if fn not in ovldcall.obj.constructors: fn_generic = dc_replace(fn, tracking_id=None) inf = __call__(fn_generic) ovldcall.obj.constructors[fn] = TrackedInferrer(inf) return ovldcall.obj.constructors[fn]
def _get_parameter( self, parameter_element: _Element ) -> Optional[AgentParameterDto]: parameter = super()._get_parameter(parameter_element) if parameter is None: return None # Metadata are written in such a way that a longdesc text is a # continuation of a shortdesc text. return dc_replace( parameter, longdesc=f"{parameter.shortdesc}\n{parameter.longdesc}".strip(), advanced=parameter.shortdesc.startswith("Advanced use only"), )
def _complete_all_intervals( raw_operation_list: Iterable[AgentActionDto], ) -> List[AgentActionDto]: """ Return a new list of operations with "interval" defined for all of them operation_list -- can include items with "interval" == None """ operation_list = [] for operation in raw_operation_list: if operation.interval is None: operation_list.append( dc_replace( operation, interval=_get_default_interval(operation.name) ) ) else: operation_list.append(operation) return operation_list
def clone(self, **changes): return dc_replace(self, **changes)
def no_tracking_id(self, x: GraphFunction): """Resolve all Pending and erase tracking_id information.""" return dc_replace(x, tracking_id=None)
def _no_tracking_id(self, x: GraphFunction): return dc_replace(x, tracking_id=None)
def normalize( assignments: ty.List[BeltAssignment]) -> ty.List[BeltAssignment]: """ Normalize a belt assignment solution set. Minimizes hetereogeneous belts. """ by_belt_type = defaultdict(list) # type: ignore for asst in assignments: by_belt_type[asst.belt].append(asst) out = [] # within each belt type... for bt_assts in by_belt_type.values(): assts_copy = set(bt_assts) while True: continue_outer = False by_item = defaultdict(set) # type: ignore # ... we map each item to the hetero assts that contain it ... for asst in assts_copy: if asst.item_right == asst.item_left: continue by_item[asst.item_left].add(asst) by_item[asst.item_right].add(asst) # ... rechecking by_item every time we add a new asst ... for asst_set in by_item.values(): # ... if ever an item has two hetero assets # then they can be swapped to homogenize a belt... if len(asst_set) == 2: x = asst_set.pop() y = asst_set.pop() # so we check which assets to swap between the # belts. Immutability is a guiderail here. if (x.item_right == y.item_right) or (x.item_left == y.item_left): new_x = dc_replace(x, item_right=y.item_left) new_y = dc_replace(y, item_left=x.item_right) else: new_x = dc_replace(x, item_right=y.item_right) new_y = dc_replace(y, item_right=x.item_right) # we invalidate the originals assts_copy.discard(x) assts_copy.discard(y) # and add the reforged assignments assts_copy.add(new_x) assts_copy.add(new_y) # we continue our search if we did anything continue_outer = True break # for asst_set in by_item.values() # we continue continuing our search if we did anything if continue_outer: break # for asst in assts_copy # otherwise we are done! if not continue_outer: break # while True out.extend(list(assts_copy)) return sorted(out)