def __init__(self, entity: Optional['CdmEntityDefinition'] = None, rasb: Optional['ResolvedAttributeSetBuilder'] = None) -> None: self.entity = entity # type: Optional[CdmEntityDefinition] # --- internal --- self._rasb = rasb if rasb else ResolvedAttributeSetBuilder( ) # type: ResolvedAttributeSetBuilder
def _fetch_resolved_attributes( self, res_opt: 'ResolveOptions', acp_in_context: Optional['AttributeContextParameters'] = None ) -> 'ResolvedAttributeSet': from cdm.resolvedmodel import ResolvedAttributeSet from cdm.utilities import SymbolSet from .cdm_attribute_context import CdmAttributeContext from .cdm_corpus_def import CdmCorpusDefinition from .cdm_entity_attribute_def import CdmEntityAttributeDefinition from .cdm_entity_def import CdmEntityDefinition from cdm.resolvedmodel.resolved_attribute_set_builder import ResolvedAttributeSetBuilder was_previously_resolving = self.ctx.corpus._is_currently_resolving self.ctx.corpus._is_currently_resolving = True if not res_opt: res_opt = ResolveOptions( self, self.ctx.corpus.default_resolution_directives) in_circular_reference = False was_in_circular_reference = res_opt._in_circular_reference if isinstance(self, CdmEntityDefinition): in_circular_reference = self in res_opt._currently_resolving_entities res_opt._currently_resolving_entities.add(self) res_opt._in_circular_reference = in_circular_reference # uncomment this line as a test to turn off allowing cycles #if in_circular_reference: # return ResolvedAttributeSet() kind = 'rasb' ctx = self.ctx rasb_result = None rasb_cache = self._fetch_object_from_cache( res_opt, acp_in_context) # type: ResolvedAttributeSetBuilder under_ctx = None current_depth = res_opt._depth_info.current_depth # store the previous symbol set, we will need to add it with # children found from the constructResolvedTraits call curr_sym_ref_set = res_opt._symbol_ref_set or SymbolSet() res_opt._symbol_ref_set = SymbolSet() # if using the cache passes the maxDepth, we cannot use it if rasb_cache \ and res_opt._depth_info.max_depth \ and res_opt._depth_info.current_depth + rasb_cache._resolved_attribute_set._depth_traveled > res_opt._depth_info.max_depth: rasb_cache = None if not rasb_cache: # a new context node is needed for these attributes, # this tree will go into the cache, so we hang it off a placeholder parent # when it is used from the cache (or now), then this placeholder parent is ignored and the things under it are # put into the 'receiving' tree under_ctx = CdmAttributeContext._get_under_context_for_cache_context( res_opt, self.ctx, acp_in_context) rasb_cache = self._construct_resolved_attributes( res_opt, under_ctx) # type: ResolvedAttributeSetBuilder if rasb_cache: # register set of possible docs o_def = self.fetch_object_definition(res_opt) if o_def is not None: ctx.corpus._register_definition_reference_symbols( o_def, kind, res_opt._symbol_ref_set) # get the new cache tag now that we have the list of docs cache_tag = ctx.corpus._create_definition_cache_tag( res_opt, self, kind, 'ctx' if acp_in_context else None) # save this as the cached version if cache_tag: ctx._cache[cache_tag] = rasb_cache # get the 'under_ctx' of the attribute set from the acp that is wired into the target tree under_ctx = cast(ResolvedAttributeSetBuilder, rasb_cache)\ ._resolved_attribute_set.attribute_context\ ._get_under_context_from_cache_context(res_opt, acp_in_context) \ if cast(ResolvedAttributeSetBuilder, rasb_cache)._resolved_attribute_set.attribute_context else None else: # get the 'under_ctx' of the attribute set from the cache. The one stored there was build with a different # acp and is wired into the fake placeholder. so now build a new under_ctx wired into the output tree but with # copies of all cached children under_ctx = cast(ResolvedAttributeSetBuilder, rasb_cache) \ ._resolved_attribute_set.attribute_context \ ._get_under_context_from_cache_context(res_opt, acp_in_context) \ if cast(ResolvedAttributeSetBuilder, rasb_cache)._resolved_attribute_set.attribute_context else None # under_ctx._validate_lineage(res_opt) # debugging if rasb_cache: # either just built something or got from cache # either way, same deal: copy resolved attributes and copy the context tree associated with it # 1. deep copy the resolved att set (may have groups) and leave the attCtx pointers set to the old tree # 2. deep copy the tree. # # 1. deep copy the resolved att set (may have groups) and leave the attCtx pointers set to the old tree rasb_result = ResolvedAttributeSetBuilder() rasb_result._resolved_attribute_set = cast( ResolvedAttributeSetBuilder, rasb_cache)._resolved_attribute_set.copy() # 2. deep copy the tree and map the context references. if under_ctx: # null context? means there is no tree, probably 0 attributes came out if under_ctx.associate_tree_copy_with_attributes( res_opt, rasb_result._resolved_attribute_set) is False: return None if isinstance(self, CdmEntityAttributeDefinition): # if we hit the maxDepth, we are now going back up res_opt._depth_info.current_depth = current_depth # now at the top of the chain where max depth does not influence the cache if res_opt._depth_info.current_depth == 0: res_opt._depth_info.max_depth_exceeded = False if not in_circular_reference and self.object_type == CdmObjectType.ENTITY_DEF: # should be removed from the root level only # if it is in a circular reference keep it there res_opt._currently_resolving_entities.remove(self) res_opt._in_circular_reference = was_in_circular_reference # merge child reference symbols set with current curr_sym_ref_set._merge(res_opt._symbol_ref_set) res_opt._symbol_ref_set = curr_sym_ref_set self.ctx.corpus._is_currently_resolving = was_previously_resolving return rasb_result._resolved_attribute_set if rasb_result else rasb_result