def copy_needed(self, traits: 'ResolvedTraitSet', res_guide: 'CdmAttributeResolutionGuidanceDefinition', actions: List['AttributeResolutionApplier']) -> bool: if not actions: return False # For every attribute in the set, detect if a merge of traits will alter the traits. If so, need to copy the # attribute set to avoid overwrite. for res_att in self._set: for trait_action in actions: ctx = ApplierContext() ctx.res_opt = traits.res_opt ctx.res_att_source = res_att ctx.res_guide = res_guide if trait_action._will_attribute_modify(ctx): return True return False
def remove_requested_atts( self, marker: Tuple[int, int]) -> 'ResolvedAttributeSet': # The marker tracks the track the deletes 'under' a certain index. (count_index, mark_index) = marker # For every attribute in the set, run any attribute removers on the traits they have. applied_att_set = None # type: ResolvedAttributeSet for i_att, res_att in enumerate(self._set): # Possible for another set to be in this set. if isinstance(res_att.target, ResolvedAttributeSet): sub_set = cast('ResolvedAttributeSet', res_att.target) # Go around again on this same function and get rid of things from this group. marker = (count_index, mark_index) new_sub_set = sub_set.remove_requested_atts(marker) (count_index, mark_index) = marker # Replace the set with the new one that came back. res_att.target = new_sub_set # If everything went away, then remove this group. if not new_sub_set or not new_sub_set._set: res_att = None else: # Don't count this as an attribute (later). count_index -= 1 else: # This is a good time to make the resolved names final. res_att.previous_resolved_name = res_att.resolved_name if res_att.arc and res_att.arc.applier_caps and res_att.arc.applier_caps.can_remove: for apl in res_att.arc.actions_remove: # This should look like the applier context when the att was created. ctx = ApplierContext() ctx.res_opt = res_att.arc.res_opt ctx.res_att_source = res_att ctx.res_guide = res_att.arc.res_guide if apl._will_remove(ctx): res_att = None break if res_att: # Attribute remains. Are we building a new set? if applied_att_set: applied_att_set.merge(res_att) count_index += 1 else: # Remove the attribute. If this is the first removed attribute, then make a copy of the set now. After # this point, the rest of the loop logic keeps the copy going as needed. if not applied_att_set: applied_att_set = ResolvedAttributeSet() for i_copy in range(i_att): applied_att_set.merge(self._set[i_copy]) # Track deletes under the mark (move the mark up) if count_index < mark_index: mark_index -= 1 marker = (count_index, mark_index) # Now we are that (or a copy). ras_result = self if applied_att_set and applied_att_set.size != ras_result.size: ras_result = applied_att_set ras_result.base_trait_to_attributes = None ras_result.attribute_context = self.attribute_context return ras_result
def apply( self, traits: 'ResolvedTraitSet', res_opt: 'ResolveOptions', res_guide: 'CdmAttributeResolutionGuidanceDefinition', actions: List['AttributeResolutionApplier'] ) -> 'ResolvedAttributeSet': from cdm.objectmodel import CdmAttributeContext if not traits and not actions: # nothing can change. return self # for every attribute in the set run any attribute appliers. applied_att_set = ResolvedAttributeSet() applied_att_set.attribute_context = self.attribute_context # check to see if we need to make a copy of the attributes # do this when building an attribute context and when we will modify the attributes (beyond traits) # see if any of the appliers want to modify making_copy = False if self._set and applied_att_set.attribute_context and actions: res_att_test = self._set[0] for trait_action in actions: ctx = ApplierContext(res_opt=res_opt, res_att_source=res_att_test, res_guide=res_guide) if trait_action._will_attribute_modify(ctx): making_copy = True break if making_copy: # fake up a generation round for these copies that are about to happen acp = AttributeContextParameters( under=applied_att_set.attribute_context, type=CdmAttributeContextType.GENERATED_SET, name='_generatedAttributeSet') applied_att_set.attribute_context = CdmAttributeContext._create_child_under( traits.res_opt, acp) acp = AttributeContextParameters( under=applied_att_set.attribute_context, type=CdmAttributeContextType.GENERATED_ROUND, name='_generatedAttributeRound0') applied_att_set.attribute_context = CdmAttributeContext._create_child_under( traits.res_opt, acp) for res_att in self._set: att_ctx_to_merge = res_att.att_ctx # start with the current context for the resolved att, if a copy happens this will change if isinstance(res_att.target, ResolvedAttributeSet): sub_set = cast('ResolvedAttributeSet', res_att.target) if making_copy: res_att = res_att.copy() # making a copy of a subset (att group) also bring along the context tree for that whole group att_ctx_to_merge = res_att.att_ctx # the set contains another set. Process those. res_att.target = sub_set.apply(traits, res_opt, res_guide, actions) else: rts_merge = res_att.resolved_traits.merge_set(traits) res_att.resolved_traits = rts_merge if actions: for trait_action in actions: ctx = ApplierContext() ctx.res_opt = traits.res_opt ctx.res_att_source = res_att ctx.res_guide = res_guide if trait_action._will_attribute_modify(ctx): # make a context for this new copy if making_copy: acp = AttributeContextParameters( under=applied_att_set.attribute_context, type=CdmAttributeContextType. ATTRIBUTE_DEFINITION, name=res_att.resolved_name, regarding=res_att.target) ctx.att_ctx = CdmAttributeContext._create_child_under( traits.res_opt, acp) att_ctx_to_merge = ctx.att_ctx # type: CdmAttributeContext # make a copy of the resolved att if making_copy: res_att = res_att.copy() att_ctx_to_merge._add_lineage(res_att.att_ctx) res_att.att_ctx = att_ctx_to_merge ctx.res_att_source = res_att # modify it trait_action._do_attribute_modify(ctx) applied_att_set.merge(res_att) applied_att_set.attribute_context = self.attribute_context return applied_att_set